Skip to main content

Kafka vs RabbitMQ

Cập nhật: 2026-07-20

Mục lục


1. Kiến thức nền: Producer, Consumer, Broker là gì?

Nếu chưa từng đụng tới message queue bao giờ, mấy khái niệm ở các phần sau (broker, producer, consumer, topic...) sẽ hơi trừu tượng. Trước khi vào so sánh Kafka với RabbitMQ, hãy làm rõ vài khái niệm nền chung cho mọi hệ thống message queue, không riêng gì 2 cái này.

Trong bất kỳ hệ thống nào dùng message queue, luôn có 3 vai trò:

  • Producer: bên gửi message — thường là 1 service trong hệ thống muốn thông báo hoặc giao việc cho service khác, mà không cần đợi service kia xử lý xong ngay.
  • Consumer: bên nhận và xử lý message — lấy message ra khỏi hàng đợi, xử lý logic nghiệp vụ tương ứng.
  • Broker: phần mềm trung gian đứng giữa producer và consumer — nhận message từ producer, lưu tạm, rồi chuyển cho consumer đúng lúc. RabbitMQ và Kafka bản thân chúng chính là 2 kiểu broker khác nhau.

💡 Hình dung như thế này: message queue giống hộp thư thoại. Gọi điện trực tiếp (giao tiếp đồng bộ) đòi hỏi cả 2 bên phải rảnh cùng lúc — bên gọi phải chờ trên đường dây. Để lại lời nhắn trong hộp thư thoại (giao tiếp bất đồng bộ qua queue) thì người gọi cứ để lại lời nhắn rồi đi làm việc khác, người nhận nghe lại khi nào rảnh cũng được — 2 bên không cần "gặp mặt" cùng lúc.

Có 2 mô hình phổ biến khi nhiều consumer cùng tồn tại:

  • Point-to-point: 1 message chỉ có đúng 1 consumer nhận và xử lý — dù có nhiều consumer đang lắng nghe, chỉ 1 trong số đó "thắng" và lấy được message đó. Đây là mô hình mặc định của RabbitMQ queue.
  • Publish-subscribe (pub-sub): 1 message được nhiều consumer độc lập cùng nhận và xử lý riêng, không ai tranh ai. Đây là mô hình Kafka dùng khi nhiều consumer group cùng đọc chung 1 topic.

Nắm được 3 vai trò và 2 mô hình này rồi, phần so sánh RabbitMQ/Kafka bên dưới sẽ dễ theo hơn nhiều — vì suy cho cùng, cả 2 chỉ là 2 cách hiện thực hóa khác nhau của đúng bộ khái niệm này.


2. Vì sao cần Message Queue?

Giả sử order service của bạn cần nói chuyện với inventory service. Cách đơn giản nhất là gọi trực tiếp — gửi HTTP request, đợi response, rồi tiếp tục. Cách này hoạt động tốt, cho tới khi inventory service chậm, down, hoặc bị dồn traffic quá tải. Lúc đó order service bị kẹt lại chờ, timeout, hoặc phải drop request vì không còn chỗ nào để đặt chúng.

Message queue như Kafka và RabbitMQ giải quyết vấn đề này bằng cách thêm 1 lớp buffer giữa các service. Thay vì gọi trực tiếp inventory service, order service chỉ cần đưa message vào queue rồi return ngay lập tức. Inventory service sau đó tự lấy message ra khi sẵn sàng để xử lý.

Nếu inventory service chậm, message sẽ tích lại trong queue. Nếu có 1 đợt tăng đột biến đơn hàng — ví dụ trong 1 đợt flash sale — queue sẽ hấp thụ hết lượng traffic đó, rồi để các service phía sau xử lý theo đúng tốc độ mà chúng chịu được.

Kafka và RabbitMQ đều mang lại khả năng decoupling này — có producer, consumer, và 1 broker hoặc message queue ở giữa. Nhưng cách chúng thực sự hoạt động bên dưới lại khác nhau hoàn toàn, và đó chính là điều cần quyết định khi chọn dùng cái nào cho dự án.

Direct Call vs Message QueueDirect call (fragile)Order ServiceInventory Serviceslow / down / overloadedHTTP request — blocking, waitsVia Message Queue (buffered)Order ServiceQueue / Logabsorbs traffic spikesInventory Servicedrop & returnpull khi rảnh

3. RabbitMQ: Traditional Message Broker

RabbitMQ là 1 message broker truyền thống, theo 1 mental model mà hầu hết developer thấy khá trực quan nếu từng làm việc với cấu trúc dữ liệu kiểu queue.

