Skip to main content

Welcome to a Grasp lesson

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

Lesson 61

Synchronous vs. Asynchronous Communication in Microservices

Recommended resources

Hello! Welcome to the next lesson in our microservices module.

In our last session, we discussed the database-per-service pattern. We established that giving each service its own private database is crucial for loose coupling and scalability, but it introduces a major challenge: maintaining data consistency across a distributed system. A simple business operation, like placing an order, now becomes a complex distributed transaction.

Today, we address the next logical question: how should these independent services talk to each other? The communication style you choose is a fundamental architectural decision that directly impacts performance, resilience, and how you'll solve the data consistency problems we just discussed. Your goal for this lesson is to compare synchronous (REST) vs. asynchronous (messaging) communication patterns in microservices. This is a classic topic in senior-level system design interviews, so mastering these trade-offs is essential.

1. The Core Distinction: Synchronous vs. Asynchronous

At its heart, the choice is between a direct, blocking conversation and an indirect, non-blocking one. It's not just "REST vs. Messaging," but about the underlying interaction model.

Lesson 137 - Rest vs. Messaging

Let's start with a high-level overview. This video from 'Software Architecture Monday' frames the problem perfectly, moving beyond specific technologies to the core concepts of synchronous and asynchronous communication.

Watch the segment from 01:21 to 02:07. It clarifies that the real decision isn't about REST versus a specific messaging tech, but about choosing a synchronous or asynchronous communication style.

Now, let's break down each style.


2. Synchronous Communication: The Direct Call

In synchronous communication, the calling service sends a request to another service and waits (blocks) for a response. The entire interaction must complete before the caller can proceed. The most common implementation is a REST API call over HTTP.

Microservices Communication Patterns
This image visually contrasts synchronous patterns like REST and gRPC, where the caller waits for a response, with asynchronous messaging that uses an intermediary message broker.

How It Works

A client (e.g., Order Service) makes a direct network call (e.g., using a Feign client in Spring Boot) to a server (e.g., Inventory Service). The thread on the Order Service is blocked until the Inventory Service processes the request and sends a response back.

Synchronous vs. Asynchronous Design Patterns in MicroServices

For a clear definition and a practical code example, let's look at this article from Swapnil Kalbande.

Read the section titled '1️⃣ Synchronous Communication: The Direct Approach'. Pay close attention to the pros and cons, and review the Spring Boot code snippet showing an OrderController using a FeignClient to call an InventoryController. This is a very common pattern in enterprise Java.

Key Characteristics & Trade-offs

Based on the article and general principles, here's a summary:

Pros Cons
Simplicity Temporal Coupling
The request-response model is intuitive, making it easier to implement and debug. The caller and receiver must both be available at the same time. If the Inventory Service is down, the Order Service call will fail.
Immediate Feedback Higher Latency
The caller gets an immediate success or failure response. This is critical for real-time validation (e.g., "Is this credit card valid?"). The caller's response time is the sum of its own processing, network latency, and the receiver's processing time. Chained calls can lead to poor performance.
Easier Tracing Reduced Resilience
A single request has a clear, linear execution path, which is simpler to trace and monitor. Failures can easily cascade. A slowdown in a downstream service directly impacts all upstream services calling it.

When to use synchronous communication?
Use it for requests that need an immediate response or where the business logic demands it.

  • Queries: Fetching data (e.g., get user profile).
  • Validation: Real-time checks (e.g., check product stock before adding to cart).
  • Authorization: Commands that require immediate confirmation (e.g., processing a payment).

3. Asynchronous Communication: The Fire-and-Forget Message

In asynchronous communication, the sending service (the producer) publishes a message to a channel without waiting for a result. Another service (the consumer) subscribes to this channel, picks up the message, and processes it independently.

This pattern introduces a new component: the message broker (e.g., RabbitMQ, Apache Kafka). The broker acts as an intermediary, persisting messages and ensuring they are delivered to consumers.

