Giao diện
📬 ASYNCHRONOUS MESSAGING
Kafka vs RabbitMQ: Cuộc chiến Kinh điển của Message Brokers
Mục tiêu Học tập
Sau khi hoàn thành module này, bạn sẽ có khả năng:
- Phân biệt Synchronous vs Asynchronous communication patterns
- Hiểu kiến trúc Message Queue (Producer → Broker → Consumer)
- So sánh Kafka vs RabbitMQ và chọn đúng tool
- Implement Pub/Sub và Dead Letter Queue patterns
1. Why Asynchronous? Tại sao không gọi trực tiếp?
NOTE
🎓 Giáo sư Tom: Synchronous: "Tôi gọi, bạn trả lời, tôi đợi". Asynchronous: "Tôi gửi tin nhắn, đi làm việc khác, bạn xử lý khi nào xong thì xong". Đây là sự khác biệt cơ bản giữa tight coupling và loose coupling.
┌─────────────────────────────────────────────────────────────────────────┐
│ SYNCHRONOUS vs ASYNCHRONOUS │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ SYNCHRONOUS (Blocking): │
│ ═══════════════════════ │
│ │
│ User ────► Order Service ────► Payment Service ────► Inventory │
│ wait wait wait wait │
│ User ◄──── Order Service ◄──── Payment Service ◄──── Inventory │
│ │
│ Total latency = Sum of ALL service latencies │
│ If Payment is slow (2s) → User waits 2+ seconds │
│ If Inventory down → ENTIRE request fails │
│ │
│ ──────────────────────────────────────────────────────────────────── │
│ │
│ ASYNCHRONOUS (Non-blocking): │
│ ═════════════════════════════ │
│ │
│ User ────► Order Service ────► Message Queue │
│ ◄──── "Order received" (async process) │
│ User done! │ │
│ ├────► Payment Service │
│ (User doing other things) │ │ │
│ │ ▼ │
│ │ ┌──────────┐ │
│ │ │ Success! │ │
│ │ └──────────┘ │
│ │ │
│ └────► Inventory Service │
│ └────► Notification Service │
│ │
│ ✅ User gets instant response │
│ ✅ Services process independently │
│ ✅ One service down ≠ entire flow fails │
│ │
└─────────────────────────────────────────────────────────────────────────┘1.1 When to Use Async?
| Scenario | Sync or Async? |
|---|---|
| User login (need immediate result) | Sync |
| Send email after registration | Async |
| Process payment (need result) | Sync → Then Async for receipt |
| Generate PDF report | Async (job queue) |
| Update search index | Async |
| Real-time notifications | Async |
| Analytics/Logging | Async |
2. Message Queue Architecture
2.1 Core Components
┌─────────────────────────────────────────────────────────────────────────┐
│ MESSAGE QUEUE ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────────────┐ ┌───────────┐ │
│ │ PRODUCER │ │ BROKER │ │ CONSUMER │ │
│ │ │ ──────► │ │ ──────► │ │ │
│ │ (Publisher) │ │ ┌───────────────┐ │ │(Subscriber│ │
│ │ │ │ │ QUEUE │ │ │ │ │
│ └─────────────┘ │ │ ┌─┬─┬─┬─┬─┐ │ │ └───────────┘ │
│ │ │ │M│M│M│M│M│ │ │ │
│ │ │ │1│2│3│4│5│ │ │ │
│ │ │ └─┴─┴─┴─┴─┘ │ │ │
│ │ └───────────────┘ │ │
│ │ │ │
│ └─────────────────────┘ │
│ │
│ PRODUCER: │
│ • Tạo message, gửi đến broker │
│ • Không cần biết ai sẽ xử lý (decoupling) │
│ │
│ BROKER (Message Queue): │
│ • Nhận message từ producers │
│ • Lưu trữ message (persistence) │
│ • Deliver message đến consumers │
│ • Handle failures, retries, ordering │
│ │
│ CONSUMER: │
│ • Subscribe vào queue │
│ • Process message │
│ • ACK sau khi xử lý xong │
│ │
└─────────────────────────────────────────────────────────────────────────┘
)2.2 Delivery Guarantees
┌─────────────────────────────────────────────────────────────────────────┐
│ DELIVERY SEMANTICS │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. AT-MOST-ONCE (Fire and Forget) │
│ ══════════════════════════════════ │
│ Producer ────► Broker ────► Consumer │
│ (no ACK) (no ACK) │
│ │
│ • Message có thể mất │
│ • Fastest, simplest │
│ • Use case: Metrics, logs (loss acceptable) │
│ │
│ ───────────────────────────────────────────────────────────────── │
│ │
│ 2. AT-LEAST-ONCE (Guaranteed but may duplicate) │
│ ═════════════════════════════════════════════════ │
│ Producer ────► Broker ────► Consumer │
│ ◄──── ACK │
│ Consumer crashes before ACK? │
│ → Broker re-delivers │
│ → Consumer sees DUPLICATE │
│ │
│ • Message delivered at least once │
│ • Consumer MUST be idempotent │
│ • Most common choice │
│ │
│ ───────────────────────────────────────────────────────────────── │
│ │
│ 3. EXACTLY-ONCE (Holy Grail) │
│ ══════════════════════════════ │
│ • Extremely hard to achieve │
│ • Requires transactions across producer/broker/consumer │
│ • Kafka supports (with limitations) │
│ • High performance cost │
│ │
│ ⚠️ Real-world tip: Design for AT-LEAST-ONCE with IDEMPOTENT consumers │
│ │
└─────────────────────────────────────────────────────────────────────────┘3. Kafka: The Distributed Log
3.1 Kafka Architecture
TIP
🔧 Kỹ sư Raizo: Kafka không phải "message queue" theo nghĩa truyền thống. Nó là "distributed commit log". Sự khác biệt? Queue xóa message sau khi consume. Kafka GIỮ LẠI message theo retention policy. Bạn có thể replay từ bất kỳ điểm nào trong quá khứ.
┌─────────────────────────────────────────────────────────────────────────┐
│ KAFKA ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ TOPIC: "orders" │
│ ═══════════════ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ PARTITION 0 │ │
│ │ ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ │
│ │ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ → → │ │
│ │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘ │ │
│ │ ▲ │ │
│ │ Consumer A │ │
│ │ offset: 8 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ PARTITION 1 │ │
│ │ ┌────┬────┬────┬────┬────┬────┬────┐ │ │
│ │ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ → → │ │
│ │ └────┴────┴────┴────┴────┴────┴────┘ │ │
│ │ ▲ │ │
│ │ Consumer B │ │
│ │ offset: 5 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ PARTITION 2 │ │
│ │ ┌────┬────┬────┬────┬────┬────┬────┬────┐ │ │
│ │ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ → → │ │
│ │ └────┴────┴────┴────┴────┴────┴────┴────┘ │ │
│ │ ▲ │ │
│ │ Consumer C │ │
│ │ offset: 6 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ KEY CONCEPTS: │
│ • Partition = ordered, immutable sequence of messages │
│ • Offset = position of message in partition (like array index) │
│ • Consumer Group = set of consumers sharing partitions │
│ • Each partition → ONE consumer in group (parallelism) │
│ │
│ RETENTION: │
│ • Time-based: Keep 7 days (default) │
│ • Size-based: Keep last 1TB │
│ • Compaction: Keep only latest value per key │
│ │
└─────────────────────────────────────────────────────────────────────────┘3.2 Kafka Strengths
| Feature | Benefit |
|---|---|
| High Throughput | Millions of messages/second |
| Durability | Replicated across brokers |
| Scalability | Add partitions, add consumers |
| Replay | Re-process from any offset |
| Ordering | Guaranteed within partition |
| Retention | Keep messages for days/weeks |
3.3 Kafka Consumer Groups
┌─────────────────────────────────────────────────────────────────────────┐
│ CONSUMER GROUPS │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Topic "orders" (3 partitions) │
│ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ CONSUMER GROUP A │ │
│ │ (Order Processing) │ │
│ │ │ │
│ │ P0 ──────► Consumer A1 │ │
│ │ P1 ──────► Consumer A2 │ │
│ │ P2 ──────► Consumer A3 │ │
│ │ │ │
│ │ Each partition → Exactly ONE consumer │ │
│ │ Parallel processing: 3 consumers = 3x throughput │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ CONSUMER GROUP B │ │
│ │ (Analytics Pipeline) │ │
│ │ │ │
│ │ P0 ──────► Consumer B1 │ │
│ │ P1 ──────► │ │
│ │ P2 ──────► │ │
│ │ │ │
│ │ Single consumer handles ALL partitions │ │
│ │ Lower throughput but simpler │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ ⚠️ SAME MESSAGE → delivered to BOTH groups │
│ (Pub/Sub semantics between groups) │
│ │
│ ⚠️ Within a group, each partition assigned to ONE consumer │
│ (Competing consumers within group) │
│ │
└─────────────────────────────────────────────────────────────────────────┘4. RabbitMQ: The Smart Broker
4.1 RabbitMQ Architecture
┌─────────────────────────────────────────────────────────────────────────┐
│ RABBITMQ ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────────────┐ │
│ │ PRODUCER │───────────┐ │ QUEUES │ │
│ └─────────────┘ │ │ │ │
│ ▼ │ ┌───────────────┐ │ │
│ ┌─────────────┐ ┌─────────────┐ │ │ email_queue │──┼─►│
│ │ PRODUCER │───►│ EXCHANGE │───────────┤ └───────────────┘ │ │
│ └─────────────┘ │ │ │ │ │
│ │ (Router) │ │ ┌───────────────┐ │ │
│ ┌─────────────┐ │ │───────────┤ │ sms_queue │──┼─►│
│ │ PRODUCER │───►│ │ │ └───────────────┘ │ │
│ └─────────────┘ └─────────────┘ │ │ │
│ │ │ ┌───────────────┐ │ │
│ └──────────────────┤ │ push_queue │──┼─►│
│ │ └───────────────┘ │ │
│ └─────────────────────┘ │
│ │
│ EXCHANGE TYPES: │
│ ═══════════════ │
│ │
│ 1. DIRECT │
│ Route by exact routing key match │
│ Key = "email" → email_queue │
│ │
│ 2. FANOUT │
│ Broadcast to ALL bound queues │
│ (Ignores routing key) │
│ │
│ 3. TOPIC │
│ Pattern matching with wildcards │
│ "orders.*" matches "orders.created", "orders.shipped" │
│ "orders.#" matches "orders.asia.vietnam.created" │
│ │
│ 4. HEADERS │
│ Route by message headers (rarely used) │
│ │
└─────────────────────────────────────────────────────────────────────────┘4.2 RabbitMQ vs Kafka: Philosophy
┌─────────────────────────────────────────────────────────────────────────┐
│ SMART BROKER vs SMART CONSUMER │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ RABBITMQ: SMART BROKER │
│ ══════════════════════ │
│ │
│ Broker: │
│ • Routes messages (Exchanges) │
│ • Tracks what's delivered │
│ • Handles ACK/NACK │
│ • Deletes after consumption │
│ • Manages retries, DLQ │
│ │
│ Consumer: │
│ • Just process and ACK │
│ • Minimal logic │
│ │
│ Analogy: Post office sorts mail, delivers to your door │
│ │
│ ───────────────────────────────────────────────────────────────── │
│ │
│ KAFKA: DUMB BROKER, SMART CONSUMER │
│ ══════════════════════════════════ │
│ │
│ Broker: │
│ • Append to log │
│ • Serve reads │
│ • That's it! │
│ │
│ Consumer: │
│ • Track own offset │
│ • Decide what to re-read │
│ • Handle failures │
│ • Coordinate with consumer group │
│ │
│ Analogy: Library - books stay, you track what you've read │
│ │
└─────────────────────────────────────────────────────────────────────────┘5. Kafka vs RabbitMQ: Comparison Matrix
5.1 Feature Comparison
| Criteria | Kafka | RabbitMQ |
|---|---|---|
| Model | Distributed Log | Message Queue |
| Message Deletion | Retention-based | After ACK |
| Replay | ✅ Any offset | ❌ Once consumed, gone |
| Ordering | Per partition | Per queue |
| Routing | Topic-based | Exchange (flexible) |
| Throughput | Millions/sec | Thousands/sec |
| Latency | Higher (batching) | Lower |
| Complexity | Higher | Lower |
5.2 Use Case Matrix
| Use Case | Best Choice | Why |
|---|---|---|
| Event Sourcing | Kafka | Replay capability |
| Log Aggregation | Kafka | High throughput, retention |
| Stream Processing | Kafka | Kafka Streams, ksqlDB |
| Task Queue | RabbitMQ | Flexible routing, ACK |
| RPC-style | RabbitMQ | Request-reply pattern |
| Priority Queue | RabbitMQ | Native priority support |
| Multi-tenant routing | RabbitMQ | Exchange patterns |
| CDC (Change Data Capture) | Kafka | Debezium integration |
5.3 Decision Flowchart
6. Messaging Patterns
6.1 Pub/Sub Pattern
┌─────────────────────────────────────────────────────────────────────────┐
│ PUB/SUB PATTERN │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Publisher KHÔNG BIẾT ai là Subscriber │
│ Subscriber KHÔNG BIẾT ai là Publisher │
│ │
│ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Order │ │ TOPIC/EXCHANGE │ │
│ │ Service │────────►│ "order.created" │ │
│ │ │ │ │ │
│ └─────────────┘ └──────────┬──────────┘ │
│ │ │
│ ┌──────────────────────┼──────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Email Service │ │ Analytics │ │ Inventory │ │
│ │ │ │ Service │ │ Service │ │
│ │ "Send confirm" │ │ "Update stats" │ │ "Reserve stock" │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ Benefits: │
│ • Order Service chỉ publish, không quan tâm ai consume │
│ • Add new subscriber? NO CHANGES to publisher │
│ • Remove subscriber? NO IMPACT │
│ │
│ Challenges: │
│ • No response (fire-and-forget) │
│ • Hard to debug (distributed tracing needed) │
│ • Message ordering across subscribers │
│ │
└─────────────────────────────────────────────────────────────────────────┘6.2 Dead Letter Queue (DLQ)
WARNING
The Poison Pill Problem: What happens when a message CANNOT be processed no matter how many times you retry? Without DLQ, it blocks the queue forever.
┌─────────────────────────────────────────────────────────────────────────┐
│ DEAD LETTER QUEUE │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ SCENARIO: Malformed order message │
│ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ MAIN QUEUE │ │
│ │ │ │
│ │ ┌───┐ ┌───┐ ┌───┐ ┌───────────────┐ ┌───┐ │ │
│ │ │ M │ │ M │ │ M │ │ POISON PILL │ │ M │ ──────► │ │
│ │ │ 5 │ │ 4 │ │ 3 │ │ (Invalid JSON)│ │ 1 │ │ │
│ │ └───┘ └───┘ └───┘ └───────┬───────┘ └───┘ │ │
│ │ │ │ │
│ └────────────────────────────┼─────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────┐ │
│ │ CONSUMER │ │
│ │ │ │
│ │ Try 1: FAIL │ │
│ │ Try 2: FAIL │ │
│ │ Try 3: FAIL │ │
│ │ │ │
│ │ Max retries = 3 │ │
│ │ → Move to DLQ │ │
│ └───────────┬───────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ DEAD LETTER QUEUE │ │
│ │ │ │
│ │ ┌───────────────────────────────────────────────────────────┐ │ │
│ │ │ Original Message + Error Details + Retry Count + Timestamp│ │ │
│ │ └───────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ Options: │ │
│ │ 1. Human review & manual fix │ │
│ │ 2. Alert & monitoring │ │
│ │ 3. Automatic reprocessing with different logic │ │
│ │ 4. Archive for audit │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ ✅ Main queue unblocked, continues processing M1, M3, M4, M5 │
│ ✅ Poison pill isolated for investigation │
│ │
└─────────────────────────────────────────────────────────────────────────┘6.3 DLQ Best Practices
┌─────────────────────────────────────────────────────────────────────────┐
│ DLQ IMPLEMENTATION │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. ENRICH THE DEAD LETTER │
│ ══════════════════════════ │
│ { │
│ "original_message": { ... }, │
│ "error": { │
│ "type": "ValidationError", │
│ "message": "Invalid order_id format", │
│ "stack_trace": "..." │
│ }, │
│ "metadata": { │
│ "retry_count": 3, │
│ "first_attempt": "2024-01-15T10:00:00Z", │
│ "last_attempt": "2024-01-15T10:00:30Z", │
│ "original_queue": "orders.process", │
│ "consumer_id": "worker-pod-abc123" │
│ } │
│ } │
│ │
│ 2. MONITORING & ALERTING │
│ ═══════════════════════ │
│ • Alert if DLQ > X messages │
│ • Dashboard: DLQ depth, age of oldest message │
│ • Runbook: How to investigate, replay │
│ │
│ 3. RETRY STRATEGY │
│ ══════════════════ │
│ Immediate → Wait 1s → Wait 5s → Wait 30s → DLQ │
│ (Exponential backoff with max retries) │
│ │
└─────────────────────────────────────────────────────────────────────────┘7. Raizo's Production Advice
TIP
🔧 Kỹ sư Raizo - HPN Stack:
Penrift Cloud sử dụng BOTH Kafka và RabbitMQ:
- Kafka: User activity stream, CDC pipeline, event sourcing
- RabbitMQ: Background jobs, email queue, webhooks
Rule: Nếu cần replay hoặc high throughput → Kafka. Nếu cần flexible routing hoặc task queue → RabbitMQ.
7.1 Common Pitfalls
┌─────────────────────────────────────────────────────────────────────────┐
│ COMMON MESSAGING PITFALLS │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ❌ PITFALL 1: Not handling duplicates │
│ ══════════════════════════════════════ │
│ At-least-once = duplicates WILL happen │
│ Fix: Idempotent consumers (check if already processed) │
│ │
│ ❌ PITFALL 2: Unbounded queues │
│ ══════════════════════════════ │
│ Producer faster than consumer = queue grows forever = OOM │
│ Fix: Backpressure, rate limiting, alerting on queue depth │
│ │
│ ❌ PITFALL 3: No DLQ │
│ ═══════════════════ │
│ Bad message blocks entire queue │
│ Fix: Always have DLQ + monitoring │
│ │
│ ❌ PITFALL 4: Large messages │
│ ══════════════════════════════ │
│ Sending 10MB files through message queue │
│ Fix: Store in S3, send reference in message │
│ │
│ ❌ PITFALL 5: Ignoring ordering requirements │
│ ══════════════════════════════════════════ │
│ Multiple partitions/consumers = out of order processing │
│ Fix: Partition by order_id if sequence matters │
│ │
└─────────────────────────────────────────────────────────────────────────┘8. Scenario Quiz
Câu hỏi 1: E-commerce Events
HPN Store cần xử lý events: Order Created → Payment Processed → Inventory Updated → Email Sent. Mỗi event có thể có hàng ngàn xử lý đồng thời. Cần replay khả năng đối với Payment team để debug.
Bạn chọn Kafka hay RabbitMQ? Tại sao?
👁️ Xem đáp án
Đáp án: Kafka
Lý do:
- Replay capability: Payment team cần xem lại events để debug → Kafka giữ messages
- High throughput: Hàng ngàn events/second → Kafka optimized cho scale
- Event sourcing: Chuỗi events tự nhiên phù hợp với Kafka's log model
- Multiple consumers: Analytics, Fraud detection, etc. có thể consume cùng event
Implementation:
yaml
Topic: order-events
Partitions: 10 (partition by order_id for ordering)
Retention: 7 days
Consumer Groups:
- order-processing
- analytics-pipeline
- fraud-detectionCâu hỏi 2: Background Jobs
HPN Blog cần gửi email newsletter cho 100K subscribers. Email gửi không cần nhanh (có thể chờ vài giờ). Nếu gửi thất bại, cần retry với exponential backoff. Priority queue cho VIP users.
Bạn chọn Kafka hay RabbitMQ? Tại sao?
👁️ Xem đáp án
Đáp án: RabbitMQ
Lý do:
- Priority queue: RabbitMQ native support, Kafka không có
- Flexible retry: RabbitMQ + DLQ + TTL = easy exponential backoff
- Task queue model: "Process once and delete" phù hợp với email
- No replay needed: Email đã gửi thì không cần gửi lại
Implementation:
python
# RabbitMQ với priority queue
channel.queue_declare(
queue='email_queue',
arguments={
'x-max-priority': 10,
'x-dead-letter-exchange': 'email_dlx',
'x-message-ttl': 86400000 # 24h
}
)
# VIP users get priority 10
channel.basic_publish(
exchange='',
routing_key='email_queue',
body=message,
properties=pika.BasicProperties(priority=10)
)9. Tiếp theo
Xin chúc mừng! Bạn đã hoàn thành Phase 2: Distributed Systems Theory! 🎉
Quay lại System Design Universe để explore các modules khác:
Hoặc tiếp tục với Case Studies để áp dụng kiến thức: