Nền tảng
Distributed log: topic, partition, offset.
Message key và thứ tự: thứ tự được bảo đảm tới đâu.
Kafka là log có vị trí đọc: đọc không xóa record, nhiều group đọc độc lập, replay được. RabbitMQ là router và queue: exchange quyết định queue nào nhận, ack xong message rời queue. Hai mô hình trả lời khác nhau cho ba câu hỏi: đọc xong message còn không, ai quyết định message đi đâu, và “đã gửi thành công” nghĩa là gì.
| Nhu cầu | Chọn | Vì sao |
|---|---|---|
| Replay, nhiều consumer độc lập đọc cùng dữ liệu | Kafka | Log giữ theo retention, mỗi group có offset riêng |
| Thứ tự theo key ở throughput lớn | Kafka | Thứ tự trong partition, key chọn partition |
| Event streaming, CDC, stream processing | Kafka | Hệ sinh thái Connect, Streams, compaction |
| Work queue, mỗi job một worker, ack từng job | RabbitMQ (quorum queue) | Ack theo message, DLX, prefetch |
| Định tuyến linh hoạt theo pattern (topic, headers) | RabbitMQ | Exchange và binding |
| Retry có backoff, dead-letter theo từng message | RabbitMQ | DLX, TTL, x-delivery-limit |
| Cần cả queue-like lẫn log trong một hệ | Cân nhắc: Kafka Share Groups (4.2) hoặc RabbitMQ streams | Xem Share Groups và queue types |
Quy tắc ngón tay cái: cần replay hoặc stream thì Kafka; cần chia việc và định tuyến thì RabbitMQ. Cả hai đều at-least-once ở tầng ứng dụng, nên consumer idempotent luôn cần.
Nền tảng
Distributed log: topic, partition, offset.
Message key và thứ tự: thứ tự được bảo đảm tới đâu.
Độ bền và tiến độ
Replication, ISR, acks: khi nào write được xác nhận.
Commit offset: khoảng hở giữa side effect và offset.
Vận hành
Share Groups: nhiều worker trên một partition.
Consumer lag: đo, alert và chẩn đoán.
Retry topic và DLQ: message lỗi không chặn partition.
Chống ghi trùng
Idempotent producer: dedupe retry cùng batch.
Transactions và exactly-once: ranh giới dừng ở Kafka.
| Bài | Trả lời câu hỏi |
|---|---|
| Exchange và binding | Message đến queue nào? Publish không lỗi có nghĩa đã tới queue không? |
| Ack, prefetch, publisher confirms | Ba ranh giới xác nhận khác nhau thế nào? consumer_timeout là gì? |
| Dead-letter, TTL, retry có đếm | Job lỗi đi đâu, retry bao nhiêu lần, poison message dừng ở đâu? |
| Classic, quorum, stream | Chọn queue type nào cho từng luồng? |
Broker quản lý message và trạng thái giao nhận, không biết side effect của service đã thành công hay chưa. Ghi database xong rồi crash trước khi xác nhận thì message được xử lý lại; xác nhận trước khi ghi thì mất việc.
Xử lý trùng
Consumer idempotent: inbox table, unique key, một transaction. Dùng cho cả Kafka và RabbitMQ.
Dual write
Transactional outbox: ghi state và ý định phát event trong một DB transaction. Chống mất event, vẫn có thể trùng.
Bối cảnh rộng hơn: tám ngộ nhận về hệ phân tán.
| Tình huống | Đọc theo thứ tự |
|---|---|
| Mới với Kafka | Distributed log → Message key → Consumer group |
| Mới với RabbitMQ | Exchange → Ack và prefetch → DLX và TTL |
| Event bị xử lý hai lần | Consumer idempotent → Commit offset |
| Producer báo thành công nhưng mất dữ liệu | Replication, ISR, acks |
| Thêm consumer mà throughput không tăng | Share Groups |
| Cần replay nhưng dữ liệu đã mất | Retention và compaction |
| Lag tăng, không biết vì sao | Consumer lag → Consumer group |
| Một message lỗi chặn cả partition Kafka | Retry topic và DLQ → Consumer idempotent |
| Queue RabbitMQ đầy, job lặp mãi | Dead-letter và retry có đếm |
| DB commit nhưng event không tới broker | Transactional outbox |
| Producer đổi cấu trúc event và một consumer cũ bị hỏng | Event schema evolution |