Producer gửi message tới broker. Broker nhìn vào các routing rule đã được cấu hình để xác định message đó thuộc queue nào, rồi consumer sẽ pull message ra từ queue đó. Khi consumer xác nhận (acknowledge) đã xử lý xong, RabbitMQ xóa message đó.

💡 Hình dung như thế này: RabbitMQ giống dịch vụ chuyển phát nhanh — người gửi đưa thư cho bưu tá, bưu tá dựa vào địa chỉ (routing rule) để phân vào đúng hòm thư, người nhận lấy thư ra và ký nhận. Xong việc, lá thư đó coi như hoàn thành nhiệm vụ, không ai giữ lại bản sao nữa.

Broker đảm nhiệm rất nhiều việc: route message tới đúng queue, theo dõi message nào đã được deliver, và tự động retry với các lần deliver thất bại. Khi 1 message thất bại lặp lại nhiều lần, RabbitMQ tự động chuyển nó vào dead letter queue để có thể debug sau. Với vai trò engineer, chỉ cần cấu hình các rule này, còn broker sẽ tự thực thi chúng.

⚠️ Lưu ý: Kafka không có sẵn cơ chế này. Nếu cần dead letter handling trong Kafka, phải tự xây dựng nó.

RabbitMQ Message FlowProducerBrokerrouting rules,delivery tracking,retriesQueueConsumerDead Letter Queue(sau nhiều lần fail)routepullack → broker deletes message

Từ góc nhìn của consumer, mọi thứ rất đơn giản: kết nối/subscribe vào 1 queue, message xuất hiện, xử lý, rồi gửi lại acknowledgement. Toàn bộ độ phức tạp của việc xác định message đến từ đâu, cần đi đâu — đó là việc của broker, không phải của consumer.

Mô hình này khớp rất tốt với các workload dạng task-oriented: gửi email, xử lý thanh toán, resize ảnh — có 1 đơn vị công việc cần thực hiện, đưa nó vào queue, và có thứ gì đó nhặt lấy rồi thực thi. Đơn giản, dễ đoán, đúng thứ hầu hết dev cần.


4. Kafka: Distributed Append-Only Log

Kafka hoạt động theo cách khác hẳn. Thay vì là 1 message broker route message vào các queue rồi xóa chúng sau khi được consume, Kafka thực chất là 1 distributed append-only log.

Khi producer gửi message, Kafka append nó vào 1 topic. Message đó không biến mất khi có ai đó đọc nó — nó vẫn nằm nguyên trong log. Tùy theo cấu hình retention, nó có thể tồn tại vài giờ, vài ngày, vài tuần, hoặc thậm chí vô thời hạn.

💡 Hình dung như thế này: Kafka giống 1 cuốn sổ cái công khai — ai ghi gì vào sổ thì dòng đó nằm nguyên trong sổ mãi mãi, không bị xóa. Mỗi người đọc tự lật tới đúng trang mình đang dừng (offset), muốn lật lại trang cũ để đọc lại lúc nào cũng được, và nhiều người có thể cùng đọc chung 1 cuốn sổ mà không ảnh hưởng tới nhau.

Consumer sau đó đọc từ log này, nhưng chính consumer chịu trách nhiệm theo dõi vị trí đọc của mình. Kafka gọi vị trí này là offset. Ví dụ, khi consumer đọc tới message số 500, nó tự nhớ rằng mình đang ở vị trí 500. Nếu consumer bị crash hoặc restart, nó tra lại vị trí đã dừng và tiếp tục đọc từ đó. Nếu cần đọc lại 1 message từ 1 giờ trước, chỉ cần rewind về đúng offset đó — hoàn toàn khả thi.

Điều này thay đổi cả mô hình.

Kafka: Append-Only LogProducerappend01234 (mới nhất)Topic (log)Consumer Group Ađang ở offset 1Consumer Group Bđang ở offset 4 — đọc độc lập, không liên quan tới Group AMessage không bị xóa sau khi đọc — mỗi consumer group tự nhớoffset của mình, có thể rewind về đọc lại bất kỳ lúc nào.

5. Khác biệt cốt lõi: Smart Broker vs Smart Consumer

RabbitMQ là smart broker với simple consumer — nó xử lý routing, theo dõi delivery, quản lý retry. Kafka là simple broker với smart consumer — nó lưu message theo thứ tự, còn consumer tự quyết định đọc gì và đọc khi nào. Kafka vẫn track offset theo consumer group, nhưng logic điều khiển chính vẫn nằm ở phía consumer.

