Bốn bài đầu tiên, chắc hẳn các bạn đã có những hiểu biết nhất định về kiến trúc và các thành phần trong 1 cụm Kafka như Brokers, Producer, Consumer, Partitions…
Bài hôm nay, mình sẽ chi tiết hơn về 2 thành phần cực kì quan trọng để tương tác với dữ liệu của cụm, đó là Producer và Consumer.
Kafka Producer Design
Như đã trình bày ở phần trước, Producer chịu trách nhiệm đẩy dữ liệu từ nguồn bên ngoài vào cụm. Một đơn vị dữ liệu được gửi đi là ProducerRecord. Bao gồm
- Topic (bắt buộc): Tên topic nhận dữ liệu
- Partition (optional): Partition trong topic
- Key (optional): Key của bản ghi
- Value (bắt buộc): Dữ liệu của bản ghi
Trên mô hình, có thể thấy rằng trước khi được đẩy vào topic, 1 bản ghi sẽ trải qua 2 quá trình xử lý:
- Serializer: Là việc chuyển dữ liệu trên bộ nhớ Heap thành mảng byte để truyền qua mạng.
- Partitioner: Chiến lược chọn partition cho dữ bản ghi, theo mặc định sẽ là roud — robin lần lượt đều trên tất cả partitions.
Ngoài ra Kafka hỗ trợ sẵn cơ chế retry khi có lỗi trong quá trình gửi dữ liệu (Kafka cung cấp 1 vài option cho việc này)
Có 2 phần cần lưu ý:
- Khung màu đỏ: Cấu hinh cụm kafka, bao gồm cả trình serializer cho Key và Value
- Khung màu blue: Đẩy dữ liệu vào cụm thông qua đối tượng Producer Record.
Producer Acks:
Producer trong kafka cung cấp tính năng Acks, sử dụng để đảm bảo dữ liệu từ nguồn được đẩy vào cụm theo các mode:
- Acks = 0: Producer chỉ đẩy dữ liệu, không cần chờ phản hồi từ Cluster, dữ liệu lỗi trong quá trình đẩy sẽ bị mất.
- Acks = 1: Producer đẩy dữ liệu xong khi Leader nhận được bản ghi không cần chờ các follower replicate dữ liệu. (là chế độ mặc định)
- Acks = -1: Producer đẩy dữ liệu xong khi Leader nhận được bản ghi và toàn bộ các follower replicate đủ số lượng cấu hình của topic.
Có thể thấy rằng Acks = 0 sẽ đẩy dữ liệu nhanh hơn cả do không phải chờ đợi và xử lý các case lỗi tuy nhiên có thể mất mát bản ghi. Mode này rất phù hợp với các dữ liệu có lượng lớn nhưng không quá quan trọng.
Acks = -1 lại là 1 sự đảm bảo nhất cho các bản ghi khi dữ liệu sau khi nhận còn đảm bảo cả số bản sao lưu dự phòng, tuy nhiên mode này sẽ chậm hơn nhiều do việc sao lưu và kiểm tra dữ liệu mất thêm thời gian, với các dữ liệu quan trọng như giao dịch khách hàng, cần đánh đổi thời gian để đảm bảo chất lượng dữ liệu.
Acks = 1 cân bằng giữa 0 và -1, nó đủ an toàn trong hầu hết các trường hợp và nhanh hơn Acks = -1. Tuy nhiên vẫn có khả năng mất mát dữ liệu khi Follower chưa kịp sau lưu thì Leader bị down.
Kafka Partitioner
Partition là cách chia nhỏ dữ liệu của 1 topic thành nhiều phần khác nhau. Nếu không chỉ định, mặc định khi 1 producer đẩy dữ liệu vào topic, kafka sẽ lần lượt chia các bản ghi các các partitions của topic ấy (round robin). Tuy nhiên, nếu không muốn lần lượt, bạn hoàn toàn có thể custom lại cách chia dữ liệu thông qua Kafka partitioner bằng cách tạo 1 Class extends org.apache.kafka.clients.producer.Partitioner và triển khai các thuật toán trong đó.
VD producer đọc dữ liệu order của khách hàng từ web và app nhưng bạn muốn chia dữ liệu order từ web vào 1 partition và app 1 partition khác để dễ dàng xử lý, hãy nghĩ đến việc tạo 1 Partitioner cho riêng trường hợp này.
Consumer Groups
Consumer phụ trách việc đọc dữ liệu từ Kafka ra theo topic. Một hệ thống Messaging Queue có 2 loại:
- Pub/ Sub (1-n): Một message sẽ được xử lý bởi một vài consumer thích hợp. VD 1 bản ghi giao dịch đặt hàng được xử lý bởi 2 tiến trình, 1 là tiến trình gửi đơn hàng cho nhà cung cấp, 1 tiến trình khác để gửi confirm đặt hàng cho khách hàng.
- Queue (1–1): Một message sẽ được xử lý bởi một consumer, chính là hệ thống queue thông thường
Consumer Group là khái niệm của Kafka, nó hỗ trợ được cả 2 mô hình Queue truyền thống và Pub/ sub như sau:
- Nhiều consumer group cùng subscribe 1 topic, ta có hệ thống Pub/ sub
- Nhiều instance consumer chung 1 group, ta có hệ thống Queue
Kafka bảo đảm mỗi một message sẽ được gửi cho một consumer instance duy nhất trong một consumer group.
Như hình, ta dựng 2 tiến trình consumer, đọc 2 topic thì mỗi partition của 1 topic chỉ đc giao cho 1 consusmer, đảm bảo không consumer nào xử lý trùng dữ liệu của consumer khác trong 1 group.
Consumer Rebalances
Khi dữ liệu tăng, các consumer sẽ bị tăng tải, lúc này để san tải, ta sẽ nghĩ tới việc dựng thêm tiến trình xử lý? Với cơ Consumer group, việc này sẽ dễ dàng hơn bao giờ hết.
VD hệ thống đang có 2 consumer xử lý lượng dữ liệu 1 triệu bản ghi 1 ngày rất mượt mà, tới 1 ngày đẹp trời bạn quyết định triển khai 1 campaign và lượng giao dịch tăng gấp rưỡi, và 2 consumer sẽ bắt đầu cao tải. Lúc này, chỉ cần dựng thêm 1 consumer nữa với cùng consumer id group với 2 consumer cũ, Kafka sẽ tự san tải làm 3, đảm bảo không trùng lặp dữ liệu. Khi hết campaign, muốn tiết kiêm tài nguyên, bạn bỏ 1 consumer đi, Kafka sẽ tự động phân tải lại cho 2 consumer trong group, rất tuyệt đúng không nào.
Link bài viết gốc tại đây
Bài viết đăng tải lại dưới sự cho phép của tác giả : thầy Nguyễn Chí Thanh là giảng viên khoá Big Data tại Techmaster
Bình luận