Bird
Raised Fist0
Microservicessystem_design~25 mins

Why inter-service communication defines architecture in Microservices - Design It to Understand It

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
Design: Microservices Architecture Communication
Focus on communication mechanisms between microservices and how they shape system design. Out of scope are internal service implementations and UI design.
Functional Requirements
FR1: Enable multiple independent services to communicate effectively
FR2: Support synchronous and asynchronous communication patterns
FR3: Ensure reliable message delivery between services
FR4: Handle service discovery and load balancing
FR5: Maintain data consistency across services
FR6: Support scalability and fault tolerance
Non-Functional Requirements
NFR1: Latency for synchronous calls should be under 200ms p99
NFR2: System should handle 10,000 concurrent service-to-service calls
NFR3: Availability target of 99.9% uptime for communication channels
NFR4: Communication must be secure and authenticated
NFR5: Services may be deployed in different data centers or cloud regions
Think Before You Design
Questions to Ask
❓ Question 1
❓ Question 2
❓ Question 3
❓ Question 4
❓ Question 5
❓ Question 6
Key Components
API Gateway or Service Mesh
Message Broker (e.g., Kafka, RabbitMQ)
Service Registry and Discovery
Load Balancer
Circuit Breaker and Retry Mechanisms
Authentication and Authorization components
Design Patterns
Request-Response (Synchronous) communication
Event-Driven (Asynchronous) communication
Publish-Subscribe pattern
Saga pattern for distributed transactions
Circuit Breaker pattern
Bulkhead pattern
Reference Architecture
Client
  |
  v
API Gateway / Service Mesh
  |
  +-----------------------------+
  |                             |
Service A <--> Service B <--> Service C
  |            |               |
  v            v               v
Message Broker (Kafka/RabbitMQ)
  |
  v
Service D (Event Consumer)

Service Registry & Discovery used by all services

Authentication & Authorization layer integrated at API Gateway and services
Components
API Gateway / Service Mesh
Envoy, Istio, or NGINX
Routes requests, handles load balancing, security, and observability
Service Registry and Discovery
Consul, Eureka, or Kubernetes DNS
Allows services to find each other dynamically
Message Broker
Apache Kafka or RabbitMQ
Supports asynchronous event-driven communication and decouples services
Circuit Breaker
Resilience4j or Hystrix
Prevents cascading failures by stopping calls to failing services
Authentication and Authorization
OAuth 2.0, JWT tokens
Secures communication between services
Request Flow
1. Client sends request to API Gateway
2. API Gateway authenticates and routes request to target service
3. Service uses Service Registry to locate dependent services
4. For synchronous calls, service calls another service via API Gateway or direct HTTP/gRPC
5. For asynchronous calls, service publishes event to Message Broker
6. Other services subscribe to events from Message Broker and process asynchronously
7. Circuit Breaker monitors service health and prevents calls to unhealthy services
8. Services update state and respond back through API Gateway to client
Database Schema
Not applicable as focus is on communication; however, services maintain own databases to ensure loose coupling and data ownership.
Scaling Discussion
Bottlenecks
API Gateway becoming a single point of failure or bottleneck
Message Broker overload with high event volume
Service Registry latency causing service discovery delays
Network latency impacting synchronous calls
Failure propagation causing cascading failures
Solutions
Deploy multiple API Gateway instances with load balancing and failover
Partition and scale Message Broker clusters horizontally
Use caching and replication for Service Registry to reduce latency
Favor asynchronous communication to reduce latency impact
Implement Circuit Breaker and Bulkhead patterns to isolate failures
Interview Tips
Time: Spend 10 minutes understanding requirements and constraints, 20 minutes designing architecture and explaining communication patterns, 10 minutes discussing scaling and failure handling, 5 minutes for questions.
Explain difference between synchronous and asynchronous communication
Discuss how communication patterns affect latency and scalability
Highlight importance of service discovery and load balancing
Describe failure handling with Circuit Breaker and retries
Mention security considerations in inter-service communication
Show awareness of trade-offs between consistency and availability

Practice

(1/5)
1. Which of the following best explains why inter-service communication is crucial in microservices architecture?
easy
A. It only affects the user interface design of the application.
B. It determines how services coordinate and impacts system performance and reliability.
C. It is used to store data permanently in the database.
D. It defines the programming language used for each service.