Smart Broker vs Smart ConsumerRabbitMQBroker (smart)routing · delivery trackingretries · dead letter queuetự động xử lý hếtConsumer (simple)chỉ việc xử lý & ackKafkaBroker (simple)chỉ append vào logConsumer (smart)tự track offset của mìnhtự quyết định đọc gì, khi nàocó thể rewind, replay

Lợi ích của cách làm này là message trong Kafka trở nên durable và replayable. Nhiều consumer group có thể đọc cùng 1 stream 1 cách độc lập với nhau — team analytics có thể xử lý cùng những event mà hệ thống real-time notification đang xử lý. 1 service mới ra đời 6 tháng sau vẫn có thể đọc lại toàn bộ lịch sử từ ngày đầu tiên để backfill dữ liệu nếu cần.

💡 Nhấn mạnh lại sự khác biệt này: RabbitMQ là message broker — message chỉ chảy qua nó. Kafka là log — message sống trong nó. Trong RabbitMQ, khi 1 message đã được consume, nó biến mất. Trong Kafka, message vẫn tồn tại, và bất kỳ số lượng consumer nào cũng có thể đọc chúng ở bất kỳ thời điểm nào, từ bất kỳ điểm nào trong lịch sử.

Sự khác biệt duy nhất này chi phối gần như mọi trade-off khác giữa 2 hệ thống. Vì chúng giải quyết những bài toán khác nhau, nhiều team thực tế dùng cả 2: Kafka làm durable event stream mà nhiều hệ thống cùng đọc, RabbitMQ làm task queue xử lý công việc do các event đó trigger ra.


6. Khác biệt kỹ thuật cụ thể

Ordering guarantees

Cả 2 hệ thống đều giữ được thứ tự, nhưng theo cách khác nhau. Queue trong RabbitMQ có thứ tự chặt chẽ — message ra theo đúng thứ tự đã vào. Nếu chỉ có 1 consumer duy nhất, được đảm bảo thứ tự hoàn hảo. Nhưng với nhiều consumer cùng pull từ 1 queue song song, mỗi consumer xử lý song song với nhau — phải đánh đổi thứ tự đó để lấy throughput.

Kafka thì chia mỗi topic thành nhiều partition. Thứ tự chỉ được đảm bảo trong 1 partition, không đảm bảo giữa các partition với nhau. Message đi vào partition nào được kiểm soát thông qua partition key — ví dụ mọi order của khách hàng 12345 sẽ vào cùng 1 partition và được xử lý theo đúng thứ tự, còn order của khách hàng 67890 có thể vào 1 partition khác. Vậy là thứ tự của từng entity vẫn được giữ nguyên, nhưng không có thứ tự toàn cục.

Ordering theo Partition KeyProducerkey = customer_idPartition 0 — customer 12345order đúng thứ tự trong partition nàyPartition 1 — customer 67890Không có thứ tự toàn cụcCùng 1 partition key luôn vào cùng 1 partition → thứ tự per-entity được giữ,nhưng giữa các partition với nhau thì không so được ai trước ai sau.

Trade-off ở đây: RabbitMQ cho thứ tự toàn cục nhưng với 1 consumer duy nhất. Kafka cho thứ tự theo từng entity nhưng đi kèm khả năng chạy song song. Chọn dựa trên việc thực sự cần cái nào.

Throughput & Latency

Quyết định trên kéo theo hệ quả về throughput và latency. RabbitMQ xử lý khoảng 4.000–10.000 message/giây (tùy kích thước message và hardware), với latency khoảng 1–5ms cho workload thấp. Lý do là broker tự động đẩy (push) message tới consumer, nhưng đồng thời broker cũng phải làm rất nhiều việc — theo dõi trạng thái delivery, quản lý acknowledgement, xử lý quyết định routing — tất cả overhead đó tính trên từng message cộng dồn lại, và khi tăng lên thì throughput giảm xuống.

Kafka xử lý hơn 1 triệu message/giây — khoảng gấp 100 lần. Latency ở baseline cao hơn, thường 5–50ms, vì consumer pull message theo batch thay vì nhận ngay lập tức. Broker phải làm ít việc hơn hẳn trên mỗi message — chỉ append vào 1 log tuần tự, rồi để consumer tự theo dõi vị trí của mình. Dưới tải nặng, sự đơn giản này thực sự phát huy tác dụng — vì tất cả những gì broker cần làm là append vào log, nên latency có thể giữ ổn định ngay cả khi volume tăng lên.

Delivery guarantees

