Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 17

Synchronous vs. Asynchronous Communication

Recommended resources

Welcome back! In our last lesson, we meticulously defined the public API contract for our 'Order Service' using gRPC and Protocol Buffers. That orders.proto file gave us a set of synchronous RPC methods like CreateOrder and GetOrder.

Today, we address a crucial system design question that arises from this: when the OrderService receives a CreateOrder call, it can't act in a vacuum. It needs to check inventory, process a payment, and maybe notify a shipping department. How should it coordinate with the 'Inventory' and 'Payment' services? This lesson explores the two fundamental patterns for this inter-service communication: synchronous and asynchronous. Understanding the trade-offs between these two is one of the most critical decisions you'll make as a distributed systems architect.

Synchronous Communication: The Phone Call

Synchronous communication is like making a phone call. You dial a number (make a request), and you wait for the other person to answer (the response). The line is tied up, and you are blocked from doing other things until the conversation is over.

In microservices, this translates to a service making a direct network call (like a REST API call or a gRPC RPC) to another service and waiting for the response before it can proceed. The gRPC contract we defined in the previous lesson is a perfect example of this pattern.

Let's visualize this with our e-commerce system.

Sync. Vs Async. Communication - Request Response Vs Event-Driven Architecture in Microservices

The video from Innoskrit provides a clear, step-by-step walkthrough of how a synchronous request chain works in an e-commerce microservice architecture.

Watch the section that details the synchronous communication flow. As you watch, map the "Service D" in the video to our OrderService. Notice how it must call the UserService, then the OrderService (in their example, for order history), and finally the ProductService in a sequence, waiting for each response before starting the next call.

As the video demonstrates, to fulfill one client request, the OrderService might have to orchestrate a chain of synchronous calls:

  1. Client sends CreateOrder request to OrderService.
  2. OrderService calls InventoryService.CheckStock. It waits.
  3. InventoryService responds with OK.
  4. OrderService calls PaymentService.ProcessPayment. It waits.
  5. PaymentService responds with OK.
  6. OrderService finalizes the order and responds to the client.

REST and gRPC Comparison

This diagram from OneUptime shows a conceptual example of our OrderService making a synchronous REST call to an InventoryService to check stock before creating an order.

Trade-offs of Synchronous Communication

While conceptually simple, this direct, blocking pattern introduces significant challenges in a distributed system.

Sync. Vs Async. Communication - Request Response Vs Event-Driven Architecture in Microservices

Let's continue with the same video to explore the consequences of this tight coupling.

Now watch the detailed breakdown of the disadvantages of synchronous communication. Pay close attention to the concepts of cascading failures and performance bottlenecks.

The key trade-offs are:

  • Pros:

    • Simplicity: The logic is straightforward to write and debug. The flow of control is explicit and easy to follow.
    • Immediate Consistency: The client receives an immediate and definitive success or failure response. The state of the system is known at the end of the call.
  • Cons:

    • Tight (Temporal) Coupling: The OrderService is tightly coupled in time to the InventoryService and PaymentService. All services must be available simultaneously for the operation to succeed.
    • Cascading Failures: If the PaymentService is down or slow, the OrderService is blocked. This failure can cascade up the chain, ultimately causing the client's request to fail or time out. The entire system's availability becomes the product of the availability of all services in the chain.
    • Poor Performance: The total response time is the sum of all individual request-response latencies. The user has to wait for the entire chain to complete.

Asynchronous Communication: The Text Message

Asynchronous communication is like sending a text message or an email. You send the message ("fire and forget") and are free to do other things immediately. The recipient will process it when they are available, and they might send a message back later. There is no blocking.

In microservices, this is typically achieved using a message broker (like RabbitMQ, Apache Kafka, or Redis). Instead of making a direct call, a service publishes an event (a message about something that happened) to the broker. Other services can subscribe to these events and react accordingly.

Let's re-imagine our CreateOrder flow using this event-driven approach.

  1. Client sends CreateOrder request to OrderService.
  2. OrderService validates the request, saves the order to its own database with a PENDING status, and immediately returns a success response to the client ("Your order is being processed").
  3. The OrderService then publishes an OrderCreated event to the message broker.
  4. The InventoryService, a subscriber to OrderCreated events, receives the event, reserves the stock, and publishes an InventoryReserved event.
  5. The PaymentService, another subscriber, receives the OrderCreated event, processes the payment, and publishes a PaymentSucceeded event.
  6. The OrderService itself subscribes to InventoryReserved and PaymentSucceeded. When it receives both, it updates the order's status from PENDING to CONFIRMED.
