Kafka retention và log compaction: giữ lịch sử hay giữ trạng thái mới nhất? Trung cấp
Thời gian đọc ước tính: 6 phút
Cần đọc trước
Vấn đề
Phần tiêu đề “Vấn đề”Service A dựng lại bảng email hiện tại từ topic user-email: chỉ cần giá trị mới nhất của mỗi user. Service audit cần mọi lần đổi email. Cả hai nghe “Kafka lưu log nên replay được”, nhưng cleanup policy quyết định dữ liệu thật sự còn lại.
| Nhu cầu | Policy |
|---|---|
| Lịch sử theo cửa sổ thời gian (event log) | delete (mặc định) |
| Trạng thái mới nhất theo key (snapshot, CDC state) | compact |
| Snapshot nhưng có trần thời gian | delete,compact |
| Audit đầy đủ vĩnh viễn | Không dùng compact; lưu ra kho riêng |
Segment: đơn vị dọn dẹp
Phần tiêu đề “Segment: đơn vị dọn dẹp”Log của partition chia thành các segment file. Kafka xoá hoặc compact theo segment:
- Segment đang ghi (active) không bao giờ bị compact (docs: “the active segment will not be compacted”).
- Với
delete, retention cũng xoá nguyên cả segment (“Retention and cleaning is always done a file at a time”). segment.mstồn tại để ép đóng segment “to ensure that retention can delete or compact old data”.
Nghĩa là segment đang nhận ghi liên tục thường chưa bị xoá; chi tiết xử lý active segment hết hạn khi retention chạy là chi tiết cài đặt, tuỳ phiên bản.
Đang tải diagram…
Segment đóng khi đạt segment.bytes (mặc định 1 GiB) hoặc segment.ms (mặc định 7 ngày). Topic nhỏ, ít ghi có thể chưa đóng segment nào: lý do thường gặp của câu hỏi “sao retention/compaction chưa chạy”.
Cheat-sheet config (mặc định theo docs 4.2)
Phần tiêu đề “Cheat-sheet config (mặc định theo docs 4.2)”| Config | Mặc định | Ý nghĩa |
|---|---|---|
cleanup.policy |
delete |
delete, compact hoặc cả hai |
retention.ms |
604800000 (7 ngày) | Giữ segment tối đa bao lâu |
retention.bytes |
-1 (không giới hạn) | Trần dung lượng mỗi partition |
segment.bytes |
1073741824 (1 GiB) | Kích thước segment |
segment.ms |
604800000 (7 ngày) | Ép đóng segment theo thời gian |
min.cleanable.dirty.ratio |
0.5 | Tỷ lệ phần “dirty” tối thiểu để cleaner compact |
min.compaction.lag.ms |
0 | Record phải đủ tuổi này mới được compact |
max.compaction.lag.ms |
rất lớn (không giới hạn thực tế) | Trần chờ compaction |
delete.retention.ms |
86400000 (1 ngày) | Giữ tombstone bao lâu |
remote.storage.enable |
false |
Bật tiered storage (xem cuối bài) |
Hai tính chất cần nhớ: thời điểm xoá thật không trùng mili-giây hết hạn của từng record, và retention không chờ consumer chậm.
delete retention
Phần tiêu đề “delete retention”Segment đóng bị xoá khi hết retention.ms hoặc topic vượt retention.bytes. Consumer lag vượt cửa sổ này sẽ không đọc được dữ liệu cũ, dù chưa từng commit qua nó.
Quy tắc: cửa sổ retention phải dài hơn thời gian sự cố tệ nhất cộng thời gian bắt kịp. Theo dõi lag bằng thời gian (tuổi record cũ nhất chưa xử lý) chứ không chỉ số record.
compaction
Phần tiêu đề “compaction”Với compact, Kafka giữ ít nhất bản mới nhất của mỗi key trong partition. Cleaner chạy bất đồng bộ, và chỉ compact khi phần dirty (chưa compact) vượt min.cleanable.dirty.ratio.
Đang tải diagram…
- Offset không bị đánh số lại: offset 2 vẫn là 2; dãy đọc được có gap.
- Consumer theo kịp có thể thấy cả bản cũ lẫn mới; bảo đảm là đọc từ đầu sẽ dựng được trạng thái cuối theo key.
- Tombstone là record có key và value
null(không phải chuỗi'null'). Nó bị cleaner xoá saudelete.retention.ms(1 ngày): consumer bootstrap chậm hơn cửa sổ này có thể bỏ lỡ tombstone. - Key phải ổn định (
userId, không phảieventId), nếu không mỗi event là một key riêng và compaction không tạo snapshot.
Khi nào dùng / không dùng
Phần tiêu đề “Khi nào dùng / không dùng”| Dùng compact | Không dùng compact |
|---|---|
| State theo key: CDC snapshot, cấu hình, cache rebuild | Audit trail, event sourcing cần mọi thay đổi |
__consumer_offsets (Kafka tự dùng compact) |
Event không có key ổn định |
| Consumer mới cần bootstrap nhanh từ trạng thái cuối | Cần biết khi nào A đổi sang B |
Tiered storage (remote.storage.enable, mặc định false) cho phép đẩy segment cũ sang storage ngoài để giữ retention dài với chi phí broker thấp; bật theo topic và kiểm tra hỗ trợ ở phiên bản bạn dùng.
Ví dụ thực tế
Phần tiêu đề “Ví dụ thực tế”Mô hình trạng thái cuối trong RAM (không mô phỏng cleaner thật):
npx --prefix examples ts-node examples/src/kafka-compaction/compaction-model.tsOutput: bốn record offset 0–3; bản mới nhất mỗi key là 2:user-1=new@example.test và 3:user-2=null; áp tombstone còn user-1=new@example.test. Trên broker thật, compaction không chạy ngay và tombstone có retention riêng.
Trade-offs
Phần tiêu đề “Trade-offs”Chọn policy theo nhu cầu
- Delete: dung lượng dự đoán được, hợp event log theo cửa sổ.
- Compact: dựng trạng thái mới nhất mà không giữ mọi thay đổi.
- Offset của record còn lại ổn định.
Giới hạn
- Delete có thể xoá trước khi consumer chậm đọc tới.
- Compact không giữ lịch sử và không chạy tức thì.
- Tombstone và
delete,compactcần tính cửa sổ bootstrap.
Checklist production
Phần tiêu đề “Checklist production”- Chọn policy từ nhu cầu: lịch sử (
delete) hay snapshot (compact). - Đặt
retention.mstheo SLA khôi phục, không dùng 7 ngày mặc định một cách vô thức. - Compact: key ổn định, schema value tương thích ngược.
- Compact: consumer bootstrap phải đọc hết trong
delete.retention.ms. - Alert theo tuổi record cũ nhất chưa xử lý so với retention.
- Audit cần giữ lâu thì lưu ra kho riêng hoặc tiered storage.
Sai lầm thường gặp
Phần tiêu đề “Sai lầm thường gặp”Tóm tắt
Phần tiêu đề “Tóm tắt”Tự kiểm tra: (1) Vì sao offset có gap sau compaction? (2) Cần audit mọi lần đổi email, compacted topic có đủ không? (3) Producer dùng eventId làm key thì compaction theo user còn hiệu quả không?