Message queue: RabbitMQ, Kafka và khi nào bạn thật sự cần chúng

  • author-image

    Nguyễn Đình Cường

  • blog-tag
  • blog-comment 0 comment
  • created-date 09 Nov, 2026
blog-thumbnail

Khi hệ thống lớn dần, việc các thành phần gọi trực tiếp nhau bắt đầu gây khó: một dịch vụ chậm kéo theo cả chuỗi, tải tăng đột biến làm sập mọi thứ. Message queue chen một lớp đệm ở giữa để các thành phần giao tiếp lỏng lẻo hơn. Bài này giải thích ý tưởng và so sánh hai cái tên phổ biến.

Ý tưởng cốt lõi

Thay vì A gọi B và chờ kết quả, A gửi một thông điệp vào hàng đợi rồi đi làm việc khác. B (người tiêu thụ) lấy thông điệp ra xử lý khi sẵn sàng. Ba vai trò chính:

  • Producer: bên gửi thông điệp.
  • Broker: hệ thống trung gian lưu và phân phối thông điệp.
  • Consumer: bên nhận và xử lý.

Lợi ích: tách rời (decoupling), chịu đựng được tải đột biến nhờ hàng đợi làm bộ đệm, cho phép thử lại khi xử lý lỗi, và mở rộng bằng cách thêm consumer.

RabbitMQ: người điều phối thông điệp thông minh

RabbitMQ là message broker theo mô hình truyền thống. Producer gửi thông điệp tới một exchange, exchange định tuyến vào các queue theo quy tắc, consumer lấy từ queue. Khi consumer xác nhận (ack) đã xử lý xong, thông điệp bị xóa khỏi queue.

# Python với pikaimport pikaconn = pika.BlockingConnection(pika.ConnectionParameters("localhost"))ch = conn.channel()ch.queue_declare(queue="emails", durable=True)# Producerch.basic_publish(exchange="", routing_key="emails", body="gửi mail cho user 42",                 properties=pika.BasicProperties(delivery_mode=2))  # lưu bền# Consumerdef handle(ch, method, props, body):    print("xử lý:", body)    ch.basic_ack(delivery_tag=method.delivery_tag)ch.basic_consume(queue="emails", on_message_callback=handle)ch.start_consuming()

RabbitMQ mạnh ở định tuyến linh hoạt (direct, topic, fanout), hàng đợi tác vụ, độ trễ thấp và các tính năng như thử lại, hàng đợi thư chết (dead-letter queue) cho thông điệp xử lý lỗi nhiều lần.

Kafka: nhật ký sự kiện phân tán

Kafka có triết lý khác. Nó là một nhật ký (log) phân tán, chỉ ghi thêm. Thông điệp được ghi vào các topic chia thành nhiều partition và được giữ lại theo thời gian cấu hình, không bị xóa khi đã đọc. Mỗi consumer tự nhớ vị trí (offset) mình đã đọc tới, nên nhiều nhóm consumer có thể đọc cùng một luồng sự kiện độc lập, và bạn có thể đọc lại từ đầu khi cần.

Kafka phù hợp với lưu lượng cực lớn, luồng sự kiện, xử lý dữ liệu theo thời gian thực, thu thập log và kiến trúc hướng sự kiện. Đổi lại, vận hành phức tạp hơn và mô hình tư duy khác.

So sánh nhanh

Tiêu chíRabbitMQKafka
Mô hìnhHàng đợi, broker định tuyếnNhật ký sự kiện phân tán
Thông điệp sau khi xử lýBị xóaĐược giữ theo thời gian lưu trữ
Đọc lạiKhông phải thế mạnhTự nhiên (đặt lại offset)
Điểm mạnhTác vụ nền, định tuyến linh hoạtThông lượng lớn, streaming
Độ phức tạp vận hànhVừa phảiCao hơn

Những vấn đề phải tính tới

  • Ít nhất một lần: thông điệp có thể bị giao nhiều hơn một lần, nên consumer cần idempotent (xử lý lặp không gây hại).
  • Thứ tự: chỉ được đảm bảo trong phạm vi nhất định, ví dụ trong một partition của Kafka.
  • Thông điệp lỗi: cần chiến lược thử lại và hàng đợi thư chết.
  • Giám sát độ trễ: theo dõi số thông điệp tồn đọng để biết consumer có theo kịp không.

Bạn đã thật sự cần chưa?

Đây là câu hỏi quan trọng nhất. Nhiều ứng dụng chỉ cần hàng đợi tác vụ đơn giản dựa trên Redis hoặc database, như hệ thống queue có sẵn trong Laravel, Celery hay Sidekiq. Thêm RabbitMQ hay Kafka nghĩa là thêm một hệ thống phải vận hành, giám sát và nâng cấp. Hãy bắt đầu đơn giản, và chỉ chuyển sang broker chuyên dụng khi có nhu cầu rõ ràng: nhiều dịch vụ cần giao tiếp qua sự kiện, lưu lượng rất lớn, hoặc cần phát lại sự kiện.

Ví dụ tình huống thực tế

Hãy hình dung một cửa hàng trực tuyến. Khi khách đặt hàng, hệ thống cần gửi email xác nhận, trừ tồn kho, thông báo cho kho vận và cập nhật thống kê. Nếu mọi việc nằm trong một request đồng bộ, chỉ cần dịch vụ email chậm là khách phải chờ lâu. Với hàng đợi, dịch vụ đơn hàng chỉ lưu đơn rồi phát đi sự kiện "đơn hàng đã tạo"; các dịch vụ khác tự đăng ký nhận và xử lý theo nhịp của mình. Nếu dịch vụ email tạm thời hỏng, thông điệp vẫn nằm trong hàng đợi và được gửi sau khi hồi phục, không mất đơn nào. Đây chính là giá trị của giao tiếp bất đồng bộ: sự cố cục bộ không lan thành sự cố toàn hệ thống.

Kết luận

Message queue giúp hệ thống bền hơn và dễ mở rộng, nhưng đi kèm chi phí phức tạp. Hiểu khác biệt giữa hàng đợi tác vụ kiểu RabbitMQ và nhật ký sự kiện kiểu Kafka giúp bạn chọn đúng công cụ khi thật sự cần.

Muốn học bài bản và có lộ trình rõ ràng? Bạn có thể xem các khóa học trên codebem.com.

author_photo
Nguyễn Đình Cường

0 comment