Chuyển đến nội dung chính

Lesson 6: Inter-service Communication — Sync, Async & Event-Driven

Synchronous (HTTP, gRPC) vs Asynchronous (Message Queue, Event Streaming) communication. Request-Reply, Publish-Subscribe, Event Notification patterns. When to use RabbitMQ vs Kafka vs NATS. Avoid distributing monolith anti-pattern.

🏗️ Architecture — Lesson 6 Lesson 6: Inter-service Communication — Sync, Async & Event-Driven

Microservices & Micro Frontend system design — From basics to Production

Part 2: Designing Microservices Backend

xdev.asia

Introduction

How microservices communicate with each other determines the coupling, reliability, and performance of the entire system. This article analyzes communication patterns and guides on choosing the right pattern for each use case.

Inter-service Communication — Sync, Async and Event Streaming


1. Synchronous Communication

1.1 Request-Reply Pattern

┌──────────┐   HTTP/gRPC    ┌──────────┐
│  Order   │ ──────────────►│ Product  │
│  Service │◄────────────── │ Service  │
└──────────┘   Response     └──────────┘

Order Service gọi Product Service để validate product trước khi tạo order.
Phải đợi response → coupling tạm thời (temporal coupling).

Advantages:

  • Simple, easy to understand, easy to debug
  • Response immediately
  • Explicit error handling (HTTP status codes)

Disadvantages:

  • Temporal coupling: caller blocked until receiving response
  • Cascade failure: if Product Service goes down → Order Service also fails
  • Latency increases with each hop in the call chain

1.2 Minimize Sync risks

  • Circuit Breaker: breaks circuit when downstream service fails
  • Timeout: set a reasonable timeout (not too long)
  • Retry with backoff: retry with exponential backoff
  • Fallback: returns cached data or default response
  • Bulkhead: isolate connection pools for each downstream

2. Asynchronous Communication

2.1 Message Queue Pattern

┌──────────┐   Enqueue      ┌──────────┐   Dequeue     ┌──────────┐
│  Order   │ ──────────────►│  Queue   │──────────────►│  Email   │
│  Service │                │(RabbitMQ)│               │  Service │
└──────────┘                └──────────┘               └──────────┘

Fire-and-forget: Order Service gửi message, không đợi.
Email Service xử lý khi sẵn sàng (rate riêng).
Queue đảm bảo message không mất.

Use cases:

  • Task distribution (send email, resize image)
  • Work queues (process video, generate report)
  • Load leveling (absorb traffic spikes)

2.2 Event Streaming / Pub-Sub Pattern

┌──────────┐                ┌──────────────┐
│  Order   │──publish──────►│    Kafka     │
│  Service │  OrderPlaced   │   Topic:     │
└──────────┘                │  orders      │
                            └──┬───┬───┬───┘
                               │   │   │
                    ┌──────────┘   │   └──────────┐
                    ▼              ▼              ▼
              ┌──────────┐  ┌──────────┐  ┌──────────┐
              │ Payment  │  │Inventory │  │  Email   │
              │ Service  │  │ Service  │  │  Service │
              └──────────┘  └──────────┘  └──────────┘

1 event → N consumers. Services không biết nhau → loose coupling.
Events được lưu trữ → có thể replay (event sourcing).

Use cases:

  • Domain events (OrderPlaced, PaymentConfirmed)
  • Data replication across services
  • Event sourcing & audit trail
  • Real-time analytics

2.3 Event Notification vs Event-Carried State Transfer

PatternWhat does Event containWhat do consumers need
Event NotificationID only: {orderId: "123"}Query source service again
Event-Carried StateFull data: {orderId, items, total, ...}No need to query again

Recommendation: Event-Carried State Transfer helps reduce coupling (consumers do not need to call the source again).


3. Compare Message Brokers

FeaturesRabbitMQApache KafkaNATS
ModelMessage QueueEvent Stream/LogPub/Sub + JetStream
OrderingPer queuePer partitionPer subject
RetentionConsumed → deletedConfigurable (days/forever)JetStream: configurable
Throughput~50K msg/s~1M msg/s~10M msg/s
ReplayNoYes (offset-based)JetStream: Yes
Consumer groupsYesYesJetStream: Yes
ComplexityAverageHigh (ZooKeeper/KRaft)Low
Best forTask queues, RPCEvent streaming, sourcingCloud-native, lightweight

3.1 When to use what?

RabbitMQ: Task queues (send email, process image)
          Request-Reply pattern (RPC over messages)
          Complex routing (exchanges, bindings)

Kafka:    Domain events (OrderPlaced, PaymentConfirmed)
          Event sourcing & CQRS
          Data pipeline & streaming analytics
          Audit trail (event log)

NATS:     Lightweight microservices communication
          Real-time messaging (chat, notifications)
          Cloud-native, Kubernetes-native
          Request-Reply + Pub/Sub combined

4. Hybrid Approach (Production Pattern)

In practice, most systems use a combination of both:

┌─────────────────────────────────────────────────┐
│              E-Commerce Communication           │
├─────────────────────────────────────────────────┤
│ SYNCHRONOUS (REST/gRPC):                        │
│ • GET product details (query, cần response ngay)│
│ • Validate payment (command, cần kết quả)       │
│ • Search products (query, real-time)            │
├─────────────────────────────────────────────────┤
│ ASYNCHRONOUS (Kafka Events):                    │
│ • OrderPlaced → trigger Payment, Inventory      │
│ • PaymentConfirmed → trigger Shipping           │
│ • UserRegistered → trigger Welcome Email        │
│ • ProductUpdated → update Search Index          │
└─────────────────────────────────────────────────┘

Summary

PatternWhen to useTradeoff
Sync (REST/gRPC)Need immediate response, query dataTight coupling, cascade failure
Async QueueTask distribution, load levelingEventual consistency
Async EventsDomain events, data syncComplexity, difficult debugging
HybridProduction recommendationNeed to manage both

Next article: Lesson 7: Database per Service & Polyglot Persistence