Asynchronous communication in Microservices Interview Questions and Answers | Part -3 | Code Decode

The 'Code Decode' channel provides a great walk-through of asynchronous communication using a clear analogy and explains the critical role of the message broker.

Watch this segment from 01:57 to 08:23. It explains how a service sends a message and 'forgets' about it, letting the broker handle delivery. Focus on how this breaks the tight coupling and improves fault tolerance compared to a REST call.

How It Works

The Order Service doesn't call the Notification Service directly. Instead, it publishes an OrderPlaced event to a Kafka topic. The Notification Service, a consumer of this topic, receives the event and sends the confirmation email. The Order Service can immediately return a response to the user without waiting for the email to be sent.

Synchronous vs. Asynchronous Design Patterns in MicroServices

The same Medium article provides a corresponding code example for this asynchronous pattern using Kafka and Spring Boot.

Now read section '2️⃣ Asynchronous Communication: The Event-Driven Approach'. Review the OrderProducer using KafkaTemplate and the InventoryConsumer using @KafkaListener. This demonstrates the producer/consumer relationship in code.

Key Characteristics & Trade-offs

Pros Cons
Loose Coupling Increased Complexity
The producer and consumer don't need to know about each other. The consumer can be down, and the producer can still accept requests. You now have a message broker as a critical piece of infrastructure to deploy, manage, and monitor.
Improved Resilience Eventual Consistency
The message broker isolates services. If the Notification Service is down, messages queue up and are processed when it recovers. This prevents cascading failures. There is a delay between an action and its outcome. The user gets an 'order confirmed' message, but the confirmation email might arrive seconds or minutes later.
Responsiveness & Scalability Difficult Error Handling
The initial service responds very quickly. The broker can also act as a buffer, absorbing traffic spikes (load leveling), allowing consumers to be scaled independently. If the consumer fails to process a message, how do you notify the original user? This often requires complex patterns like Dead Letter Queues (DLQs) and compensating transactions.

Message-Passing Models

There are two main models for asynchronous messaging:

  1. Point-to-Point (Queue): A message is sent by one producer to a queue and is processed by exactly one consumer. Once consumed, the message is removed. This is used for command-style interactions where a specific task needs to be done once. (e.g., RabbitMQ).
  2. Publish-Subscribe (Topic): A message is published by one producer to a topic and can be received by many consumers. Each consumer group gets a copy of the message. This is used for event-driven architectures where multiple services might need to react to the same event (e.g., an OrderPlaced event could be consumed by Notification, Inventory, and Analytics services). (e.g., Apache Kafka).
Test your understanding!

An Order Service needs to trigger an inventory update and send a shipping notification. Should it use a queue or a topic?

Show answer

This is a great use case for the Publish-Subscribe (Topic) model. The Order Service would publish a single OrderPlaced event to a topic. Both the Inventory Service and the Shipping Service would subscribe to this topic and react to the event independently. Using a queue would be incorrect, as only one of the services would be able to process the message.


4. The Architect's Decision: A Summary of Trade-offs

The choice is never about one pattern being universally better; it's about choosing the right tool for the job. Complex systems almost always use a hybrid approach.

Interservice communication in microservices - Azure

This document from Microsoft Azure provides a formal summary of the trade-offs involved.

Read the sections 'Synchronous versus asynchronous messaging', the list of benefits under 'Asynchronous message passing', and the challenges listed immediately after. This reinforces the pros and cons we've discussed with a formal architectural perspective.

Here is a summary table to guide your decision-making, a crucial asset for any system design interview:

Dimension Synchronous (e.g., REST/gRPC) Asynchronous (e.g., Kafka/RabbitMQ)
Coupling Tightly Coupled (Temporal) Loosely Coupled
System Resilience Lower (risk of cascading failures) Higher (failure isolation via broker)
User-Perceived Latency Higher (waits for full process) Lower (fast initial response)
Data Consistency Strong/Immediate (within the call) Eventual (takes time to propagate)
Implementation Complexity Lower (direct, familiar paradigm) Higher (requires broker, complex error handling)
Typical Use Cases Queries, real-time validation, payments Notifications, background jobs, data pipelines, analytics

