Bird
Raised Fist0
Microservicessystem_design~7 mins

Anti-patterns (distributed monolith, chatty services) in Microservices - System Design Guide

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 are designed without clear boundaries or have excessive inter-service communication, the system behaves like a single monolith spread across multiple services. This causes slow responses, complex debugging, and tight coupling that defeats the purpose of microservices.
Solution
Avoid tight coupling by defining clear service boundaries and minimizing synchronous calls between services. Use asynchronous communication or event-driven patterns to reduce chatty interactions and ensure services can evolve independently.
Architecture
Service A
Service B
Service A
Event Bus

The first diagram shows services tightly coupled with many synchronous calls causing a distributed monolith. The second diagram shows services communicating asynchronously via an event bus to reduce chatty interactions.

Trade-offs
✓ Pros
Improves service independence and scalability by reducing tight coupling.
Reduces latency caused by multiple synchronous calls.
Simplifies debugging by limiting complex inter-service dependencies.
Enables teams to deploy and evolve services independently.
✗ Cons
Requires careful design of service boundaries and communication patterns.
Asynchronous communication can increase system complexity and eventual consistency challenges.
Refactoring existing distributed monoliths can be time-consuming and risky.
When building or refactoring microservices with high inter-service communication and tight coupling, especially at scale above hundreds of services or thousands of requests per second.
When the system is small with few services and low traffic, the overhead of complex asynchronous communication may outweigh benefits.
Real World Examples
Netflix
Refactored from a distributed monolith to event-driven microservices to reduce chatty synchronous calls and improve resilience.
Uber
Uses asynchronous messaging to decouple services and avoid chatty interactions in their ride matching and pricing systems.
Amazon
Avoids distributed monoliths by enforcing strict service boundaries and using event-driven architecture for order processing.
Code Example
The before code shows ServiceA calling ServiceB synchronously, creating tight coupling and chatty calls. The after code uses an EventBus to publish events asynchronously, allowing ServiceB to handle events without direct calls, reducing coupling and chatty communication.
Microservices
### Before: Chatty synchronous calls causing tight coupling
class ServiceA:
    def call_service_b(self):
        service_b = ServiceB()
        result = service_b.process()
        return result

class ServiceB:
    def process(self):
        # Some processing
        return "data"


### After: Asynchronous event-driven communication reducing chatty calls
import asyncio

class EventBus:
    def __init__(self):
        self.subscribers = {}

    def subscribe(self, event_type, handler):
        self.subscribers.setdefault(event_type, []).append(handler)

    async def publish(self, event_type, data):
        handlers = self.subscribers.get(event_type, [])
        for handler in handlers:
            await handler(data)

class ServiceA:
    def __init__(self, event_bus):
        self.event_bus = event_bus

    async def do_work(self):
        await self.event_bus.publish('event_b', {'info': 'start'})

class ServiceB:
    async def handle_event(self, data):
        # Process event asynchronously
        print(f"Processing event with data: {data}")

# Setup
bus = EventBus()
service_b = ServiceB()
bus.subscribe('event_b', service_b.handle_event)
service_a = ServiceA(bus)

# Run
asyncio.run(service_a.do_work())
OutputSuccess
Alternatives
API Gateway
Centralizes communication and reduces direct service-to-service calls by routing through a gateway.
Use when: When you want to simplify client interactions but still need to reduce chatty calls between backend services.
Backend for Frontend (BFF)
Creates specialized backend services per client type to reduce chatty calls from frontend to multiple microservices.
Use when: When frontend clients cause excessive calls to many services and need tailored aggregation.
Summary
Distributed monoliths occur when microservices are tightly coupled with excessive synchronous calls.
Reducing chatty services by using asynchronous communication improves scalability and independence.
Careful design of service boundaries and communication patterns prevents these anti-patterns.

Practice

(1/5)
1. Which of the following best describes a distributed monolith in microservices architecture?
easy
A. Services are fully independent and communicate rarely.
B. Services are tightly coupled and require coordinated deployment.
C. Services use asynchronous messaging to reduce latency.
D. Services are stateless and scale automatically.

Solution

  1. Step 1: Understand distributed monolith characteristics

    A distributed monolith looks like microservices but behaves like a single app with tight coupling.
  2. Step 2: Identify deployment and coupling issues

    Such services require coordinated deployment and cannot scale independently.
  3. Final Answer:

    Services are tightly coupled and require coordinated deployment. -> Option B
  4. Quick Check:

    Distributed monolith = tight coupling [OK]
