Microservices Communication: Sync vs Async Patterns That Actually Scale
Microservices Communication Patterns#
The hardest part of microservices is not splitting the monolith — it is getting the pieces to talk to each other reliably. Choose the wrong communication pattern and you get a distributed monolith that is slower and more fragile than what you started with.
Synchronous vs Asynchronous#
Two fundamental approaches, each with clear trade-offs.
Synchronous Communication#
The caller sends a request and waits for a response.
Order Service --HTTP POST--> Payment Service
<--200 OK-----
When to use: queries that need an immediate answer, user-facing flows where latency matters, simple CRUD operations.
Protocols:
| Protocol | Format | Speed | Ecosystem |
|---|---|---|---|
| REST/HTTP | JSON | Good | Universal |
| gRPC | Protobuf | Fast | Growing |
| GraphQL | JSON | Good | Frontend-focused |
REST (HTTP/JSON)#
The default choice for most teams.
GET /api/orders/123
Accept: application/json
// Response
{
"id": 123,
"status": "shipped",
"total": 49.99
}
Pros: simple, well-understood, great tooling. Cons: text-based (larger payloads), no streaming, no built-in contracts.
gRPC (HTTP/2 + Protobuf)#
Binary protocol with strong contracts.
service OrderService {
rpc GetOrder (OrderRequest) returns (OrderResponse);
rpc StreamUpdates (OrderRequest) returns (stream OrderUpdate);
}
Pros: fast serialization, bi-directional streaming, auto-generated clients. Cons: not browser-native, harder to debug, steeper learning curve.
Asynchronous Communication#
The caller sends a message and does not wait for a response.
Order Service --publish--> Message Broker --deliver--> Inventory Service
(fire and forget)
When to use: long-running operations, event notifications, decoupling services, handling spikes.
Patterns:
| Pattern | Description | Example |
|---|---|---|
| Fire-and-forget | Send message, move on | Order placed notification |
| Request-reply (async) | Send message, get response later via callback queue | Payment processing |
| Publish-subscribe | Broadcast event to many subscribers | Order events to analytics, inventory, email |
Message Brokers#
The backbone of async communication.
Producer --> [Message Broker] --> Consumer(s)
Broker options:
- RabbitMQ : Traditional message queue, routing, priorities
- Apache Kafka: Event log, high throughput, replay capability
- AWS SQS : Managed queue, simple, scales automatically
- NATS : Lightweight, low-latency, cloud-native
Choosing Between Them#
Need event replay/audit log? --> Kafka
Need simple task queue? --> RabbitMQ or SQS
Need real-time low-latency pub/sub? --> NATS
Want zero ops? --> SQS / SNS / EventBridge
API Composition Pattern#
When a client needs data from multiple services, use an API composer (often the API Gateway).
Client --> API Gateway --> Order Service (order details)
--> User Service (customer info)
--> Shipping Service (tracking)
<-- merged response --
Rules:
- Keep composition in the gateway or a dedicated BFF (Backend for Frontend)
- Call downstream services in parallel where possible
- Set aggressive timeouts — one slow service should not block everything
Saga Pattern for Distributed Transactions#
You cannot use ACID transactions across services. Sagas coordinate multi-step business processes through a sequence of local transactions.
Choreography (Event-Driven)#
Each service publishes events and reacts to others.
Order Created --> Payment Service charges card
Payment Succeeded --> Inventory Service reserves stock
Stock Reserved --> Shipping Service schedules delivery
// Compensation on failure:
Payment Failed --> Order Service cancels order
Stock Unavailable --> Payment Service refunds card
Pros: simple, no central coordinator, loosely coupled. Cons: hard to track, implicit flow, can become tangled.
Orchestration (Command-Driven)#
A central orchestrator directs each step.
Saga Orchestrator:
1. Command: ChargePayment --> Payment Service
2. Command: ReserveStock --> Inventory Service
3. Command: ScheduleShip --> Shipping Service
On failure at step 2:
Compensate: RefundPayment --> Payment Service
Pros: explicit flow, easy to track, centralized error handling. Cons: orchestrator is a single point of coordination, tighter coupling.
Service Mesh#
A dedicated infrastructure layer for service-to-service communication.
Service A --> [Sidecar Proxy] --network--> [Sidecar Proxy] --> Service B
The sidecar handles:
- mTLS encryption
- Load balancing
- Retries and timeouts
- Circuit breaking
- Observability (metrics, traces)
Popular options: Istio, Linkerd, Consul Connect.
When you need it: 50+ services, strict security requirements (mTLS everywhere), teams struggling with cross-cutting concerns.
When you do not need it: fewer than 10 services, simple communication patterns, team capacity is limited.
Resilience Patterns#
Networks fail. Services crash. These patterns keep failures from cascading.
Retry with Backoff#
Attempt 1: call service --> timeout
Attempt 2: wait 1s, retry --> timeout
Attempt 3: wait 2s, retry --> success
// Exponential backoff with jitter:
delay = min(base * 2^attempt + random_jitter, max_delay)
Rules: set a max retry count, use exponential backoff, add jitter to avoid thundering herd.
Timeout#
// Without timeout: caller waits forever
// With timeout:
call_with_timeout(payment_service, timeout=3s)
--> if no response in 3s, fail fast
Set timeouts at every network boundary. A missing timeout is a guaranteed outage waiting to happen.
Circuit Breaker#
Three states that protect your system from repeated failures.
CLOSED (normal)
--> failures exceed threshold
OPEN (all calls fail fast for cooldown period)
--> cooldown expires
HALF-OPEN (allow limited test calls)
--> test calls succeed: back to CLOSED
--> test calls fail: back to OPEN
Configuration example:
- Failure threshold: 5 failures in 60 seconds
- Cooldown: 30 seconds
- Half-open test calls: 3
Communication Decision Matrix#
Scenario | Pattern
----------------------------------|------------------------
User clicks "Place Order" | Sync (REST/gRPC)
Send order confirmation email | Async (fire-and-forget)
Coordinate payment + inventory | Saga (orchestration)
Dashboard aggregates 5 services | API Composition
Real-time price updates | Async (pub-sub / SSE)
Service-to-service auth + tracing | Service Mesh
Key Takeaways#
- Default to async for anything that does not need an immediate response
- Use gRPC for internal service-to-service calls where performance matters
- Use REST for public APIs and simple integrations
- Sagas replace transactions — choose choreography for simple flows, orchestration for complex ones
- Always implement retry + timeout + circuit breaker at every network boundary
- Service mesh is powerful but only justified at scale
Communication patterns are the nervous system of your microservices architecture. Get them right and your system scales gracefully. Get them wrong and every service becomes a liability.
This is article #260 in the Codelit engineering series. We publish in-depth technical guides on architecture, infrastructure, and modern engineering practices. Explore more at codelit.dev.
Try it on Codelit
Chaos Mode
Simulate node failures and watch cascading impact across your architecture
Related articles
AI Agent Tool Use Architecture: Function Calling, ReAct Loops & Structured Outputs
6 min read
AI searchAI-Powered Search Architecture: Semantic Search, Hybrid Search, and RAG
8 min read
AI safetyAI Safety Guardrails Architecture: Input Validation, Output Filtering, and Human-in-the-Loop
8 min read
Try these templates
OpenAI API Request Pipeline
7-stage pipeline from API call to token generation, handling millions of requests per minute.
8 componentsScalable SaaS Application
Modern SaaS with microservices, event-driven processing, and multi-tenant architecture.
10 componentsNetflix Video Streaming Architecture
Global video streaming platform with adaptive bitrate, CDN distribution, and recommendation engine.
10 componentsBuild this architecture
Generate an interactive architecture for Microservices Communication in seconds.
Try it in Codelit →
Comments