Kafka的compact清理策略
Kafka 的 log compaction(日志压缩)清理策略 是一种“保留每个 Key 最新状态”的数据清理机制。它和普通的删除策略(delete)不同,它不是根据时间删除,而是根据 Key 的历史版本 删除旧消息。
它主要用于保存“最新状态”的场景,例如:
- 用户最新信息
- 商品最新库存
- 配置中心数据
- 服务状态
- CDC(数据库变更同步)
1. 为什么需要 compact?
假设一个 Topic:
user-profile
不断记录用户变化:
offset key value
--------------------------------
0 user1 Tom
1 user2 Jack
2 user1 Tom, age=20
3 user3 Alice
4 user1 Tom, age=21
如果使用普通 delete:
Kafka 只能按时间删除:
删除旧segment
可能导致:
user1 的所有历史都消失
但是业务通常只关心:
user1 当前状态是什么?
所以 compact:
保留:
offset 1:
user2 = Jack
offset 3:
user3 = Alice
offset 4:
user1 = Tom, age=21
删除:
offset 0:
user1 = Tom
offset 2:
user1 = Tom, age=20
2. compact 的核心规则
一句话:
对同一个 Partition 内,相同 Key 的消息,只保留最新的一条。
注意三个关键词:
① 同一个 Partition
Kafka 保证:
同一个key
|
v
同一个partition
所以 Kafka 可以局部压缩。
② 相同 Key
例如:
key=A
offset 10 value=x
offset 20 value=y
offset 30 value=z
compact 后:
offset 30 value=z
③ 最新一条
Kafka 根据:
offset
判断新旧。
offset越大:
越新
3. compact 的执行流程
Kafka 有后台线程:
LogCleaner
流程:
Partition Log
offset:
0 -------- 100 -------- 200
clean dirty
第一步:扫描 dirty 区域
建立一个 Key 索引:
例如:
原数据:
offset key
100 A
101 B
102 A
103 C
构建:
Key 最新offset
A 102
B 101
C 103
这个叫:
offset map
第二步:扫描旧数据
发现:
offset 50
key=A
但是:
offset map:
A -> 102
说明:
50 是旧版本
删除。
第三步:生成新的 segment
原:
segment:
A(old)
B
A(new)
C
变成:
segment:
B
A(new)
C
4. clean 和 dirty 区域
Kafka 不会每次扫描整个 Partition。
它维护:
clean offset
例如:
offset
0 ---------------- 100 ---------------- 300
clean dirty
含义:
| 区域 | 含义 |
|---|---|
| clean | 已经压缩过 |
| dirty | 新写入,可能有重复key |
只有 dirty 达到条件才执行 compact。
5. compact 的触发条件
主要参数:
开启清理线程
log.cleaner.enable=true
默认开启。
清理比例
log.cleaner.min.cleanable.ratio=0.5
例如:
Partition:
100GB
其中:
dirty=60GB
比例:
60%
超过:
50%
触发 compact。
清理线程数量
log.cleaner.threads=1
多个 Partition 可以并行清理。
6. compact 不会删除所有旧数据
这是一个重点。
Kafka compact 有一个保留窗口。
例如:
offset:
0 1 2 3 4 5 6
A A A B C A
compact 后:
B
C
A(最新)
但是:
在清理过程中:
旧消息可能暂时存在
因为 compact 是:
异步后台任务
不是实时删除。
7. Tombstone(删除标记)
compact 支持删除 Key。
例如:
原:
key=user1
value=Tom
删除:
Producer发送:
key=user1
value=null
Kafka保存:
user1=null
这个特殊消息叫:
tombstone
compact 后:
user1不存在
例如:
offset 10:
user1=Tom
offset 20:
user1=null
压缩:
删除user1
8. compact 和 delete 可以同时使用
生产环境很常见:
log.cleanup.policy=compact,delete
含义:
第一层:
compact
保证:
一个key只有最新状态
第二层:
delete
保证:
数据不会无限增长
例如:
用户状态:
user1 最新信息
保留。
但是:
5年前没人更新的数据
删除。
9. compact 适合什么场景?
非常适合
1. 状态存储
例如:
user-service-state
userId -> userInfo
2. 配置中心
例如:
config-topic
db.url -> xxx
timeout -> 5000
3. CDC同步
数据库:
update user
Kafka:
key=userId
value=row
消费者只需要最新行。
10. 不适合 compact 的场景
例如:
订单流水:
订单创建
支付
发货
退款
完成
如果:
key=orderId
compact:
可能只剩:
完成
丢失:
创建
支付
发货
这种场景应该:
cleanup.policy=delete
保留完整事件流。
11. delete vs compact 对比
| delete | compact | |
|---|---|---|
| 依据 | 时间/大小 | key |
| 删除对象 | segment | 旧record |
| 保留最新状态 | ❌ | ✅ |
| 保持完整历史 | ✅ | ❌ |
| 适合日志 | ✅ | ❌ |
| 适合状态 | ❌ | ✅ |
| 后台线程 | LogManager | LogCleaner |
配置示例: https://blog.tongqing.asia/detail/301/
总结:
Kafka compact 清理策略本质是一个 按 Key 做状态合并的后台整理机制。Kafka 保证同一个 Key 在同一个 Partition,通过 LogCleaner 建立 Key→最新 offset 的索引,删除旧版本消息,只保留最新状态。它不是删除历史事件,而是把事件流压缩成当前状态快照。
评论(1)
tongqing
要注意的是,compact这些清理策略并不保证实时清理。 同一时刻是可能出现一个key保留多个值的情况的
2026年07月08日 11:07