Bách Khoa Software
Trang chủ › Giải Pháp Phần Mềm

So sánh message queue: RabbitMQ, Kafka và Redis Pub/Sub

Ban biên tập Bách Khoa Software · · Cập nhật
So sánh message queue: RabbitMQ, Kafka và Redis Pub/Sub

RabbitMQ là message broker truyền thống, mạnh về định tuyến linh hoạt và hàng đợi tác vụ; Kafka là nền tảng log sự kiện phân tán, lưu tin nhắn bền vững để nhiều bên đọc lại và xử lý luồng dữ liệu lớn; Redis Pub/Sub là kênh phát tin tức thời, rất nhanh nhưng không lưu tin nhắn, ai không đang nghe thì mất. Ba công cụ này không thay thế hoàn toàn cho nhau, nên câu hỏi đúng là "bài toán của mình cần đảm bảo gì" chứ không phải "cái nào nhanh nhất".

Vì sao hệ thống cần message queue

Khi một service gọi trực tiếp service khác qua HTTP, hai bên gắn chặt với nhau: bên nhận chậm hoặc chết thì bên gọi cũng bị ảnh hưởng. Đặt một hàng đợi ở giữa mang lại ba lợi ích:

  • Tách rời: bên gửi không cần biết ai xử lý, khi nào xử lý.
  • Đệm tải: lúc cao điểm, tin nhắn xếp hàng chờ thay vì làm sập service phía sau.
  • Mở rộng: thêm consumer để xử lý song song khi lượng việc tăng.

Ví dụ quen thuộc: khi khách đặt hàng, service đơn hàng chỉ cần ghi đơn và phát sự kiện "đơn đã tạo". Gửi email, trừ kho, cộng điểm thưởng, ghi log phân tích là việc của các consumer khác.

RabbitMQ: broker định tuyến linh hoạt

RabbitMQ triển khai giao thức AMQP 0-9-1 (và hỗ trợ thêm MQTT, STOMP qua plugin). Producer gửi tin nhắn vào exchange, exchange định tuyến tới một hoặc nhiều queue dựa trên loại exchange (direct, topic, fanout, headers) và routing key. Consumer lấy tin từ queue, xử lý xong thì gửi ack; tin nhắn được xóa khỏi queue sau khi ack.

Điểm mạnh:

  • Định tuyến phong phú, dễ mô tả quy tắc như "mọi sự kiện thanh toán của khu vực miền Nam".
  • Hỗ trợ ưu tiên tin nhắn, TTL, dead letter exchange để gom tin xử lý lỗi.
  • Phù hợp cho hàng đợi tác vụ (task queue): mỗi việc chỉ cần đúng một worker làm.
  • Có Quorum Queue dựa trên thuật toán Raft cho độ bền cao trong cụm, và Streams cho nhu cầu đọc lại kiểu log.

Hạn chế: mô hình mặc định xóa tin sau khi tiêu thụ nên không hợp khi nhiều hệ thống cần đọc lại lịch sử sự kiện; khi queue tồn đọng quá nhiều, hiệu năng và bộ nhớ cần được theo dõi kỹ.

Kafka: log sự kiện phân tán

Kafka tổ chức dữ liệu thành topic, mỗi topic chia thành nhiều partition. Mỗi partition là một log chỉ ghi nối thêm (append-only); tin nhắn được giữ theo thời gian hoặc dung lượng cấu hình, không bị xóa khi đã đọc. Consumer tự quản lý vị trí đọc (offset), nên có thể đọc lại từ đầu, và nhiều consumer group khác nhau đọc cùng một topic độc lập với nhau.

Điểm mạnh:

  • Thông lượng rất cao nhờ ghi tuần tự xuống đĩa và gom lô.
  • Lưu lịch sử sự kiện, phục vụ event sourcing, đồng bộ dữ liệu sang data lake, xử lý luồng với Kafka Streams hay Flink.
  • Đảm bảo thứ tự trong cùng một partition; chọn khóa partition (ví dụ mã khách hàng) để mọi sự kiện của một đối tượng đi đúng thứ tự.
  • Hệ sinh thái Kafka Connect để kéo/đẩy dữ liệu từ database, hệ thống lưu trữ.

Hạn chế: vận hành phức tạp hơn (từ các bản gần đây Kafka dùng chế độ KRaft, không còn cần ZooKeeper, nhưng vẫn phải hiểu partition, replication, rebalancing); không có định tuyến linh hoạt hay hàng đợi ưu tiên như RabbitMQ; số partition giới hạn mức song song của một consumer group.

Nếu đội dự định đổ dữ liệu sự kiện về kho phân tích, bài xây dựng Data Lake cho phân tích lớn mô tả cách Kafka thường đóng vai trò đường ống nạp dữ liệu.

Redis Pub/Sub và Redis Streams

Redis Pub/Sub cho phép client đăng ký kênh và nhận tin ngay khi có người publish. Không có lưu trữ: nếu subscriber mất kết nối vài giây, các tin trong khoảng đó biến mất. Vì vậy nó hợp cho thông báo tức thời mà mất một vài tin cũng không sao, như cập nhật trạng thái "đang gõ" trong chat, đẩy thông báo tới các instance WebSocket, hoặc báo các node xóa cache.

