TT Lab
开始
学习 学习路径 课程

订单重复到达,又消失了一次

保留与压缩——主题配置决定留下什么、丢弃什么

在 TT Lab 中继续学习

本实验在 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)才能 删除。压缩是另一种保留。在带键的变更日志中,它一定会保留每个键的 最后一个值,所以从头读取就能还原当前状态。如果不了解这个 区别,就读不懂“明明删了却还在”“说是保留了却没了”这样的反馈。

步骤

  1. 用 retention.ms=20000、segment.ms=10000 创建主题 events。
  2. 放入 e1、e2、e3,等待至少 12 秒后放入 e4,使段滚动,然后再等待大约 30 秒。当最前面的偏移量不再是 0 时,在 /root/kafka/retention.txt 中写两行:earliest=<가장 앞 오프셋>、latest=<로그 끝 오프셋>(占位符依次为最前面的偏移量、日志末尾偏移量)。
  3. 用 cleanup.policy=compact、segment.ms=10000、min.cleanable.dirty.ratio=0.01 创建主题 customers。
  4. 用解析键的方式放入 alice:v1、bob:v1、alice:v2、alice:v3,等待 12 秒以上后放入 carol:v1,使段滚动。压缩结束后(大约 30 秒),从头连同键一起读取,并保存到 /root/kafka/compacted.txt。alice 必须只出现一次,值为 v3。
  5. 用 max.message.bytes=1024 创建主题 photos,并尝试放入一行 2,000 个字符的内容(/root/kafka/big2k.txt)。把生产者的 stderr 保存到 /root/kafka/toolarge.txt——它会被拒绝,记录必须是 0 条。
  6. 用 kafka-configs.sh 把 events 的 retention.ms 改为 86400000(不要重新创建主题)。
  7. 在 /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。

参考

只保留 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 时的典型取值。