Bird
Raised Fist0
Microservicessystem_design~7 mins

Synchronous vs asynchronous communication in Microservices - Architecture Trade-offs

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Problem Statement
When microservices communicate synchronously, a slow or failing service can block the entire request flow, causing delays or failures. Conversely, without asynchronous communication, services cannot decouple their workloads, leading to tight dependencies and reduced resilience.
Solution
Synchronous communication waits for a response before continuing, ensuring immediate results but risking delays if a service is slow. Asynchronous communication sends requests without waiting, allowing services to continue working independently and handle responses later, improving resilience and scalability.
Architecture
Service A
(Client)
Service B
Service A
(Producer)
Message

The diagram shows two communication styles: synchronous calls where Service A waits for Service B's response, and asynchronous messaging where Service A sends a message to a queue and continues without waiting, while Service B processes messages independently.

Trade-offs
✓ Pros
Synchronous communication provides immediate feedback and simpler error handling.
Asynchronous communication improves system resilience by decoupling services.
Asynchronous allows better scalability by smoothing traffic spikes with message queues.
Synchronous is easier to implement and reason about for simple workflows.
✗ Cons
Synchronous calls can cause cascading failures if downstream services are slow or down.
Asynchronous communication adds complexity in message handling and eventual consistency.
Debugging asynchronous flows is harder due to lack of immediate response and tracing.
Synchronous communication can reduce system throughput under high load.
Use synchronous communication for simple, low-latency operations where immediate response is critical and service reliability is high. Use asynchronous communication when services need to be loosely coupled, handle variable load, or tolerate delays without blocking.
Avoid synchronous communication when downstream services are unreliable or slow, or when scaling beyond a few hundred requests per second. Avoid asynchronous communication for operations requiring immediate consistency or real-time user feedback.
Real World Examples
Uber
Uses asynchronous messaging to decouple ride request processing from payment and notification services, improving reliability during peak loads.
Netflix
Employs asynchronous event-driven communication for user activity logging and recommendation updates to avoid blocking user streaming sessions.
Amazon
Uses synchronous calls for inventory checks during checkout but asynchronous messaging for order fulfillment workflows to handle scale and failures gracefully.
Code Example
The before code shows a synchronous HTTP request that waits for a response, blocking the caller. The after code demonstrates sending a request message to a queue and processing it asynchronously in a separate thread, allowing the caller to continue immediately.
Microservices
### Before: Synchronous call (naive) ###
import requests

def get_user_profile(user_id):
    response = requests.get(f"http://service-b/users/{user_id}")
    return response.json()


### After: Asynchronous call using message queue ###
import json
import threading

message_queue = []  # Simplified queue

def send_user_request(user_id):
    message = json.dumps({"user_id": user_id})
    message_queue.append(message)
    print(f"Request sent for user {user_id}")


def process_messages():
    while message_queue:
        message = message_queue.pop(0)
        data = json.loads(message)
        print(f"Processing user {data['user_id']} asynchronously")

# Usage
send_user_request(123)
threading.Thread(target=process_messages).start()
OutputSuccess
Alternatives
Event-driven architecture
Focuses on emitting and reacting to events asynchronously rather than direct service-to-service calls.
Use when: Choose when you want highly decoupled services reacting to state changes without tight request-response dependencies.
API Gateway with request aggregation
Aggregates multiple synchronous calls behind a single endpoint to reduce client complexity.
Use when: Choose when clients need synchronous responses but backend services are distributed.
Summary
Synchronous communication waits for a response, risking delays if services are slow or down.
Asynchronous communication decouples services by sending messages without waiting, improving resilience and scalability.
Choosing between them depends on system requirements for latency, reliability, and complexity.

Practice

(1/5)
1. Which statement best describes synchronous communication in microservices?
easy
A. The caller waits for the response before continuing.
B. The caller sends a request and continues without waiting.
C. The services communicate only through message queues.
D. The services never exchange data directly.

