RabbitMQ vs Kafka: chọn cái nào cho bài toán nào
Tiếp đi: so sánh RabbitMQ và Kafka. Khi nào chọn cái nào?
Câu này gần như chắc chắn gặp khi phỏng vấn. Đừng trả lời "Kafka nhanh hơn". Hãy trả lời theo mô hình dữ liệu: RabbitMQ hỏi "ai sẽ xử lý việc này?", Kafka hỏi "chuyện gì đã xảy ra?".
1. Bài toán: shop-app có nhiều kiểu message
a) OrderCreated → inventory, notification, analytics, fraud (thêm sau)
b) Gửi email xác nhận: một job, gửi một lần, retry có delay
c) Xuất hóa đơn PDF: job nặng, đơn VIP được ưu tiên
d) Clickstream người dùng: 50.000 event/giây, lưu 30 ngày để phân tích lại
e) Gọi "tính phí ship" và chờ kết quả (request/reply)
2. Vấn đề: một công cụ cho tất cả thường gượng
- Dùng RabbitMQ cho (d): queue phình to, message bị xóa sau ACK nên không phân tích lại được.
- Dùng Kafka cho (c): không có priority, không có delay từng message; một job chậm chặn cả partition.
- Dùng Kafka cho (e): làm được nhưng vụng; REST/gRPC hoặc RabbitMQ RPC tự nhiên hơn.
3. Giải pháp: hiểu bản chất của từng bên
| Tiêu chí | RabbitMQ | Kafka |
|---|---|---|
| Mô hình | Message broker, queue (smart broker, simple consumer) | Distributed append-only log (simple broker, smart consumer) |
| Đơn vị cốt lõi | Exchange → binding → queue | Topic → partition → offset |
| Sau khi xử lý | ACK → message bị xóa | Giữ theo retention, consumer chỉ dời offset |
| Routing | Rất linh hoạt: direct, fanout, topic, headers (bài 8.2) | Chỉ theo topic + key → partition |
| Nhiều bên cùng nhận | Mỗi bên một queue bind vào exchange | Mỗi bên một consumer group |
| Scale consumer | Thêm consumer vào queue (competing consumers) | Bị giới hạn bởi số partition |
| Thứ tự | Theo queue; mất khi nhiều consumer/requeue | Đảm bảo trong partition, theo key |
| Replay | Không tự nhiên (Streams của RabbitMQ có hỗ trợ) | Có sẵn: reset offset |
| Throughput | Rất tốt, hàng chục nghìn msg/s mỗi node | Rất cao, hàng trăm nghìn tới triệu record/s cụm |
| Tính năng message | Priority, TTL, DLX, delay (plugin), per-message ACK/reject | Retention, compaction, transactions, Kafka Streams/Connect |
| Độ bền HA | Quorum queue (Raft) (bài 8.4) | Replication, ISR, acks=all (bài 8.7) |
| Retry/lỗi | Nack, DLX, TTL queue (bài 8.5) | Retry topic, DLT (bài 8.9) |
4. Code: cùng event, hai cách publish trong Spring
RabbitMQ (bài 8.2):
rabbitTemplate.convertAndSend("order.exchange", "order.created", event);
// routing key quyết định queue nào nhận
Kafka (bài 8.6):
kafkaTemplate.send("orders", event.orderId(), event);
// key quyết định partition; group quyết định ai nhận
Dùng cả hai trong shop-app là chuyện bình thường:
spring:
kafka:
bootstrap-servers: ${KAFKA_BOOTSTRAP}
rabbitmq:
host: ${RABBIT_HOST}
username: ${RABBIT_USER}
password: ${RABBIT_PASSWORD}
@KafkaListener(topics = "orders", groupId = "notification-service")
public void onOrder(OrderEvent event) {
if ("ORDER_CREATED".equals(event.type())) {
// chuyển "sự kiện" thành "công việc" có retry/delay riêng
rabbitTemplate.convertAndSend("email.exchange", "email.confirm",
new SendEmailJob(event.eventId(), event.orderId()));
}
}
5. Cách hoạt động: hai mô hình
RabbitMQ: "Ai sẽ XỬ LÝ việc này?" Kafka: "Chuyện gì ĐÃ XẢY RA?"
Producer Producer
│ │ key=orderId
▼ ▼
Exchange ──binding──▶ Queue A ─▶ C1,C2 Topic orders
└─binding──▶ Queue B ─▶ C3 P0 [0][1][2][3] ...
P1 [0][1][2] ...
ACK → message xóa ▲ ▲
group A offset group B offset
(record vẫn còn, có thể replay)
6. Quyết định cho từng bài toán shop-app
| Bài toán | Chọn | Lý do |
|---|---|---|
| a) OrderCreated cho nhiều service, có thể thêm subscriber | Kafka | Event log, subscriber mới đọc lịch sử, thứ tự theo orderId |
| b) Gửi email, retry có delay | RabbitMQ | Task queue, DLX + TTL cho retry delay, ACK từng message |
| c) Xuất PDF, VIP ưu tiên | RabbitMQ | Priority queue, competing consumers, job dài không chặn job khác |
| d) Clickstream 50k/s, phân tích lại | Kafka | Throughput, retention 30 ngày, replay, Kafka Connect sang data lake |
| e) Tính phí ship, chờ kết quả | REST/gRPC (hoặc RabbitMQ RPC) | Request/reply đồng bộ, không cần log |
7. Khi nào nên dùng / không nên dùng
- RabbitMQ: task/job queue, routing phức tạp, priority, delay, request/reply, lưu lượng vừa, team nhỏ.
- Kafka: event-driven giữa nhiều service, event sourcing/CDC, stream processing, replay, throughput lớn.
- Không nên: chọn Kafka chỉ vì "nghe xịn" cho vài trăm job/ngày; chi phí vận hành cluster và thiết kế partition không đáng.
Trong 3 công cụ Redis, RabbitMQ, Kafka, cái nào có partition? Mình thấy trong database cũng có partition.
Đúng, chữ "partition" xuất hiện ở nhiều nơi nhưng ý nghĩa khác nhau một chút:
| Công nghệ | Partition? | Ý nghĩa |
|---|---|---|
| Kafka | Có, là khái niệm cốt lõi | Chia topic thành nhiều log: đơn vị lưu trữ, song song, thứ tự |
| RabbitMQ | Không có sẵn kiểu Kafka | Muốn chia tải thì nhiều queue / consistent hash exchange / super stream |
| Redis | Gọi là sharding | Redis Cluster chia key space thành 16384 hash slot, mỗi node giữ một số slot |
| Database | Có | Chia một bảng lớn theo range/list/hash (ví dụ theo tháng) để query và bảo trì nhanh hơn; sharding là chia sang nhiều DB server |
Ý tưởng chung: chia dữ liệu để phân phối. Nhưng Kafka partition còn gánh thêm hai vai: đơn vị song song cho consumer group và phạm vi thứ tự. Redis hash slot và DB sharding chủ yếu trả lời "dữ liệu này nằm ở node nào?".
Bài 7.4 mình đã tóm tắt Redis, Kafka, RabbitMQ mỗi cái có khái niệm gì. Giờ gộp lại thành một bảng so sánh "cái gì chia tải, cái gì giữ thứ tự" được không?
Được. Gộp lại theo câu hỏi "chia tải bằng gì, giữ thứ tự ở đâu":
| Công nghệ | Concept nên nhớ | Câu hỏi nó trả lời |
|---|---|---|
| Redis | Key-value, TTL, data types, hash slot/sharding, replica, thực thi lệnh chủ yếu single-threaded | Dữ liệu nóng nằm đâu, đọc nhanh thế nào? |
| Kafka | Topic → partition → offset, consumer group, broker, replica/ISR | Chuyện gì đã xảy ra, ai đọc tới đâu? |
| RabbitMQ | Exchange → binding/routing key → queue → consumer → ACK, DLX, quorum queue | Việc này giao cho ai xử lý? |
Lưu ý: Redis cũng có Pub/Sub và Streams, nhưng trong shop-app ta dùng Redis cho cache/lock, còn messaging giao cho RabbitMQ và Kafka.
Phỏng vấn hỏi "Khi nào chọn Kafka, khi nào chọn RabbitMQ?" thì trả lời sao?
Q1. Khác biệt cốt lõi giữa RabbitMQ và Kafka?
🇻🇳 Tiếng Việt:
RabbitMQ là message broker hướng task: producer gửi vào exchange, exchange route vào queue, consumer ACK thì message bị xóa. Kafka là distributed log hướng event: record được append vào partition, giữ theo retention, mỗi consumer group tự quản lý offset nên có thể replay. RabbitMQ mạnh về routing linh hoạt; Kafka mạnh về throughput, lưu trữ và thứ tự theo key.
🇬🇧 English:
RabbitMQ is a task-oriented message broker: producers publish to an exchange, the exchange routes to queues, and a message is removed once the consumer acknowledges it. Kafka is an event-oriented distributed log: records are appended to partitions and kept by retention, and each consumer group tracks its own offsets, so replay is possible. RabbitMQ shines at flexible routing; Kafka shines at throughput, storage and per-key ordering.
Q2. Trong dự án, em chọn thế nào?
🇻🇳 Tiếng Việt:
Trong shop-app, event đơn hàng đi qua Kafka với key là orderId, vì nhiều service cần đọc, cần giữ thứ tự theo đơn và có thể replay khi analytics sửa bug. Còn job gửi email và xuất hóa đơn đi qua RabbitMQ vì cần retry có delay bằng DLX, priority và ACK từng message. Hai công cụ bổ sung cho nhau, không loại trừ nhau.
🇬🇧 English:
In our shop app, order events go through Kafka keyed by orderId, because many services consume them, ordering per order matters, and we can replay when analytics fixes a bug. Email and invoice jobs go through RabbitMQ because we need delayed retries with DLX, priorities and per-message acknowledgements. The two tools complement each other rather than compete.
Q3. Cả hai đều đảm bảo exactly-once?
🇻🇳 Tiếng Việt:
Thực tế cả hai đều cho at-least-once khi cấu hình đúng: publisher confirm và manual ACK ở RabbitMQ, acks=all và commit sau xử lý ở Kafka. Kafka có exactly-once nhưng chỉ trong phạm vi Kafka. Nên dù chọn cái nào, consumer có side effect vẫn phải idempotent.
🇬🇧 English:
In practice both give at-least-once when configured correctly: publisher confirms and manual acks in RabbitMQ, acks=all and commit-after-processing in Kafka. Kafka offers exactly-once, but only within Kafka. So whichever we choose, consumers with side effects must be idempotent.
Cách nhớ ngắn gọn
- RabbitMQ = "ai làm việc này?" → exchange, queue, ACK xóa.
- Kafka = "chuyện gì đã xảy ra?" → topic, partition, offset, replay.
- Routing/priority/delay → RabbitMQ. Throughput/replay/thứ tự theo key → Kafka.
- Cả hai: at-least-once + idempotent consumer.
Tổng kết chương 8: Messaging
| Bài | Chủ đề | Ý chính |
|---|---|---|
| 8.1 | Vì sao cần message queue, idempotency | Tách rời service, chịu tải đột biến; consumer phải chịu được message trùng |
| 8.2 | Exchange và routing | Direct, fanout, topic exchange; routing key và binding |
| 8.3 | ACK và publisher confirm | Manual ACK phía consumer, confirm phía producer để không mất message |
| 8.4 | Quorum queue | Queue replicate bằng Raft cho HA |
| 8.5 | Retry và DLX | Nack, TTL, dead letter exchange, retry có delay |
| 8.6 | Kafka partitioned log | Topic, partition, offset, retention, key → partition, thứ tự trong partition, replay |
| 8.7 | Kafka replication | Broker, leader/follower, ISR, acks=all + min.insync.replicas, KRaft |
| 8.8 | Consumer group và offset | min(consumer, partition), rebalance, commit sau xử lý, lag |
| 8.9 | Delivery semantics | At-most/at-least/exactly-once, idempotent producer, transactions, Outbox, DLT |
| 8.10 | RabbitMQ vs Kafka | Task queue vs event log; chọn theo bài toán |
Tự kiểm tra
Service fraud mới cần đọc event đơn hàng 7 ngày qua. RabbitMQ hay Kafka làm được tự nhiên?
Kafka: tạo consumer group mới với auto-offset-reset: earliest, đọc từ đầu retention. RabbitMQ queue mới chỉ nhận message từ lúc bind.
Job xuất PDF cần ưu tiên đơn VIP. Vì sao Kafka không hợp?
Kafka không có priority; record đọc theo thứ tự offset, job chậm còn chặn record sau trong partition. RabbitMQ có priority queue và competing consumers.
RabbitMQ "nhiều queue bind vào một exchange" tương đương gì trong Kafka?
Nhiều consumer group cùng đọc một topic: mỗi group (mỗi queue) nhận đủ message.
Kafka partition khác Redis hash slot ở điểm nào?
Cả hai đều chia dữ liệu, nhưng Kafka partition còn là đơn vị song song cho consumer group và phạm vi đảm bảo thứ tự. Hash slot chỉ quyết định key nằm ở node nào.
Chọn Kafka rồi có bỏ được idempotent consumer không?
Không. Exactly-once của Kafka không bao gồm DB/email/HTTP; rebalance, crash trước commit, replay vẫn gây xử lý lại.