Bỏ qua để đến nội dung
Knowledge Hub

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

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

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.ms tồ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”.

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.

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.

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á sau delete.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ải eventId), nếu không mỗi event là một key riêng và compaction không tạo snapshot.
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.

Mô hình trạng thái cuối trong RAM (không mô phỏng cleaner thật):

Terminal window
npx --prefix examples ts-node examples/src/kafka-compaction/compaction-model.ts

Output: 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.

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,compact cần tính cửa sổ bootstrap.
  1. Chọn policy từ nhu cầu: lịch sử (delete) hay snapshot (compact).
  2. Đặt retention.ms theo SLA khôi phục, không dùng 7 ngày mặc định một cách vô thức.
  3. Compact: key ổn định, schema value tương thích ngược.
  4. Compact: consumer bootstrap phải đọc hết trong delete.retention.ms.
  5. Alert theo tuổi record cũ nhất chưa xử lý so với retention.
  6. Audit cần giữ lâu thì lưu ra kho riêng hoặc tiered storage.

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?