Chuyện gì xảy ra khi 1 consumer xử lý message thất bại? Có 2 lựa chọn: hoặc mất message đó, hoặc deliver lại cho 1 consumer khác và chấp nhận rủi ro xử lý trùng lặp.

  • At-most-once: có thể mất message. Broker gửi 1 lần và không retry. Rất nhanh, nhưng nếu có sự cố, message mất vĩnh viễn.
  • At-least-once: có thể bị trùng. Broker sẽ retry cho tới khi nhận được acknowledgement từ consumer. Cách này không mất dữ liệu, nhưng consumer có thể thấy cùng 1 message 2 lần và xử lý nó 2 lần.

Cả RabbitMQ và Kafka đều hỗ trợ at-least-once — đây là thứ hầu hết ứng dụng cần và là tiêu chuẩn ngành. Kafka còn hỗ trợ exactly-once — chén thánh của delivery guarantee, nơi mỗi message được truyền và xử lý đúng 1 lần duy nhất. Nghe hấp dẫn đúng không? Có 1 cái bẫy.

⚠️ Lưu ý: exactly-once bị giới hạn hơn nhiều so với tên gọi của nó. Nó chỉ hoạt động khi cả input và output đều là Kafka topic, nằm trong cùng 1 Kafka cluster, dưới Kafka transactions. Ngay khi cần ghi vào database, gọi 1 API bên ngoài, hoặc vượt ra khỏi ranh giới cluster, lại quay về at-least-once. Trong thực tế, hầu hết ứng dụng vẫn cần consumer idempotent. Đừng chọn Kafka chỉ vì nghe nói nó hỗ trợ exactly-once — thực tế phức tạp hơn nhiều, và với phần lớn use case, khả năng cao nó không thực sự áp dụng được.

Độ phức tạp vận hành

RabbitMQ dễ vận hành hơn nhiều — nó là 1 single binary, clustering đơn giản, có sẵn management UI. Với 1 team nhỏ chỉ chạy vài queue, nó rất dễ tiếp cận.

Kafka thì khó hơn. Trước đây cần Zookeeper như 1 coordination service riêng; các phiên bản mới hơn dùng Raft (KRaft mode, production-ready từ Kafka 3.3.1, và là chế độ duy nhất kể từ Kafka 4.0 khi Zookeeper bị gỡ bỏ hoàn toàn), loại bỏ nhu cầu cần Zookeeper — nhưng vẫn phải tự quản lý partition rebalancing, broker failure, cấu hình topic, và coordination giữa các consumer group. Có nhiều thứ phải học hơn, và cũng nhiều thứ có thể sai hơn.

Các managed service làm thay đổi bài toán này — Confluent Cloud, Amazon MSK, Azure Event Hubs xử lý giúp phần lớn độ phức tạp của Kafka. Nếu chọn Kafka, nên cân nhắc nghiêm túc dùng managed service, trừ khi team đã có sẵn chuyên môn hạ tầng chuyên trách.

Bốn khác biệt trên — ordering, throughput, delivery, vận hành — mới là thứ thực sự quyết định nên chọn ai, chứ không phải cái tên nào nghe "mạnh" hơn.


7. Nên dùng RabbitMQ hay Kafka?

Nắm được cả mô hình lẫn khác biệt kỹ thuật rồi — giờ tới câu hỏi thực dụng nhất: bạn nên chọn cái nào?

Chọn RabbitMQ nếu:

  • Cần task queue và background job — gửi email, xử lý thanh toán, resize ảnh. Công việc đi vào, được thực hiện xong, rồi message biến mất.
  • Cần smart routing — broker quyết định worker nào nhận message nào dựa trên nội dung.
  • Cần low latency ở scale vừa phải — dưới 5ms khi không đẩy tới hàng triệu message.
  • Cần vận hành đơn giản — dễ setup, dễ suy luận hơn.

💡 Ví dụ thực tế: Instagram dùng RabbitMQ để xử lý ảnh upload — khi đăng 1 bức ảnh, việc resize và filter được thực hiện qua background worker, được pull ra từ RabbitMQ queue. Reddit cũng dùng nó để build comment thread và tính điểm karma. Đây đều là những pattern task queue kinh điển.

Chọn Kafka nếu:

  • Cần nhiều hệ thống cùng đọc chung 1 luồng event — analytics, fraud detection, billing, audit logging, tất cả cùng consume 1 stream 1 cách độc lập.
  • Cần khả năng replay — xử lý lại dữ liệu lịch sử để debug hoặc rebuild state.
  • Có scale khổng lồ — hàng triệu event/giây với yêu cầu latency ổn định.
  • Cần durable event history — 1 bản ghi vĩnh viễn của mọi thứ từng xảy ra.

