保留与压缩——主题配置决定留下什么、丢弃什么
本实验在 VM 中运行
Ubuntu VM 上以 KRaft 单节点方式运行着 Apache Kafka 4.3.1
(localhost:9092)。broker 的保留检查周期(log.retention.check.interval.ms)被
缩短到了 10 秒,清理器等待时间(log.cleaner.backoff.ms)被缩短到了 5 秒,所以 1 分钟内就能看到删除和
压缩。首次启动大约需要 4 分钟。
目标
亲眼看到按时间保留(retention.ms)删除旧段,压缩(cleanup.policy=compact)
只为每个键保留最后一个值,max.message.bytes 拒绝大记录,
并亲手修改一个运行中主题的配置。
为什么重要
主题配置决定了“把什么保留多久”。默认保留是 7 天,而且是以
段为单位删除的,所以并不会因为过了 retention.ms 就立刻消失
——活动段永远不会被删除,段必须发生滚动(segment.ms)才能
删除。压缩是另一种保留。在带键的变更日志中,它一定会保留每个键的
最后一个值,所以从头读取就能还原当前状态。如果不了解这个
区别,就读不懂“明明删了却还在”“说是保留了却没了”这样的反馈。
步骤
- 用
retention.ms=20000、segment.ms=10000创建主题events。 - 放入
e1、e2、e3,等待至少 12 秒后放入e4,使段滚动,然后再等待大约 30 秒。当最前面的偏移量不再是 0 时,在/root/kafka/retention.txt中写两行:earliest=<가장 앞 오프셋>、latest=<로그 끝 오프셋>(占位符依次为最前面的偏移量、日志末尾偏移量)。 - 用
cleanup.policy=compact、segment.ms=10000、min.cleanable.dirty.ratio=0.01创建主题customers。 - 用解析键的方式放入
alice:v1、bob:v1、alice:v2、alice:v3,等待 12 秒以上后放入carol:v1,使段滚动。压缩结束后(大约 30 秒),从头连同键一起读取,并保存到/root/kafka/compacted.txt。alice必须只出现一次,值为v3。 - 用
max.message.bytes=1024创建主题photos,并尝试放入一行 2,000 个字符的内容(/root/kafka/big2k.txt)。把生产者的 stderr 保存到/root/kafka/toolarge.txt——它会被拒绝,记录必须是 0 条。 - 用
kafka-configs.sh把events的retention.ms改为86400000(不要重新创建主题)。 - 在
/root/kafka/topic-report.txt中写五行:events_retention_ms=86400000、customers_policy=compact、photos_max_bytes=1024、min_insync_default=1、three_broker_min_isr=2。
参考
- 主题配置在创建时用
--config 키=값(占位符依次为键、值)给出,之后则用kafka-configs.sh --bootstrap-server localhost:9092 --entity-type topics --entity-name <토픽> --alter --add-config 키=값(占位符依次为主题、键、值)给出。确认则用同一条命令的--describe。 - 偏移量范围:
kafka-get-offsets.sh --topic events --time earliest和--time latest。输出是토픽:파티션:오프셋(占位符依次为主题、分区、偏移量)。 - 确认压缩:
--from-beginning --timeout-ms 8000 --formatter-property print.key=true。压缩不会改变顺序,也不会改变偏移量(设计文档的保证)——alice v3位于它原来的位置(偏移量 3)。 - 最后两行是概念。主题配置文档中
min.insync.replicas的默认值是 1,文档举出的典型配置是副本因子 3、min.insync.replicas 2、acks=all。在单节点上无法重现那种交互,所以通过测验来确认。 - 常见错误 1:不让段滚动就干等。活动段既不会被删除,也不会被压缩——要有新记录进来,才会检查
segment.ms。 - 常见错误 2:看到压缩之后
alice仍出现多次,就当成失败。这只是清理器还没运行,10 秒后再读取一次。
只保留 20 秒的主题
用 retention.ms=20000、segment.ms=10000 创建主题 events。
--create --topic events --partitions 1 --config retention.ms=20000 --config segment.ms=10000。如果没有 segment.ms,默认 7 天内段都不会滚动,什么都删不掉。
旧段被删除
放入 e1、e2、e3,等待至少 12 秒后放入 e4,使段滚动,然后再等待大约 30 秒。当最前面的偏移量不再是 0 时,在 /root/kafka/retention.txt 中写两行:earliest=<가장 앞 오프셋>、latest=<로그 끝 오프셋>(占位符依次为最前面的偏移量、日志末尾偏移量)。
如果 kafka-get-offsets.sh --topic events --time earliest 变成了 events:0:3 这样,就说明第一个段已被删除。被删除的单位不是记录而是段,所以 e1 到 e3 会一起消失,而活动段中的 e4 会留下来。
只为每个键保留最后一个值的主题
用 cleanup.policy=compact、segment.ms=10000、min.cleanable.dirty.ratio=0.01 创建主题 customers。
--config cleanup.policy=compact --config segment.ms=10000 --config min.cleanable.dirty.ratio=0.01。dirty ratio 的默认值是 0.5,所以日志要有一半是重复的,清理器才会动——在实验中把它降到接近 0。
压缩之后 alice 只有一个
用解析键的方式放入 alice:v1、bob:v1、alice:v2、alice:v3,等待 12 秒以上后放入 carol:v1,使段滚动。压缩结束后(大约 30 秒),从头连同键一起读取,并保存到 /root/kafka/compacted.txt。alice 必须只出现一次,值为 v3。
活动段不会被压缩,所以必须用 carol 让它滚动。读取时加上 --formatter-property print.key=true,就会是 alice\tv3 的形式。如果 alice 还有三条,就说明清理器还没运行,10 秒后再读取一次。
过大的记录会被拒绝
用 max.message.bytes=1024 创建主题 photos,并尝试放入一行 2,000 个字符的内容(/root/kafka/big2k.txt)。把生产者的 stderr 保存到 /root/kafka/toolarge.txt——它会被拒绝,记录必须是 0 条。
head -c 2000 /dev/zero | tr '\0' y > big2k.txt; echo >> big2k.txt。如果 broker 因批次大小上限而拒绝,生产者日志里会打印 RecordTooLarge 一类的错误,而 kafka-get-offsets.sh 的结果是 0。
在运行中修改配置
用 kafka-configs.sh 把 events 的 retention.ms 改为 86400000(不要重新创建主题)。
kafka-configs.sh --bootstrap-server localhost:9092 --entity-type topics --entity-name events --alter --add-config retention.ms=86400000。这就是运维文档“Modifying topics”中的做法。用 --describe 确认。
用配置值来总结
在 /root/kafka/topic-report.txt 中写五行:events_retention_ms=86400000、customers_policy=compact、photos_max_bytes=1024、min_insync_default=1、three_broker_min_isr=2。
前三个用 kafka-configs.sh --describe 读取当前值再写入(评分器也是这样检查的)。后两个来自主题配置文档中的 min.insync.replicas 条目——它的默认值,以及副本因子为 3 时的典型取值。