Bốn mươi phần, mỗi phần dựng bằng container thật và đo bằng số thật. Bài cuối gom lại những gì đáng mang theo.
Mười con số của cả sê-ri
| p2 | Công cụ dòng lệnh tốn 0,86 giây; gửi tin thật tốn 0,89 mili giây |
| p3 | 4 khoá vào 4 partition → 5.000 / 0 / 0 / 15.000 |
| p5 | batch.size 1 → 16384: thông lượng gấp 14, độ trễ giảm 1.567 lần |
| p8 | Cùng một lần sập: 1.150 tin trùng, hay 50 tin trùng, hay 50 tin mất |
| p10 | fetch.min.bytes=65536 đẩy độ trễ từ 0,35 ms lên 503,68 ms |
| p13 | Giết một broker: 9.142 ms để bầu leader mới |
| p22 | Một tin hỏng → 8.306.744 ngoại lệ trong 12 giây |
| p26 | Một tin một giao dịch = 96 tin/giây, chậm hơn 6.280 lần |
| p31 | Lag tăng 57 lần trong 60 giây, mọi chỉ số broker vẫn xanh |
| p38 | Thiếu một dòng volume: 10.000 tin và cả topic biến mất |
Không con số nào trong bảng này đoán được từ tài liệu. Tất cả đều phải đo.
Cấu hình mặc định cho một cụm thật
# độ bền — p4, p14, p15
replication.factor = 3
min.insync.replicas = 2
acks = all
unclean.leader.election.enable = false
enable.idempotence = true
# thông lượng — p5
batch.size = 65536
linger.ms = 0
compression.type = lz4
# vận hành — p9, p14, p24
auto.create.topics.enable = false
max.poll.records = 100
group.instance.id = <tên pod>
Mọi giá trị ở đây đến từ một phép đo trong loạt bài, không từ thói quen:
min.insync.replicas = 2— vì phần 14 đo được=3làm mọi lần bảo trì dừng ghi, còn=1để lọt kịch bản mất dữ liệu của phần 15.linger.ms = 0— vì phần 5 đo được nó gần như không ảnh hưởng ở tải cao, và phần 10 đo được nó cộng 54 ms ở tải thấp.compression.type = lz4— vì phần 5 đo được nó giữ 99% thông lượng mà đĩa nhỏ đi 6,7 lần.max.poll.records = 100— vì phần 24 đo được lô lớn khiến thời gian xử lý vượtmax.poll.interval.ms.group.instance.id— vì phần 27 đo được khởi động lại nhanh mất 44 giây nếu không có nó.
Sáu cách hỏng im lặng
Đây là phần đáng nhớ nhất của loạt bài. Không cái nào báo lỗi, ghi log, hay hiện lên bảng theo dõi.
p12 — Tăng partition làm 45% khoá đổi chỗ. Tin cũ và tin mới của cùng một khoá nằm ở hai partition khác nhau, và thứ tự giữa chúng hỏng vĩnh viễn.
p25 — --to-datetime với mốc sai báo Partition is empty rồi nhảy tới cuối log. Bạn nghĩ vừa tua lại, thực ra vừa bỏ qua toàn bộ dữ liệu.
p28 — Cửa sổ nối quá ngắn cho 0 kết quả. Topic đích chỉ đơn giản là rỗng, trông y hệt "chưa có dữ liệu".
p29 — JDBC mode=incrementing bỏ qua 50.000 UPDATE và 10.000 DELETE. Connector vẫn RUNNING, và Kafka phục vụ dữ liệu cũ mãi mãi.
p36 — MirrorMaker chép dữ liệu ngon lành, offset thì không sang. Kế hoạch chuyển vùng chỉ hỏng vào đúng ngày cần dùng.
p38 — Không có volume thì docker rm xoá sạch, và broker lên lại như vừa cài.
Điểm chung: mỗi cái đều có một lệnh kiểm phát hiện được trong ba mươi giây. Chạy chúng một lần còn hơn tin rằng mọi thứ ổn.
Danh sách kiểm trước khi lên môi trường thật
Độ bền
-
replication.factor ≥ 3trên mọi topic nghiệp vụ -
min.insync.replicas = 2, và nó nhỏ hơnreplication.factor - Producer dùng
acks=all— kiểm ở phía ứng dụng, broker không ép được (p14) -
unclean.leader.election.enable=falsetrên mọi topic không dựng lại được (p15) -
auto.create.topics.enable=false(p14)
Vận hành
- Volume gắn đúng vào thư mục dữ liệu (p38)
-
stop_grace_periodđủ dài, không dùngkill -9(p20, p38) - Giới hạn bộ nhớ container lớn hơn hẳn heap (p38)
- Bầu lại leader ưu tiên sau mỗi lần khởi động lại broker (p13, p37)
-
retention.msđặt theo yêu cầu xử lý lại, không để mặc định (p17, p25)
Giám sát
-
OfflinePartitionsCount,ActiveControllerCount,UnderReplicatedPartitions(p31) - Lag theo partition tệ nhất, cảnh báo theo xu hướng chứ không theo mức (p32)
- Lag tính bằng thời gian, không chỉ bằng số tin (p32)
- Dung lượng đĩa mỗi broker, cảnh báo ở 75% (p17)
Ứng dụng
- Consumer bắt
RecordDeserializationExceptionvà nhảy qua (p22) - Có topic tin chết, và có ai đó nhìn nó (p24)
- Phía tiêu thụ chịu được xử lý trùng (p8, p26)
-
delivery.timeout.mslớn hơn thời gian bị điều tiết tệ nhất (p33)
Bài học về cách đo
Sáu lần trong loạt bài này, một phép đo của tôi cho kết quả sai vì cùng hai lý do:
Nuốt lỗi bằng 2>/dev/null. Lệnh dựng môi trường hỏng, tôi không thấy, và phép đo chạy trên môi trường không như tôi nghĩ. Phần 20 là ca tệ nhất: hai topic không có cấu hình cần đo, và tôi suýt công bố một "quy luật hình chữ U" hoàn toàn không tồn tại.
Không xác minh cấu hình đã được áp dụng. Phần 10: kafka-e2e-latency.sh ghi đè fetch.min.bytes sau khi nạp tệp cấu hình, nên sáu lần chạy khác nhau đều ra 0,29 ms.
Quy tắc rút ra, và nó đúng ngoài Kafka:
Kết quả giống nhau qua nhiều cấu hình khác nhau không phải phát hiện. Nó là dấu hiệu phép đo hỏng.
Và quy tắc thứ hai, từ phần 8:
Nếu kết quả của bạn quá gọn gàng, hãy nghi ngờ nó trước đã. Điểm sập rơi đúng ranh giới lô cho ra ba con số hoàn hảo giống nhau — và che mất toàn bộ hiện tượng cần đo.
Cái loạt bài này không phủ tới
Để rõ ràng về phạm vi:
- Kafka trên Kubernetes — Strimzi và các toán tử khác, một chủ đề riêng.
- Tiered storage (từ 3.6) — đẩy segment cũ sang S3. Tôi không có môi trường để đo.
- Cụm quy mô lớn — mọi phép đo chạy trên một máy với tối đa ba broker. Con số về bầu lại leader và cân bằng lại ở quy mô hàng chục nghìn partition sẽ khác.
- Kafka Streams sâu hơn — mới chạm tới đếm, cửa sổ và nối.
Nếu chỉ nhớ ba điều
Kafka nhanh vì nó không làm gì phức tạp. Ghi nối tiếp, chỉ mục thưa, sendfile, xoá cả tệp. Mọi tối ưu đều đến từ việc không làm, và hiểu điều đó giải thích gần hết hành vi của nó (p16, p19).
Phần lớn sự cố Kafka không nằm ở Kafka. Consumer chậm, lược đồ đổi, cấu hình client sai, partition bị lệch khoá. Broker khoẻ trong khi đường ống chết là tình huống bình thường (p31).
Cái hỏng im lặng nguy hiểm hơn cái hỏng ồn ào. Sáu ca ở trên đều để hệ thống chạy tiếp với dữ liệu sai. Danh sách kiểm ba mươi giây ở mỗi phần tồn tại vì lý do đó.
Thử ba mươi giây, lần cuối
kafka-topics.sh --bootstrap-server kf:9092 --describe --under-replicated-partitions
kafka-topics.sh --bootstrap-server kf:9092 --describe --unavailable-partitions
kafka-consumer-groups.sh --bootstrap-server kf:9092 --all-groups --describe 2>/dev/null \
| awk 'NR>1 && $6 ~ /^[0-9]+$/ {print $6, $1, $2, $3, $7}' | sort -rn | head -5
Ba lệnh. Hai lệnh đầu phải im lặng. Lệnh thứ ba cho bạn năm chỗ đau nhất trong cụm, và nếu cột cuối là - thì partition đó không có ai đọc.
Cảm ơn bạn đã theo hết bốn mươi phần.