Solution

  1. Step 1: Understand synchronous communication

    Synchronous communication means the caller waits for the response before moving on.
  2. Step 2: Compare options

    The caller waits for the response before continuing. matches this definition exactly, while others describe asynchronous or unrelated concepts.
  3. Final Answer:

    The caller waits for the response before continuing. -> Option A
  4. Quick Check:

    Synchronous = Wait for reply [OK]
Hint: Synchronous means wait for reply before next step [OK]
Common Mistakes:
  • Confusing synchronous with asynchronous communication
  • Thinking synchronous means no waiting
  • Assuming message queues are always synchronous
2. Which of the following is the correct way to describe asynchronous communication in microservices?
easy
A. The caller blocks until the response is received.
B. The caller uses a direct function call to get the result.
C. The services must be on the same server.
D. The caller sends a request and processes the response later.

Solution

  1. Step 1: Define asynchronous communication

    Asynchronous means the caller sends a request and does not wait; it handles the response later.
  2. Step 2: Evaluate options

    The caller sends a request and processes the response later. correctly describes this behavior. Options A and D describe synchronous calls, and C is unrelated.
  3. Final Answer:

    The caller sends a request and processes the response later. -> Option D
  4. Quick Check:

    Asynchronous = Send and continue [OK]
Hint: Async means send request, handle reply later [OK]
Common Mistakes:
  • Mixing up blocking and non-blocking calls
  • Assuming async requires same server
  • Thinking async means no response
3. Consider this pseudocode for a microservice call:
response = callServiceSync(request)
print("Done")
What will be the output order?
medium
A. "Done" prints before the service responds.
B. "Done" prints after the service responds.
C. The code throws an error because of missing callback.
D. The code runs asynchronously without waiting.

Solution

  1. Step 1: Analyze synchronous call behavior

    The function callServiceSync waits for the service response before returning.
  2. Step 2: Determine print timing

    Since the call blocks, "Done" prints only after the response is received.
  3. Final Answer:

    "Done" prints after the service responds. -> Option B
  4. Quick Check:

    Synchronous call blocks, then prints [OK]
Hint: Sync calls block; print happens after response [OK]
Common Mistakes:
  • Assuming print runs before response
  • Confusing sync with async calls
  • Expecting errors due to missing async syntax
4. A developer wrote this asynchronous call:
sendRequestAsync(request)
print("Request sent")
waitForResponse()
But the system blocks until the response arrives. What is the likely mistake?
medium
A. print statement should be after waitForResponse().
B. sendRequestAsync() is actually synchronous.
C. Calling waitForResponse() immediately blocks the flow.
D. The request object is malformed.

Solution

  1. Step 1: Understand asynchronous call flow

    sendRequestAsync should not block, but waitForResponse() forces waiting.
  2. Step 2: Identify blocking cause

    Calling waitForResponse() immediately after sends blocks the flow, negating async benefits.
  3. Final Answer:

    Calling waitForResponse() immediately blocks the flow. -> Option C
  4. Quick Check:

    Immediate wait blocks async [OK]
Hint: Waiting right after async call blocks it [OK]
Common Mistakes:
  • Assuming async call is sync
  • Misplacing print statement
  • Blaming request format instead of flow
5. You design a microservice system where user requests must get immediate confirmation, but heavy processing can be delayed. Which communication pattern fits best?
hard
A. Use synchronous communication for confirmation and asynchronous for processing.
B. Use only synchronous communication for all tasks.
C. Use only asynchronous communication for all tasks.
D. Use synchronous communication for processing and asynchronous for confirmation.

Solution

  1. Step 1: Analyze requirements

    Immediate confirmation requires waiting for a quick response (synchronous).
  2. Step 2: Handle heavy processing

    Heavy tasks can be done later without blocking user, so asynchronous fits.
  3. Step 3: Match communication patterns

    Combining synchronous for confirmation and asynchronous for processing meets both needs efficiently.
  4. Final Answer:

    Use synchronous communication for confirmation and asynchronous for processing. -> Option A
  5. Quick Check:

    Immediate reply = sync, heavy work = async [OK]
Hint: Immediate reply sync, heavy work async combo [OK]
Common Mistakes:
  • Using only sync causes delays
  • Using only async delays confirmation
  • Reversing sync and async roles