Solution

  1. Step 1: Understand the role of inter-service communication

    Inter-service communication allows different microservices to work together by exchanging data and requests.
  2. Step 2: Identify its impact on system qualities

    This communication affects how fast and reliable the overall system is, as services depend on each other to complete tasks.
  3. Final Answer:

    It determines how services coordinate and impacts system performance and reliability. -> Option B
  4. Quick Check:

    Communication defines coordination and performance = B [OK]
Hint: Focus on coordination and system impact for communication [OK]
Common Mistakes:
  • Confusing communication with UI design
  • Thinking communication stores data permanently
  • Believing communication defines programming language
2. Which syntax correctly represents asynchronous communication between two microservices using message queues?
easy
A. serviceA.publishToQueue('taskQueue', message)
B. serviceA.sendRequest(serviceB)
C. serviceA.call(serviceB).wait()
D. serviceA.invoke(serviceB).sync()

Solution

  1. Step 1: Identify asynchronous communication syntax

    Asynchronous communication uses message queues where a service publishes messages without waiting for immediate response.
  2. Step 2: Match syntax to asynchronous pattern

    publishToQueue sends a message to a queue, fitting asynchronous style; other options imply direct or synchronous calls.
  3. Final Answer:

    <code>serviceA.publishToQueue('taskQueue', message)</code> -> Option A
  4. Quick Check:

    Message queue publish = A [OK]
Hint: Look for 'publish' or 'queue' to spot async communication [OK]
Common Mistakes:
  • Choosing direct method calls as async
  • Confusing synchronous wait with async
  • Ignoring message queue terminology
3. Given the following code snippet for synchronous communication, what will be the output if serviceB.process() takes 3 seconds to respond?
response = serviceA.call(serviceB.process)
print('Response received')
medium
A. Response received (printed immediately)
B. Response received printed twice
C. No output due to error
D. Response received (printed after 3 seconds)

Solution

  1. Step 1: Understand synchronous call behavior

    Synchronous calls wait for the called service to finish before continuing execution.
  2. Step 2: Analyze the code flow

    Since serviceB.process() takes 3 seconds, print waits and executes after the response arrives.
  3. Final Answer:

    Response received (printed after 3 seconds) -> Option D
  4. Quick Check:

    Synchronous call delays output = D [OK]
Hint: Synchronous means wait before next step [OK]
Common Mistakes:
  • Assuming immediate print without wait
  • Thinking output prints twice
  • Confusing synchronous with asynchronous
4. Identify the error in this asynchronous communication example using a message queue:
serviceA.publish('taskQueue', message)
serviceB.process()
serviceB.consume('taskQueue')
medium
A. serviceB.consume should be called before process to receive messages
B. serviceA.publish should wait for serviceB.process to finish
C. serviceB.process() should be called after consume
D. No error; the code is correct

Solution

  1. Step 1: Understand message consumption order

    To process messages, the consumer must subscribe or consume from the queue before processing.
  2. Step 2: Identify incorrect sequence

    Calling serviceB.process() before consume means no messages are received yet, causing a logic error.
  3. Final Answer:

    serviceB.consume should be called before process to receive messages -> Option A
  4. Quick Check:

    Consume before processing = C [OK]
Hint: Consume messages before processing them [OK]
Common Mistakes:
  • Calling process before consuming messages
  • Expecting publish to wait for processing
  • Thinking code order does not matter
5. You are designing a microservices system where Service A must send a request to Service B and continue working without waiting for a response. Which communication pattern should you choose to ensure scalability and loose coupling?
hard
A. Direct database polling by Service A
B. Synchronous HTTP request with retries
C. Asynchronous messaging via a message queue
D. Tightly coupled RPC calls with blocking

Solution

  1. Step 1: Analyze requirement for non-blocking communication

    Service A must not wait for Service B's response, so asynchronous communication is needed.
  2. Step 2: Choose scalable and loosely coupled pattern

    Using a message queue allows Service A to send messages and continue, while Service B processes independently, supporting scalability and loose coupling.
  3. Final Answer:

    Asynchronous messaging via a message queue -> Option C
  4. Quick Check:

    Async messaging for non-blocking and scalability = A [OK]
Hint: Pick async messaging for non-blocking, scalable design [OK]
Common Mistakes:
  • Choosing synchronous calls causing blocking
  • Using direct DB polling which is inefficient
  • Selecting tightly coupled RPC reducing flexibility