RabbitMQ vs Kafka: chọn cái nào cho bài toán nào

4 câu hỏi~25 phútTừ khóa: smart broker, dumb broker, task queue, event log, routing, replay, throughput, ordering, partition, sharding

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

3. Giải pháp: hiểu bản chất của từng bên

Tiêu chíRabbitMQKafka
Mô hìnhMessage broker, queue (smart broker, simple consumer)Distributed append-only log (simple broker, smart consumer)
Đơn vị cốt lõiExchange → binding → queueTopic → partition → offset
Sau khi xử lýACK → message bị xóaGiữ theo retention, consumer chỉ dời offset
RoutingRất linh hoạt: direct, fanout, topic, headers (bài 8.2)Chỉ theo topic + key → partition
Nhiều bên cùng nhậnMỗi bên một queue bind vào exchangeMỗi bên một consumer group
Scale consumerThê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
ReplayKhông tự nhiên (Streams của RabbitMQ có hỗ trợ)Có sẵn: reset offset
ThroughputRất tốt, hàng chục nghìn msg/s mỗi nodeRất cao, hàng trăm nghìn tới triệu record/s cụm
Tính năng messagePriority, TTL, DLX, delay (plugin), per-message ACK/rejectRetention, compaction, transactions, Kafka Streams/Connect
Độ bền HAQuorum queue (Raft) (bài 8.4)Replication, ISR, acks=all (bài 8.7)
Retry/lỗiNack, 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ánChọnLý do
a) OrderCreated cho nhiều service, có thể thêm subscriberKafkaEvent log, subscriber mới đọc lịch sử, thứ tự theo orderId
b) Gửi email, retry có delayRabbitMQTask queue, DLX + TTL cho retry delay, ACK từng message
c) Xuất PDF, VIP ưu tiênRabbitMQPriority queue, competing consumers, job dài không chặn job khác
d) Clickstream 50k/s, phân tích lạiKafkaThroughput, 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

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
KafkaCó, là khái niệm cốt lõiChia topic thành nhiều log: đơn vị lưu trữ, song song, thứ tự
RabbitMQKhông có sẵn kiểu KafkaMuốn chia tải thì nhiều queue / consistent hash exchange / super stream
RedisGọi là shardingRedis Cluster chia key space thành 16384 hash slot, mỗi node giữ một số slot
DatabaseCó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
RedisKey-value, TTL, data types, hash slot/sharding, replica, thực thi lệnh chủ yếu single-threadedDữ liệu nóng nằm đâu, đọc nhanh thế nào?
KafkaTopic → partition → offset, consumer group, broker, replica/ISRChuyện gì đã xảy ra, ai đọc tới đâu?
RabbitMQExchange → binding/routing key → queue → consumer → ACK, DLX, quorum queueViệ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

Tổng kết chương 8: Messaging

BàiChủ đềÝ chính
8.1Vì sao cần message queue, idempotencyTách rời service, chịu tải đột biến; consumer phải chịu được message trùng
8.2Exchange và routingDirect, fanout, topic exchange; routing key và binding
8.3ACK và publisher confirmManual ACK phía consumer, confirm phía producer để không mất message
8.4Quorum queueQueue replicate bằng Raft cho HA
8.5Retry và DLXNack, TTL, dead letter exchange, retry có delay
8.6Kafka partitioned logTopic, partition, offset, retention, key → partition, thứ tự trong partition, replay
8.7Kafka replicationBroker, leader/follower, ISR, acks=all + min.insync.replicas, KRaft
8.8Consumer group và offsetmin(consumer, partition), rebalance, commit sau xử lý, lag
8.9Delivery semanticsAt-most/at-least/exactly-once, idempotent producer, transactions, Outbox, DLT
8.10RabbitMQ vs KafkaTask 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.