A common and powerful hybrid pattern is to have a public-facing API Gateway that accepts synchronous REST calls, which then triggers an asynchronous workflow internally. For example, a user submits an order via a synchronous API call, but the order fulfillment process (inventory, shipping, notifications) is handled by a series of asynchronous events.


5. Common Interview Question

Let's apply this to a typical interview scenario.

Interviewer: "You're designing a food delivery app. A user places an order. Walk me through the communication patterns you would use for the following steps and justify your choices:"

  1. Verifying the user's payment method.
  2. Sending the order to the restaurant.
  3. Notifying the user that the restaurant has confirmed the order.
  4. Updating the live location of the delivery driver on the user's map.
Show suggested answer

Here's a structured way to answer:

"I would use a hybrid approach, choosing the communication style that best fits the requirements of each step.

  1. Verifying Payment Method: Synchronous.

    • Justification: This is a blocking, real-time validation. The user cannot proceed until their payment is confirmed or denied. A direct, synchronous call to a Payment Service (which might in turn call a third-party gateway like Stripe) is necessary to provide immediate feedback. Using an asynchronous pattern here would lead to a poor user experience, as they wouldn't know if their order was successfully initiated.
  2. Sending the Order to the Restaurant: Asynchronous.

    • Justification: The Order Service should not be tightly coupled to the Restaurant Service. A restaurant's point-of-sale system might be temporarily offline. I would have the Order Service publish an OrderPlaced event to a message broker (e.g., RabbitMQ queue). The Restaurant Service would be the consumer. This makes the system resilient. If the restaurant's system is down, the order remains in the queue and can be processed when it's back online, preventing the user's request from failing.
  3. Notifying the User of Confirmation: Asynchronous.

    • Justification: This is a classic notification use case. Once the restaurant's system processes the order, it would publish a RestaurantOrderConfirmed event. A Notification Service would subscribe to this event and send a push notification or SMS to the user. There's no need to make any part of the system wait for the notification to be sent. The communication is one-way and doesn't require an immediate response.
  4. Updating Live Driver Location: Asynchronous (Publish/Subscribe).

    • Justification: This requires broadcasting information. The driver's app would continuously publish LocationUpdated events to a message broker (e.g., a Kafka topic) containing the driver's ID and coordinates. The user's client application would subscribe to this topic (likely via a WebSocket connection managed by a backend service) to receive a real-time stream of updates. This is a perfect fit for the publish-subscribe model, as it decouples the driver's app from the potentially numerous users watching the map."

Conclusion

You've now explored the fundamental trade-offs between synchronous and asynchronous communication in microservices. There is no single "best" pattern; the choice is driven entirely by the specific requirements of the interaction.

Key Takeaways:

  • Synchronous communication (e.g., REST) is simple and provides immediate consistency but creates tight coupling and is less resilient to failure.
  • Asynchronous communication (e.g., messaging) provides loose coupling, resilience, and scalability but introduces the complexity of a message broker and leads to eventual consistency.
  • Most real-world, large-scale systems use a hybrid model, applying the appropriate pattern for each service interaction.
  • Understanding when to use each is a hallmark of a senior engineer and a critical skill for system design interviews.

Preview of the Next Lesson:
We've seen that complex business processes often involve multiple services. If we use an asynchronous, event-driven approach for resilience (like the 'Place Order' example), how do we guarantee that a multi-step process either completes fully or is properly compensated for if a step fails? We can't use a traditional distributed transaction. This is the exact problem that the Saga pattern is designed to solve. In the next lesson, we will explore both choreography-based and orchestration-based Sagas to manage distributed transactions.