简介
Kafka 保存记录的行为独立于谁已经读取了这些记录。消费者组还需要记住自己的进度,让后续进程能够继续读取,而不用从头开始。已提交 offset 是该组在一个分区中下一条应读取的位置,不是最后一条记录的编号。
你将读取四条预置记录中的两条,检查已提交进度和 lag,使用同一消费者组继续读取,并与新组进行比较。随后,你将在原组非活跃时预览并执行重置,再次读取保留记录。Topic 只有一个分区,方便理解这些位置。
这个独立实验提供了 Broker、四条记录和一个辅助工具,该工具会轮询真实的协调器状态,直到出现预期的 offset。你只需掌握基本终端操作,无需编写 Python 代码或设置服务。辅助工具不会修改 offset 或编造报告。请使用终端完成实验。
读取两条记录并检查已提交的下一个位置
这一步,你将把有数量限制的读取与消费者组实际保存的位置联系起来。检查准备好的四个值:
cd /home/labex/project
cat /home/labex/project/data/progress-events.txt
它们在这个新建的单分区 Topic 中的 offset 为 0 到 3。名为 orders-review 的新组没有保存过位置,因此 --from-beginning 会为首次读取选择保留数据的起点。
--command-property 将配置值传给消费者客户端,而不是改变事件显示格式。本练习中的控制台客户端会自动提交进度。max.poll.records=1 将每次 poll 返回的记录限制为一条,避免显示两条记录后停止时,位置已经前进到一个更大返回批次的末尾。提交间隔控制周期性提交行为;客户端关闭时也会完成正常的进度处理。你将检查实际结果,而不假定某个固定延迟:
kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic orders-progress --group orders-review --from-beginning --max-messages 2 --timeout-ms 30000 --command-property enable.auto.commit=true --command-property auto.commit.interval.ms=1000 --command-property max.poll.records=1 > /home/labex/project/output/first-two.txt
cat /home/labex/project/output/first-two.txt
预期会出现两条 created 事件,然后客户端退出。使用组名和预期的下一个 offset 运行提供的有限轮询辅助工具:
/home/labex/project/tools/wait-group-offset orders-review 2 > /home/labex/project/output/after-first.txt
cat /home/labex/project/output/after-first.txt
辅助工具反复查询真实消费者组的状态,直到其已提交 offset 为 2,或在截止时间后失败。它不会提交或重置任何内容。找到分区 0 对应的 CURRENT-OFFSET 2、LOG-END-OFFSET 4 和 LAG 2。有数量限制的客户端退出后,提示该组没有活跃成员是正常的;它保存的进度仍然存在。
Offset 2 表示下一次读取从第三条存储记录开始。末尾 offset 4 是现有四条记录之后的下一个位置;在这个简单且状态稳定的例子中,lag 4 − 2 = 2 表示剩余记录数量。前两条记录并未被删除。
恢复同一消费者组并与新组比较
这一步,你将预测消费者组从已保存位置会收到哪些记录。再次运行同一组,有意保留从起点开始的选项:
kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic orders-progress --group orders-review --from-beginning --max-messages 2 --timeout-ms 30000 --command-property enable.auto.commit=true --command-property auto.commit.interval.ms=1000 --command-property max.poll.records=1 > /home/labex/project/output/resumed-two.txt
cat /home/labex/project/output/resumed-two.txt
预期会出现两条 paid 事件,而不是之前的 created 事件。--from-beginning 在没有有效已提交 offset 时提供起始策略;它不会覆盖该组有效的已保存 offset 2。通过真实的协调器状态确认读取已完成:
/home/labex/project/tools/wait-group-offset orders-review 4 > /home/labex/project/output/after-resume.txt
cat /home/labex/project/output/after-resume.txt
预期已提交 offset 为 4,末尾 offset 为 4,lag 为 0。现在预测另一个名为 orders-independent 的组会如何读取。它没有保存过位置,并且独立于 orders-review,因此从起点读取应返回全部四条保留记录:
kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic orders-progress --group orders-independent --from-beginning --max-messages 4 --timeout-ms 30000 --command-property enable.auto.commit=true --command-property auto.commit.interval.ms=1000 --command-property max.poll.records=1 > /home/labex/project/output/new-group-all.txt
cat /home/labex/project/output/new-group-all.txt
/home/labex/project/tools/wait-group-offset orders-independent 4 > /home/labex/project/output/new-group-position.txt
cat /home/labex/project/output/new-group-position.txt
预期会看到全部四个值,以及新组自身的已提交 offset 4。两个组可以经历不同的读取过程,最终都到达末尾。一个组的进度不会移动另一个组的起始位置,两个组的消费也都没有删除 Topic 中的记录。
接下来,你将有意修改原组保存的位置,而不是把起点选项当作回退命令。
预览非活跃组的重置并重放历史记录
这一步,你将只重置 orders-review。其有数量限制的消费者已经退出,因此该组没有活跃成员。如果误留了该组的其他成员正在运行,请在重置前将其停止;活跃消费者可能继续改变进度。
--reset-offsets 选择进度管理操作,--topic 限定操作范围,--to-earliest 选择保留数据的起点。先使用 --dry-run 预览建议的新 offset,而不应用修改:
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group orders-review --reset-offsets --to-earliest --topic orders-progress --dry-run > /home/labex/project/output/reset-preview.txt
cat /home/labex/project/output/reset-preview.txt
预期建议的 NEW-OFFSET 为 0。确认预览没有改变当前保存的位置:
/home/labex/project/tools/wait-group-offset orders-review 4 > /home/labex/project/output/after-preview.txt
cat /home/labex/project/output/after-preview.txt
现在使用 --execute 应用限定范围的重置:
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group orders-review --reset-offsets --to-earliest --topic orders-progress --execute
/home/labex/project/tools/wait-group-offset orders-review 0 > /home/labex/project/output/after-reset.txt
cat /home/labex/project/output/after-reset.txt
实际已提交的下一个 offset 现在应为 0,末尾 offset 为 4,lag 为 4。记录仍在原处;只有该组保存的位置发生了变化。利用现在有效的已提交起点再次读取全部四条记录,不依赖默认起始策略选项:
kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic orders-progress --group orders-review --max-messages 4 --timeout-ms 30000 --command-property enable.auto.commit=true --command-property auto.commit.interval.ms=1000 --command-property max.poll.records=1 > /home/labex/project/output/replayed-all.txt
cat /home/labex/project/output/replayed-all.txt
/home/labex/project/tools/wait-group-offset orders-review 4 > /home/labex/project/output/after-replay.txt
cat /home/labex/project/output/after-replay.txt
预期会再次看到原来的四个值和已提交 offset 4。orders-independent 仍应保留自身已完成的位置;此次重置没有让那个组回退。
重放会有意再次读取已有记录。在处理记录与提交进度之间发生崩溃,也可能导致记录再次交付。这个控制台练习演示的是读取位置,并非原子化的文件写入与提交事务,也不保证端到端恰好一次。后续 Python 实验会明确展示处理与提交的顺序。
总结
你检查了已提交的下一个 offset 和 lag,在设置了默认起点的情况下仍从保存进度继续读取,并与一个独立组进行了比较。在消费者组非活跃时预览并执行重置,让你能够有意重放,而 Topic 中的真实记录保持不变。接下来,你将观察同组的多个成员如何共享分区,以及成员离开后如何重新分配其工作。