Nếu đã dùng Redis và cần độ bền hơn, Redis Streams (có từ Redis 5.0) là lựa chọn trung gian: tin nhắn được lưu, có consumer group và cơ chế ack, khá giống một Kafka thu nhỏ trong bộ nhớ. Dù vậy, dung lượng bị giới hạn bởi RAM và các tính năng phân tán không phong phú bằng Kafka.

Bảng so sánh nhanh

Tiêu chíRabbitMQKafkaRedis Pub/Sub
Mô hìnhBroker, queue, exchangeLog phân tán, topic, partitionKênh phát tức thời
Lưu tin sau khi đọcKhông (trừ Streams)Có, theo thời hạn cấu hìnhKhông lưu
Đọc lại lịch sửHạn chếCó, theo offsetKhông
Đảm bảo giao nhậnAt-least-once với ackAt-least-once, hỗ trợ exactly-once trong luồng KafkaAt-most-once
Thứ tựTheo queue, có thể lệch khi nhiều consumerTheo partitionTheo kết nối
Định tuyếnRất linh hoạtĐơn giản theo topic và khóaTheo tên kênh, pattern
Độ phức tạp vận hànhTrung bìnhCaoThấp

Chọn theo tình huống cụ thể

Xử lý tác vụ nền

Gửi email, tạo PDF hóa đơn, resize ảnh: mỗi việc cần đúng một worker làm, có retry và dead letter khi lỗi. RabbitMQ (hoặc các thư viện queue dựa trên Redis như Sidekiq, BullMQ, Celery) là lựa chọn gọn nhẹ.

Phát sự kiện nghiệp vụ cho nhiều hệ thống

Sự kiện "đơn hàng đã thanh toán" cần đến kho, kế toán, CRM, phân tích, và sau này có thể thêm hệ thống mới muốn đọc lại từ đầu. Kafka hợp hơn vì lưu lịch sử và cho mỗi hệ thống một consumer group riêng. Với dữ liệu nhạy cảm như giao dịch, hãy kết hợp thiết kế idempotent như mô tả trong bài xây dựng hệ thống thanh toán an toàn.

Thông báo thời gian thực giữa các instance

Chat, dashboard trực tiếp, đồng bộ cache giữa nhiều server: Redis Pub/Sub là đủ và đơn giản nhất, nhất là khi hạ tầng đã có Redis.

Thu thập log và số liệu

Khối lượng lớn, cần bộ đệm bền giữa nguồn và hệ thống lưu trữ: Kafka thường được đặt giữa agent thu log và kho lưu trữ, như trong kiến trúc logging tập trung cho microservices.

Nguyên tắc thiết kế dùng chung cho mọi broker

  • Consumer phải idempotent: với at-least-once, cùng một tin có thể đến hai lần. Lưu mã tin đã xử lý hoặc thiết kế thao tác để chạy lại không gây sai.
  • Định nghĩa schema tin nhắn: dùng JSON Schema, Avro hoặc Protobuf, có quy tắc đổi phiên bản tương thích ngược.
  • Xử lý tin lỗi: giới hạn số lần retry, chuyển tin hỏng sang hàng đợi riêng để kiểm tra, tránh vòng lặp vô hạn.
  • Giám sát độ trễ hàng đợi: số tin tồn đọng hoặc consumer lag là chỉ báo sớm nhất cho thấy hệ thống đang không theo kịp.
  • Outbox pattern: ghi sự kiện vào bảng outbox trong cùng transaction với dữ liệu nghiệp vụ, rồi một tiến trình riêng đẩy lên broker, tránh trường hợp ghi database thành công mà phát sự kiện thất bại.

Lời khuyên cuối: hãy bắt đầu với công cụ đội đã quen và đủ cho nhu cầu hiện tại. Chuyển từ Redis sang RabbitMQ hay Kafka khi có lý do rõ ràng (cần lưu lịch sử, cần thông lượng lớn) sẽ nhẹ nhàng hơn nhiều so với vận hành một cụm Kafka chỉ để gửi vài trăm email mỗi ngày.

Câu hỏi thường gặp

Kafka có dùng làm hàng đợi tác vụ được không?

Được, nhưng không tự nhiên bằng RabbitMQ. Mức song song bị giới hạn bởi số partition và một tin xử lý chậm có thể chặn các tin sau trong cùng partition. Từ các bản Kafka mới có tính năng share group hướng tới nhu cầu này, nên kiểm tra phiên bản đang dùng.

Redis Pub/Sub có mất tin nhắn không?

Có. Subscriber đang ngắt kết nối sẽ không nhận được tin phát ra trong lúc đó. Nếu cần độ bền, hãy dùng Redis Streams hoặc một broker có lưu trữ.

RabbitMQ và Kafka có dùng chung trong một hệ thống không?

Có, khá phổ biến. Kafka làm xương sống sự kiện nghiệp vụ và đường ống dữ liệu, còn RabbitMQ hoặc queue dựa trên Redis lo các tác vụ nền cần retry, ưu tiên và định tuyến chi tiết.

Có dịch vụ cloud thay cho tự vận hành không?

Có. Các nhà cung cấp cloud lớn đều có dịch vụ Kafka được quản lý và dịch vụ queue riêng như Amazon SQS, Google Pub/Sub, Azure Service Bus. Chúng giảm công vận hành nhưng cần tính chi phí theo lưu lượng và khả năng phụ thuộc nhà cung cấp.

Bài liên quan