Ba mức đảm bảo giao message:
- At-most-once: mỗi message được xử lý tối đa một lần, có thể mất. Consumer commit offset trước khi xử lý; xử lý lỗi thì message coi như đã tiêu thụ. Chỉ hợp với dữ liệu chấp nhận mất (metric, log truy vết).
- At-least-once: message không bao giờ mất nhưng có thể lặp. Consumer xử lý xong mới commit offset; nếu chết trước khi commit, message được giao lại. Đây là mặc định thực tế của Kafka và RabbitMQ.
- Exactly-once: mỗi message có tác động đúng một lần. Kafka làm được trong phạm vi Kafka đọc → xử lý → ghi lại Kafka nhờ idempotent producer + transaction, nhưng khi consumer ghi ra hệ thống bên ngoài (DB, gọi API bên thứ ba) thì broker không kiểm soát được.
Chọn: dùng at-least-once + consumer idempotent. Đó là câu trả lời được chờ đợi: bạn chấp nhận bị giao lặp và thiết kế xử lý sao cho chạy lại nhiều lần vẫn ra cùng kết quả (dedup key, UPSERT, kiểm tra trạng thái trước khi ghi). Cách này rẻ và bền hơn nhiều so với đuổi theo exactly-once toàn hệ thống.