Gửi Thông Điệp Exactly Once Với Kafka: Hệ Thống Phân Tán Hiện Đại
Trong thế giới của các hệ thống phân tán, khái niệm về việc gửi thông điệp "exactly once" cũng giống như một hố đen – bắt đầu chỉ là một ý niệm. Chúng ta không thể xác định sự tồn tại của nó cho đến khi có những chứng minh rõ ràng. Năm 2019, bức ảnh đầu tiên về hố đen đã được công bố, nhưng đến năm 2021 mới có những hình ảnh rõ ràng hơn.
Tương tự, trong ngữ cảnh phát triển phần mềm, việc đạt được mục tiêu gửi thông điệp "exactly once" với Kafka đã trở thành một vấn đề quan trọng. Bài viết này sẽ cung cấp cái nhìn sâu sắc về Kafka và khái niệm Exactly Once Semantics (EOS).
Các Chế Độ Gửi Thông Điệp Trong Kafka
Kafka hỗ trợ hai chế độ chính là at least once (ít nhất một lần) và at most once (tối đa một lần).
- At Least Once: Chế độ này có thể dẫn đến tình trạng lặp lại thông điệp (duplicate message) khi hệ thống gặp sự cố.
- At Most Once: Chế độ này dễ gây ra mất thông điệp nếu có lỗi xảy ra trước khi thông điệp được gửi thành công.
Vậy nguyên nhân gì dẫn đến các vấn đề này và Kafka cùng các nhà phát triển đã giải quyết nó ra sao?
Nguyên Nhân Các Vấn Đề Gửi Thông Điệp
Nguyên nhân chính đến từ các mode ACK trên Kafka producer và cách mà consumer xử lý việc commit thông điệp.
Producer
Khi thông điệp được gửi từ producer đến Kafka thông qua Replication leader, producer sẽ chờ nhận ACK từ leader để xác nhận thông điệp đã được append thành công. Tuy nhiên, nếu gặp lỗi và không nhận được phản hồi, producer sẽ thử gửi lại thông điệp, dẫn đến những rắc rối không mong muốn trong hệ thống.
-
ACK = 1 hoặc ACK = 0: Có thể dẫn đến mất thông điệp. Khi đặt mode ACK = 1, chỉ cần leader nhận được thông điệp và báo ACK mà không chờ sync với các node khác, nếu xảy ra lỗi, thông điệp có thể bị mất. ACK = 0 thậm chí còn tệ hơn khi producer không quan tâm đến việc thông điệp đã được append hay chưa.
-
ACK = ALL: Đây là chế độ có khả năng tạo ra thông điệp lặp lại. Khi producer gửi thông điệp và chờ ACK từ các nodes, nhưng nếu trường hợp bất ngờ xảy ra, producer sẽ thực hiện lại việc gửi, gây ra trùng lặp thông điệp.
Giải Quyết Vấn Đề Từ Kafka
Kafka đã giới thiệu khái niệm Idempotent Producer để xử lý các vấn đề trên.
Các Thành Phần Của Idempotent Producer
- Producer ID (PID): Mỗi producer có một ID duy nhất.
- Sequence Number (SN): Mỗi thông điệp được gửi đến một partition nhất định sẽ có một số thứ tự duy nhất. Kafka sẽ kiểm tra SN của mỗi producer để đảm bảo rằng không có thông điệp nào bị gửi lại trùng lặp.
Kể từ version 3.0, chế độ Idempotent Producer đã được thiết lập làm mặc định, giúp cho dev không cần phải cấu hình thủ công.
Consumer Và Cách Xử Lý Thông Điệp
Consumer cũng có hai khái niệm để xử lý thông điệp:
- At Most Once: Consumer commit thông điệp ngay sau khi nhận và có thể bị mất thông điệp nếu không xử lý kịp thời.
- At Least Once: Consumer xử lý thông điệp trước khi commit, nhưng có thể gây ra trường hợp xử lý trùng lặp nếu xảy ra lỗi trong quá trình commit.
Giải Pháp Cho Consumer
Dao động về việc commit thông điệp, dev nên sử dụng cách tiếp cận at least once kết hợp với việc sử dụng một định danh (transaction ID hoặc message ID) duy nhất cho mỗi thông điệp. Bằng cách này, nếu một thông điệp đã được xử lý rồi thì có thể đơn giản là bỏ qua những thông điệp trùng lặp.
Ngoài ra, Kafka còn hỗ trợ cơ chế transactional cho phép bọc cả quá trình xử lý và commit trong một transaction, giúp đảm bảo tính nhất quán của dữ liệu.
Kết Luận
Qua bài viết này, hy vọng các bạn sẽ có cái nhìn rõ ràng hơn về việc triển khai hệ thống với Kafka để đạt được tính năng gửi thông điệp "exactly once". Chúc các bạn thành công trong việc xây dựng hệ thống phân tán với Kafka!
source: viblo