Kafka's cleanup.policy decides whether log segments (one per partition) are deleted by time and size, compacted per-key, or both at once.
This article covers when to choose delete, compact, or compact,delete, the field pitfalls that bite real operators, how the main parameters interact, and the angles the CCAAK exam tends to focus on.
cleanup.policy is a per-topic setting. delete drops whole segments once they hit a time (retention.ms) or size (retention.bytes) threshold. compact keeps only the latest value per key, thinning out duplicate updates. compact,delete applies both, holding only the latest value per key while still expiring old segments by time or size to cap disk usage.
delete never touches the active segment (the one currently being written). compact runs in the background via the broker's Log Cleaner (log.cleaner.enable, log.cleaner.threads), removing duplicate keys from segments that meet conditions such as min.cleanable.dirty.ratio. Tombstones (records with a null value) act as delete markers and are retained for delete.retention.ms.
retention.ms and retention.bytes are evaluated independently; the oldest segments are removed as soon as either threshold is crossed. The key point with compact,delete is that compaction keeps each key current while old segments themselves still disappear once the time or size cap is reached.
| cleanup.policy | Retention granularity | Typical use cases | Key related settings |
|---|---|---|---|
| delete | Per segment (time / size) | Event logs, audit logs, time-series data | retention.ms / retention.bytes / segment.ms / segment.bytes |
| compact | Per key (latest value + tombstone retention) | KTables / changelogs, latest snapshot of CDC streams | delete.retention.ms / min.cleanable.dirty.ratio / min.compaction.lag.ms |
| compact,delete | Per key plus old-segment deletion | Keep the latest snapshot while capping disk usage | All of the above (watch the interplay between retention.ms and delete.retention.ms) |
How segment deletion and compaction relate (conceptual view of a single partition)
delete is the most intuitive retention strategy: a whole segment is dropped once it exceeds a time or size threshold. Because the active segment is never deleted, tightening segment.ms or segment.bytes to roll segments more often gives you a clearer retention boundary.
Time-based retention depends on the message timestamp type. CreateTime uses the time the producer stamped, LogAppendTime uses when the broker received it. For workloads with late arrivals or clock skew, LogAppendTime keeps retention behavior more predictable.
With compact, older records for the same key are thinned out, leaving only the latest version. Deletes are expressed as tombstones (null values), which are kept for delete.retention.ms so downstream consumers have a chance to observe the deletion.
Compaction is asynchronous; segments become candidates once min.cleanable.dirty.ratio (the dirty ratio since the last clean) is exceeded. min.compaction.lag.ms lets you carve out a grace window so freshly written data is not compacted immediately. On high-throughput clusters, watch the log.cleaner.threads parallelism and I/O bandwidth.
compact,delete shines when you want to keep the latest snapshot but still cap overall log volume. Compaction keeps only the latest value per key, and old segments themselves are still purged via retention.ms/bytes to bound disk usage.
The catch is that compaction does not guarantee permanent retention. Once retention.ms passes, segments that still hold snapshots you assumed were safe can be dropped. If retention.ms is shorter than your new-consumer bootstrap or downstream reprocessing window, full initialization may fail.
Typical combinations: Event logs - cleanup.policy=delete with retention.ms and retention.bytes aligned to your business SLA and disk capacity. Changelogs where the latest snapshot matters - cleanup.policy=compact with delete.retention.ms long enough to cover downstream ingestion lag. Latest snapshot plus disk cap - cleanup.policy=compact,delete with retention.ms set longer than your initial-sync or reprocessing window.
For capacity planning, estimate per-partition throughput x retention time to get rough segment volume, multiply by partition count and replication factor, then add 10-20% for index overhead. Smaller segment.bytes makes retention boundaries reflect more quickly but increases file count and metadata pressure.
Representative configuration commands (script names and options vary by version)
# 1) Event log (delete): delete once 7 days OR 200 GiB is reached
kafka-topics.sh --create \
--topic app-events \
--partitions 12 --replication-factor 3 \
--config cleanup.policy=delete \
--config retention.ms=$((7*24*60*60*1000)) \
--config retention.bytes=$((200*1024*1024*1024)) \
--config segment.ms=$((15*60*1000))
# 2) Changelog (compact): keep tombstones for 72 hours
kafka-topics.sh --create \
--topic user-profile-changelog \
--partitions 12 --replication-factor 3 \
--config cleanup.policy=compact \
--config delete.retention.ms=$((72*60*60*1000)) \
--config min.cleanable.dirty.ratio=0.5 \
--config min.compaction.lag.ms=$((10*60*1000))
# 3) Latest snapshot + size cap (compact,delete): keep latest, drop old segments after 14 days
kafka-topics.sh --create \
--topic account-state \
--partitions 24 --replication-factor 3 \
--config cleanup.policy=compact,delete \
--config retention.ms=$((14*24*60*60*1000)) \
--config delete.retention.ms=$((72*60*60*1000)) \
--config segment.bytes=$((256*1024*1024))
# 4) Altering an existing topic
kafka-configs.sh --alter --entity-type topics --entity-name app-events \
--add-config retention.ms=$((10*24*60*60*1000))
# 5) Sending a tombstone (key:value format; omitting the value means null = delete marker)
# Note: exact syntax varies by tool and client
kafka-console-producer.sh --broker-list localhost:9092 \
--topic user-profile-changelog \
--property parse.key=true --property key.separator=:
user-123:
On the monitoring side, track disk usage, log size per partition, segment count, and Log Cleaner health (thread backlog, processing rate). After a retention policy change, verify via broker logs and metrics that segments are rolling and being deleted as expected.
When things go wrong, re-check the topic's effective configuration (broker defaults plus topic overrides) and untangle how retention.ms, retention.bytes, segment.ms, delete.retention.ms, and min.cleanable.dirty.ratio interact. In particular, when initial sync fails under compact,delete, retention.ms is almost always too short.
CCAAK
問題 1
A topic is configured with cleanup.policy=compact,delete, retention.ms=48h, and delete.retention.ms=24h. A new consumer cannot bootstrap the latest state from this topic. Which cause is most plausible?
正解: A
Under compact,delete, the latest value per key is kept but segments older than retention.ms are still deleted. If retention.ms is too short, the history a new consumer needs disappears segment-by-segment before compaction finishes, so the latest state cannot be fully reconstructed. B is the opposite - short delete.retention.ms makes tombstones disappear sooner, not linger. C is unlikely to be a direct cause. D is wrong because the active segment is never deleted.
Which takes precedence, retention.ms or retention.bytes?
They are evaluated independently. The oldest segments are deleted as soon as either threshold is met, so it is common to set both a time and a size cap in tandem.
Does compact mean the data is retained forever?
No. compact only keeps the latest value for each key by thinning out older updates. With compact,delete the segments themselves are removed once retention.ms/bytes is hit. Even with compact alone, tombstones are cleaned up after delete.retention.ms expires.
What should I watch out for when switching from delete to compact (or compact,delete)?
Confirm that every message has a key, enable log.cleaner.enable, and give delete.retention.ms enough headroom. Revisit segment.ms/bytes if needed, and after the switch monitor Log Cleaner progress and disk behavior closely.
Practice with certification-focused question sets
無料で問題を解いてみるNicheeLab Editorial Team
NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.
Kafka Topics & Partitions: Distribution Fundamentals (2026)
How Kafka topics and partitions enable scale — ordering guar...
CCDAK Exam Guide: Confluent Certified Developer (2026)
Complete prep for the CCDAK exam — Producer/Consumer API, St...
CCAAK Exam Guide: Confluent Certified Administrator (2026)
Pass the CCAAK exam — cluster management, partitions, securi...
Kafka Replicas & ISR: Fault Tolerance Explained (2026)
Replica placement, in-sync replicas (ISR), leader election. ...
Kafka Offsets: Commit Modes & Consumer Position (2026)
Offset semantics — auto vs. manual commit, __consumer_offset...