Họ đang đo gì
Bạn có hiểu vì sao exactly-once không thể có trong GIAO HÀNG, và bạn đạt được nó bằng cách nào trong XỬ LÝ.
Trả lời ngắn~30 giây
At-most-once: gửi rồi quên, có thể mất. At-least-once: gửi lại tới khi có xác nhận, có thể trùng. Exactly-once trong giao hàng là không thể — vì bên gửi không bao giờ phân biệt được “bên nhận chưa nhận” với “bên nhận đã nhận nhưng xác nhận bị mất”. Thứ đạt được là exactly-once PROCESSING: at-least-once cộng với consumer idempotent, hoặc cộng với việc ghi kết quả và commit offset trong cùng một transaction.
Giải thích sâu
Cách Kafka làm exactly-once đáng hiểu vì nó cho thấy điều kiện thật sự. Producer idempotent gán số thứ tự cho mỗi bản ghi nên broker loại được bản trùng do retry. Rồi transaction cho phép ghi vào topic đầu ra VÀ commit offset của topic đầu vào trong cùng một giao dịch — nên nếu consumer chết, cả hai cùng quay lại. Nhưng điều này chỉ đúng TRONG Kafka: ngay khi kết quả đi ra ngoài, ví dụ ghi vào database khác, bảo đảm đó biến mất.
Vì vậy trong thực tế, câu trả lời gần như luôn là at-least-once cộng consumer idempotent. Cách làm consumer idempotent thì tuỳ bài toán: lưu id message đã xử lý vào bảng có UNIQUE, hoặc dùng upsert với khoá tự nhiên, hoặc thiết kế thao tác sao cho lặp lại không đổi trạng thái (SET status = 'paid' thì lặp bao nhiêu lần cũng vậy, còn balance = balance - 10 thì không).
Ở mức senior, cần nói thêm về poison message: một bản ghi luôn làm consumer lỗi sẽ được retry vô hạn và chặn cả partition phía sau nó. Cần dead letter queue với ngưỡng số lần thử, và quan trọng không kém là quy trình cho những gì vào DLQ — một DLQ không ai xem là một cách im lặng làm mất dữ liệu, chỉ khác là mất chậm hơn.
Câu hỏi tiếp theo họ sẽ hỏi
?Thứ tự message có được đảm bảo không?
Trong Kafka chỉ trong PHẠM VI một partition. Muốn các sự kiện của cùng một thực thể đến đúng thứ tự thì phải dùng id thực thể làm khoá partition. Đây là ràng buộc quan trọng khi chọn khoá: nó vừa quyết định thứ tự vừa quyết định độ cân bằng tải.
?Commit offset trước hay sau khi xử lý?
Sau, nếu bạn muốn at-least-once (mất kết nối thì xử lý lại). Trước, nếu bạn chấp nhận mất để đổi lấy at-most-once. enable.auto.commit=true commit theo thời gian nên nó nằm ở khoảng giữa và cho bảo đảm khó suy luận nhất — đó là lý do phần lớn hệ nghiêm túc tắt nó đi.
Trả lời thế này là mất điểm
- Hứa exactly-once mà không nêu điều kiện. Người phỏng vấn senior sẽ hỏi ngay “kể cả khi ghi ra database ngoài?”
- Không có kế hoạch cho poison message. Nó sẽ xảy ra, và nó chặn cả partition.