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 对比

deletecompact
依据时间/大小key
删除对象segment旧record
保留最新状态
保持完整历史
适合日志
适合状态
后台线程LogManagerLogCleaner

配置示例: https://blog.tongqing.asia/detail/301/

总结:

Kafka compact 清理策略本质是一个 按 Key 做状态合并的后台整理机制。Kafka 保证同一个 Key 在同一个 Partition,通过 LogCleaner 建立 Key→最新 offset 的索引,删除旧版本消息,只保留最新状态。它不是删除历史事件,而是把事件流压缩成当前状态快照。
文章标签:

评论(1)

用户头像
tongqing

要注意的是,compact这些清理策略并不保证实时清理。 同一时刻是可能出现一个key保留多个值的情况的

2026年07月08日 11:07