Distributed Monolith vs. True Microservices Architecture
This diagram provides a powerful visual contrast. The 'Distributed Monolith' on the left uses synchronous HTTP calls, creating a tangled web of dependencies. The 'True Microservices' on the right use an asynchronous 'MESSAGE QUEUE / EVENT BUS', which decouples the services and improves resilience.

Trade-offs of Asynchronous Communication

This pattern offers a solution to the brittleness of synchronous chains, but it introduces its own set of challenges.

How Microservices Communicate? Sync vs Async. Direct vs Brokers And Event Busses

This video from DevOps & AI Toolkit gives a concise overview of the core ideas behind asynchronous communication and its impact on system resilience.

Watch these key segments: Sync vs Async for a fundamental definition. Async with Brokers to understand the role of the message bus. Resilience Trade-offs to see why this pattern is more robust.

The key trade-offs are:

  • Pros:

    • Loose Coupling: Services are decoupled. The OrderService doesn't need to know who is listening for OrderCreated events. It can go offline, and the events will simply queue up in the broker until it comes back.
    • Resilience and Fault Isolation: The failure of a downstream service (like PaymentService) does not impact the initial order creation. The system can gracefully handle temporary outages.
    • Scalability: You can easily add more consumers. If order processing is slow, you can simply spin up more instances of the InventoryService to work through the queue without changing the OrderService at all.
  • Cons:

    • Increased Complexity: The overall flow is much harder to trace and debug. You can't follow a single request; you have to track events across multiple services and brokers.
    • Eventual Consistency: This is a critical concept. The client gets an immediate response, but the system's true state is not known instantly. The data becomes consistent eventually. The user might see their order as "Processing" for a few seconds before it's confirmed. This requires a shift in thinking from the immediate, transactional guarantees of a monolith.
    • Operational Overhead: You must deploy, manage, and monitor a message broker, which is a complex distributed system in its own right.

Strategic Comparison

Now that we've seen both patterns, let's bring it all together. The choice is not about which is "better" but which is appropriate for a given task. Production systems almost always use a hybrid model.

Architectural Strategies for Data Sharing

This article from Andrei Mutu provides a deep, written analysis comparing these two strategies.

Read the following sections to solidify your understanding: "Strategy II: Synchronous API Communication (REST vs. gRPC)": This section details the synchronous approach, offering excellent performance benchmarks between REST and gRPC that highlight why gRPC is often preferred for internal communication. "Strategy III: Asynchronous Messaging (RabbitMQ vs. Kafka)": This section covers the event-driven pattern, explaining the "Push" model and the architectural differences between popular brokers.

Here's a summary table to guide your thinking:

Characteristic Synchronous (RPC) Asynchronous (Events)
Coupling Tight (temporal) Loose
Interaction Style Request-Response (blocking) Publish-Subscribe (non-blocking)
Resilience Low (cascading failures) High (failures are isolated)
Data Consistency Strong / Immediate Eventual
Complexity Low (easy to trace) High (hard to debug, requires a broker)
Use Cases Queries, reads, actions needing immediate feedback Commands, long-running tasks, notifications to many services

Choosing the Right Pattern

This decision flowchart from the OneUptime article provides a simple mental model for when to consider each pattern.


Conclusion

In this lesson, we differentiated between the two primary modes of inter-service communication and their profound architectural implications.

Key Takeaways:

  • Synchronous communication (RPC/REST) is a direct, blocking, request-response pattern. It's simple and provides immediate consistency but creates tight coupling and is prone to cascading failures.
  • Asynchronous communication (Event-Driven) is an indirect, non-blocking, publish-subscribe pattern. It promotes loose coupling, resilience, and scalability at the cost of increased complexity and eventual consistency.
  • The choice is not "either/or." Effective microservice architectures use a hybrid approach, applying the right pattern for the job. You might use synchronous calls for queries (GET /orders/{id}) and asynchronous events for commands that trigger complex workflows (OrderCreated).

Preview of the Next Lesson:

We've established that services should be independent, and a great way to achieve that is through asynchronous communication. A core tenet of this independence is that each service should own its own data. This leads to the "database-per-service" pattern. In our next lesson, we will explore the immense benefits and significant challenges of this pattern, particularly how to manage data consistency and transactions that now span multiple, independent databases.