Hint: Distributed monolith means tight coupling, not independence [OK]
Common Mistakes:
  • Confusing distributed monolith with loosely coupled microservices
  • Thinking distributed monolith scales independently
  • Assuming distributed monolith uses asynchronous calls
2. Which syntax correctly describes a common symptom of chatty services in microservices communication?
easy
A. Service A uses event-driven messaging to notify Service B.
B. Service A calls Service B once per user request.
C. Service A calls Service B multiple times per user request.
D. Service A caches data to reduce calls to Service B.

Solution

  1. Step 1: Define chatty services behavior

    Chatty services make many small calls between services per user request.
  2. Step 2: Identify the correct syntax describing chatty calls

    Multiple calls per request indicate chatty communication.
  3. Final Answer:

    Service A calls Service B multiple times per user request. -> Option C
  4. Quick Check:

    Chatty services = many calls [OK]
Hint: Chatty means many calls, not just one [OK]
Common Mistakes:
  • Choosing event-driven messaging as chatty behavior
  • Assuming caching causes chatty services
  • Thinking one call per request is chatty
3. Given a microservices system where Service A calls Service B 5 times and Service B calls Service C 3 times per user request, what is the total number of service calls triggered by one user request?
medium
A. 20
B. 15
C. 30
D. 8

Solution

  1. Step 1: Calculate calls from Service A to B

    Service A calls Service B 5 times per request.
  2. Step 2: Calculate calls from Service B to C triggered by A's calls

    Each of the 5 calls from A causes 3 calls from B to C, so 5 * 3 = 15 calls.
  3. Step 3: Sum all calls

    Total calls = 5 (A->B) + 15 (B->C) = 20 calls.
  4. Final Answer:

    20 -> Option A
  5. Quick Check:

    5 + (5*3) = 20 [OK]
Hint: Multiply nested calls, then add all [OK]
Common Mistakes:
  • Adding 5 + 3 instead of multiplying
  • Ignoring nested calls from B to C
  • Choosing sum as 18 instead of 20
4. You notice your microservices system has high latency due to many small synchronous calls between services. Which change would best fix this chatty service anti-pattern?
medium
A. Use asynchronous messaging or batch requests to reduce calls.
B. Combine tightly coupled services into a single service.
C. Add more synchronous calls to improve data freshness.
D. Increase the number of service instances to handle load.

Solution

  1. Step 1: Identify chatty service problem

    Many small synchronous calls cause latency and network overhead.
  2. Step 2: Choose solution to reduce call frequency

    Using asynchronous messaging or batching reduces calls and latency.
  3. Final Answer:

    Use asynchronous messaging or batch requests to reduce calls. -> Option A
  4. Quick Check:

    Reduce calls with async or batching [OK]
Hint: Reduce calls by batching or async messaging [OK]
Common Mistakes:
  • Combining services creates distributed monolith
  • Adding more sync calls worsens latency
  • Scaling instances doesn't reduce call count
5. A company has a microservices system suffering from both distributed monolith and chatty services anti-patterns. Which combined approach best improves scalability and deployment independence?
hard
A. Merge all services into one large application to simplify deployment.
B. Increase hardware resources and add load balancers to handle traffic.
C. Use synchronous REST calls extensively to keep services tightly connected.
D. Refactor services to reduce dependencies and use asynchronous communication.

Solution

  1. Step 1: Address distributed monolith by reducing dependencies

    Refactoring services to be loosely coupled allows independent deployment and scaling.
  2. Step 2: Fix chatty services by adopting asynchronous communication

    Using async messaging reduces frequent synchronous calls and network overhead.
  3. Step 3: Combine both improvements for better scalability and independence

    This combined approach solves both anti-patterns effectively.
  4. Final Answer:

    Refactor services to reduce dependencies and use asynchronous communication. -> Option D
  5. Quick Check:

    Loose coupling + async = scalable microservices [OK]
Hint: Loose coupling + async communication fixes both issues [OK]
Common Mistakes:
  • Merging services worsens distributed monolith
  • Adding hardware doesn't fix design flaws
  • Using more sync calls increases chatty problems