💡 Ví dụ thực tế: Netflix xử lý hàng petabyte dữ liệu mỗi ngày qua Kafka cho recommendation và billing. Uber dùng nó cho real-time pricing và fraud detection trên hàng triệu chuyến xe. LinkedIn — nơi phát minh ra Kafka — vẫn dùng nó để vận hành feed và messaging.

Nếu có 1 use case rõ ràng, gói gọn, khớp với mô hình RabbitMQ — như task queue hay background job — nên chọn RabbitMQ vì sự đơn giản của nó. Với mọi trường hợp còn lại, có thể cần nghiêng về Kafka, và cân nhắc tự host hay dùng managed service. Hoặc, tất nhiên, có thể dùng cả 2: Kafka làm event backbone, RabbitMQ xử lý các background job do những event đó trigger ra.


8. Thử nghiệm nhanh với Docker

Đọc lý thuyết xong, cách hiểu nhanh nhất vẫn là tự tay gửi/nhận thử 1 message. Cả RabbitMQ và Kafka đều có Docker image chính thức, chạy thử trên máy chỉ mất vài phút, không cần cài đặt gì phức tạp.

Thử RabbitMQ

docker run -d --hostname my-rabbit --name some-rabbit \
-p 5672:5672 -p 15672:15672 \
rabbitmq:3-management

Port 5672 là nơi ứng dụng thật sự kết nối để gửi/nhận message (giao thức AMQP), còn 15672 là management UI dạng web. Mở trình duyệt vào http://localhost:15672, đăng nhập bằng tài khoản mặc định guest / guest, sẽ thấy dashboard trực quan để tạo queue, xem message, và theo dõi hoạt động broker theo thời gian thực.

Thử Kafka

docker run -d --name broker apache/kafka:latest
docker exec --workdir /opt/kafka/bin/ -it broker sh

Sau khi vào được shell bên trong container, chạy lần lượt 3 lệnh sau để tạo topic, gửi, rồi đọc lại message:

# Tạo 1 topic tên test-topic
./kafka-topics.sh --bootstrap-server localhost:9092 --create --topic test-topic

# Gửi message — gõ "hello", Enter, gõ "world", Enter, rồi Ctrl+C để thoát
./kafka-console-producer.sh --bootstrap-server localhost:9092 --topic test-topic

# Đọc lại toàn bộ message đã gửi, từ đầu topic (--from-beginning)
./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test-topic --from-beginning

Lệnh consumer cuối sẽ in ra đúng 2 dòng đã gõ ở bước producer: helloworld — chạy lại lệnh này bao nhiêu lần cũng ra lại đúng 2 dòng đó, vì message không bị xóa sau khi đọc (đúng như bản chất append-only log đã nói ở phần 4).

Dọn dẹp sau khi thử xong:

docker rm -f some-rabbit broker

9. Thuật ngữ dùng trong bài

Thuật ngữGiải thích
BrokerPhần mềm trung gian nhận, lưu tạm, và chuyển message giữa producer và consumer.
ProducerThành phần gửi message vào hệ thống.
ConsumerThành phần nhận và xử lý message.
Topic"Kênh" chứa message trong Kafka — tương đương khái niệm queue trong RabbitMQ, nhưng message không bị xóa sau khi đọc.
Partition1 topic Kafka được chia thành nhiều partition; thứ tự message chỉ được đảm bảo trong cùng 1 partition.
OffsetVị trí (số thứ tự) của 1 message trong 1 partition Kafka — consumer tự lưu offset để biết mình đã đọc tới đâu.
Consumer Group1 nhóm consumer trong Kafka cùng chia nhau đọc 1 topic; mỗi consumer group giữ vị trí offset riêng, độc lập với group khác.
Acknowledge (ack)Tín hiệu consumer gửi lại broker xác nhận đã xử lý xong 1 message.
Dead Letter Queue (DLQ)Hàng đợi riêng chứa các message bị xử lý thất bại nhiều lần liên tiếp, để debug sau — tính năng có sẵn trong RabbitMQ.
Idempotent (consumer)Consumer được thiết kế sao cho xử lý cùng 1 message nhiều lần vẫn cho kết quả đúng như xử lý 1 lần — cần thiết khi dùng at-least-once delivery.

Nguồn tham khảo

Nguồn gốc: Video "Kafka vs RabbitMQ" — kênh Hello Interview.

Đính chính/cập nhật (fact-check):