Xác Thực Độ Tin Cậy của Hệ Thống Trong Kafka
1. Mở đầu
Khi chúng ta đã hoàn thành việc xác định yêu cầu độ tin cậy, cấu hình các broker, cấu hình các client và sử dụng API theo cách tốt nhất cho trường hợp sử dụng của mình, liệu chúng ta có thể yên tâm chạy mọi thứ trong môi trường production, tự tin rằng không có sự kiện nào bị bỏ lỡ?
Mình khuyến nghị anh em nên thực hiện một số bước xác thực trước và với mô hình đề xuất ba lớp xác thực: xác thực cấu hình, xác thực ứng dụng và giám sát ứng dụng trong môi trường production. Hãy cùng xem và tìm hiểu từng bước và xác định những gì cần phải xác thực và cách thực hiện.
2. Xác Thực Cấu Hình
Việc kiểm tra cấu hình của broker và client riêng biệt với logic ứng dụng là dễ dàng, và được khuyến nghị làm vì hai lý do:
- Nó giúp kiểm tra xem cấu hình mà chúng ta đã chọn có đáp ứng được yêu cầu hay không.
- Đây là một bài tập tốt để suy nghĩ về hành vi mong đợi của hệ thống.
Kafka bao gồm hai công cụ quan trọng để hỗ trợ trong việc xác thực này. Gói org.apache.kafka.tools
bao gồm các lớp VerifiableProducer và VerifiableConsumer. Các công cụ này có thể chạy dưới dạng công cụ dòng lệnh hoặc được nhúng trong một framework kiểm thử tự động.
Ý tưởng là verifiable producer sẽ tạo ra một chuỗi các message chứa các số từ 1 đến một giá trị mà chúng ta chọn. Chúng ta có thể cấu hình verifiable producer giống như cấu hình producer của riêng mình, bao gồm việc đặt số lượng acks, số lần thử lại (retries), delivery.timeout.ms
, và tốc độ mà các message sẽ được gửi. Khi chạy, nó sẽ in ra kết quả thành công hoặc lỗi cho từng message được gửi đến broker, dựa trên acks nhận được. Verifiable consumer thực hiện kiểm tra bổ sung. Nó tiêu thụ các sự kiện (thường là những sự kiện do verifiable producer tạo ra) và in ra các sự kiện mà nó đã tiêu thụ theo thứ tự. Nó cũng in thông tin liên quan đến commits và rebalances.
Điều quan trọng là cần xem xét các bài kiểm tra (test) mà chúng ta muốn thực hiện. Ví dụ:
- Bầu chọn leader: Điều gì sẽ xảy ra nếu chúng ta dừng leader? Mất bao lâu để producer và consumer hoạt động lại bình thường?
- Bầu chọn controller: Mất bao lâu để hệ thống hoạt động lại sau khi khởi động lại controller?
- Rolling restart: Chúng ta có thể khởi động lại từng broker một mà không mất bất kỳ message nào không?
- Kiểm tra bầu chọn leader không an toàn: Điều gì xảy ra khi chúng ta dừng tất cả các bản sao (replica) cho một partition từng cái một (để đảm bảo mỗi cái đều mất đồng bộ) và sau đó khởi động một broker đã mất đồng bộ? Điều gì cần xảy ra để hệ thống hoạt động lại? Điều này có chấp nhận được không?
Sau đó, chúng ta chọn một kịch bản, khởi chạy verifiable producer, khởi chạy verifiable consumer, và thực hiện kịch bản—ví dụ, dừng leader của partition mà chúng ta đang produce dữ liệu. Nếu chúng ta mong đợi một khoảng tạm dừng ngắn và sau đó mọi thứ tiếp tục bình thường mà không mất message, chúng ta cần đảm bảo rằng số lượng message được producer tạo ra và số lượng message được consumer tiêu thụ khớp với nhau.
Kho mã nguồn của Apache Kafka bao gồm một bộ kiểm thử mở rộng. Nhiều kiểm thử trong bộ này dựa trên nguyên tắc tương tự và sử dụng verifiable producer và consumer để đảm bảo việc nâng cấp hoạt động chính xác.
3. Xác thực ứng dụng
Sau khi đảm bảo rằng cấu hình broker và client đáp ứng yêu cầu của chúng ta, đã đến lúc kiểm tra xem ứng dụng có cung cấp các đảm bảo mà chúng ta cần hay không. Điều này sẽ kiểm tra những phần như mã xử lý lỗi tùy chỉnh, commit offset, listener khi rabalance, và các phần tương tự nơi logic ứng dụng tương tác với thư viện client của Kafka.
Tất nhiên, vì logic ứng dụng có thể thay đổi đáng kể, nên chỉ có một số hướng dẫn nhất định về cách kiểm tra nó. Mình khuyến nghị thực hiện các kiểm thử tích hợp cho ứng dụng như một phần của bất kỳ quá trình phát triển nào, và nên chạy các kiểm thử trong nhiều điều kiện lỗi khác nhau.
- Client mất kết nối với một trong các broker
- Độ trễ cao giữa client và broker
- Đầy ổ đĩa
- Đĩa bị treo (còn gọi là “brown out”)
- Bầu chọn leader
- Khởi động lại broker tuần tự
- Khởi động lại consumer tuần tự
- Khởi động lại producer tuần tự
Có nhiều công cụ có thể được sử dụng để giới thiệu các lỗi về mạng và ổ đĩa, và nhiều công cụ rất tốt, vì vậy chúng tôi sẽ không cố gắng đưa ra khuyến nghị cụ thể. Apache Kafka tự nó bao gồm framework Trogdor để tiêm lỗi. Đối với mỗi kịch bản, chúng ta sẽ có hành vi mong đợi, đó là những gì chúng ta đã dự tính khi phát triển ứng dụng. Sau đó, chúng ta chạy thử nghiệm để xem điều gì thực sự xảy ra. Ví dụ, khi lập kế hoạch cho việc khởi động lại tuần tự các consumer, chúng ta dự tính một khoảng dừng ngắn khi consumer rebalance, sau đó tiếp tục tiêu thụ với không quá 1.000 giá trị trùng lặp. Bài kiểm tra của chúng ta sẽ cho thấy liệu cách ứng dụng commit offset và xử lý việc rebalance có hoạt động như mong muốn hay không.
4. Giám Sát Độ Tin Cậy Trong Môi Trường Production
Việc kiểm thử ứng dụng rất quan trọng, nhưng nó không thay thế được nhu cầu giám sát liên tục các hệ thống trong môi trường production để đảm bảo rằng dữ liệu đang lưu thông như mong đợi. Các bài viết kế tiếp sẽ đề cập đến các gợi ý chi tiết về cách giám sát cụm Kafka, nhưng ngoài việc giám sát sức khỏe của cụm, điều quan trọng là cần theo dõi các client và luồng dữ liệu trong toàn hệ thống.
Các client Java của Kafka bao gồm các chỉ số JMX cho phép giám sát trạng thái và sự kiện ở phía client. Đối với các producer, hai chỉ số quan trọng nhất đối với độ tin cậy là tỷ lệ lỗi và tỷ lệ thử lại (retry) cho mỗi bản ghi (tính tổng hợp). Hãy chú ý đến các chỉ số này, vì tỷ lệ lỗi hoặc thử lại tăng có thể cho thấy có vấn đề với hệ thống. Đồng thời, hãy giám sát các log của producer để phát hiện lỗi xảy ra khi gửi sự kiện, được ghi ở mức WARN, và có thể chứa thông báo như “Nhận được phản hồi lỗi produce với id tương quan 5689 trên topic-partition [topic-1,3], đang thử lại (còn hai lần thử). Lỗi: …” Khi thấy các sự kiện với 0 lần thử còn lại, nghĩa là producer đang hết khả năng thử lại. Trong bài viết, chúng ta đã cùng nhau thảo luận cách cấu hình delivery.timeout.ms
và retries để cải thiện việc xử lý lỗi trong producer và tránh việc hết khả năng thử lại (retry) quá sớm. Tất nhiên, luôn tốt hơn khi giải quyết vấn đề gây ra lỗi ngay từ đầu. Các thông báo log ở mức ERROR trên producer có thể chỉ ra rằng việc gửi message hoàn toàn thất bại do lỗi không thể thử lại, lỗi có thể thử lại đã hết số lần thử, hoặc do thời gian chờ. Khi áp dụng, lỗi chính xác từ broker cũng sẽ được ghi lại.
Ở phía consumer, chỉ số quan trọng nhất là độ trễ của consumer (consumer lag). Chỉ số này cho biết consumer còn cách bao xa so với message mới nhất đã được commit vào partition trên broker. Lý tưởng nhất, độ trễ luôn là không và consumer sẽ luôn đọc được message mới nhất. Trong thực tế, vì phương thức poll() trả về nhiều message và sau đó consumer cần thời gian để xử lý chúng trước khi lấy thêm message mới, nên độ trễ luôn dao động một chút. Điều quan trọng là đảm bảo rằng các consumer cuối cùng sẽ bắt kịp thay vì ngày càng bị tụt lại xa hơn. Do sự dao động dự kiến của độ trễ consumer, việc thiết lập các cảnh báo truyền thống cho chỉ số này có thể gặp khó khăn. Burrow là một công cụ kiểm tra độ trễ consumer của LinkedIn và có thể giúp việc này dễ dàng hơn.
Giám sát luồng dữ liệu cũng có nghĩa là đảm bảo tất cả dữ liệu được produce được tiêu thụ kịp thời (“kịp thời” thường dựa trên yêu cầu kinh doanh). Để đảm bảo dữ liệu được tiêu thụ đúng hạn, chúng ta cần biết khi nào dữ liệu được produce. Kafka hỗ trợ việc này: bắt đầu từ phiên bản 0.10.0, tất cả các message đều bao gồm một dấu thời gian (timestamp) cho biết khi sự kiện được produce (mặc dù lưu ý rằng điều này có thể bị ghi đè bởi ứng dụng gửi sự kiện hoặc bởi các broker nếu chúng được cấu hình để làm điều đó).
Để đảm bảo tất cả các message được produce được tiêu thụ trong một khoảng thời gian hợp lý, chúng ta cần ứng dụng produce message ghi lại số lượng sự kiện được produce (thường là số sự kiện mỗi giây). Các consumer cần ghi lại số lượng sự kiện tiêu thụ được mỗi đơn vị thời gian và độ trễ từ thời điểm các sự kiện được produce đến thời điểm chúng được tiêu thụ, sử dụng dấu thời gian của sự kiện. Sau đó, chúng ta sẽ cần một hệ thống để đối chiếu số lượng sự kiện mỗi giây từ cả producer và consumer (để đảm bảo không có message nào bị mất trên đường đi) và để đảm bảo khoảng thời gian giữa thời điểm produce và tiêu thụ là hợp lý. Hệ thống giám sát end-to-end kiểu này có thể gặp khó khăn và tốn thời gian để triển khai. Theo những gì mình biết, hiện không có hệ thống mã nguồn mở cho loại này, nhưng Confluent cung cấp một triển khai thương mại như một phần của Confluent Control Center.
Ngoài việc giám sát các client và luồng dữ liệu end-to-end flow, các broker Kafka cũng bao gồm các chỉ số cho biết tỷ lệ phản hồi lỗi được gửi từ các broker đến các client. Mình khuyến nghị thu thập các chỉ số kafka.server:type=BrokerTopicMetrics,name=FailedProduceRequestsPerSec và kafka.server:type=BrokerTopicMetrics,name=FailedFetchRequestsPerSec. Đôi khi, một mức độ phản hồi lỗi nhất định là điều bình thường—ví dụ, nếu chúng ta tắt một broker để bảo trì và các broker khác được bầu làm leader mới, các producer sẽ nhận được lỗi NOT_LEADER_FOR_PARTITION, điều này sẽ khiến chúng yêu cầu metadata cập nhật trước khi tiếp tục sản xuất sự kiện như bình thường. Sự gia tăng không giải thích được trong các yêu cầu bị lỗi luôn cần được điều tra. Để hỗ trợ các cuộc điều tra như vậy, các chỉ số yêu cầu bị lỗi được gán nhãn với phản hồi lỗi cụ thể mà broker đã gửi.
5. Thông tin kết nối
Nếu anh em muốn trao đổi thêm về bài viết, hãy kết nối với mình qua LinkedIn và Facebook:
- LinkedIn: https://www.linkedin.com/in/nguyentrungnam/
- Facebook: https://www.facebook.com/trungnam.nguyen.395/
Rất mong được kết nối và cùng thảo luận!
All rights reserved