全书目录

第二十篇:Kafka 完全指南 —— 城市事件广播总线宇宙

第六章:消费位点 —— Kafka 不是“消息删不删”,而是“你读到哪了”

2 分钟 485 字 第 373 / 962 个阅读单元

这是 Kafka 和很多消息系统最不同的地方。

在很多队列系统里,你容易形成一种直觉:

text
消息被消费了 -> 消息就没了

Kafka 不是这样。

Kafka 的核心问题不是“删消息”,而是:

每个 consumer group 现在读到哪一个 offset 了。

这个“读到哪”,就是消费位点,通常叫:

  • current offset
  • committed offset
#committed offset 是什么

它表示:

这个 consumer group 下次从哪里继续读。

而且有个非常关键的细节:

提交的 offset,应该是“下一条要读的 offset”,不是“刚处理完那条的 offset”。

所以代码里常见的是:

java
consumer.commitSync(Map.of(
    new TopicPartition(record.topic(), record.partition()),
    new OffsetAndMetadata(record.offset() + 1)
));

注意这里的 + 1

#为什么要在“处理成功后”再提交

看这条时间线:

text
poll 拉到消息 -> 执行业务处理 -> commit offset

如果你在处理前就提交:

text
poll -> commit -> 处理时宕机

那就可能丢消息,因为 Kafka 以为你已经读过了。

如果你在处理后提交:

text
poll -> 处理成功 -> commit

那宕机时最坏情况通常是:

  • 这条消息会被重新读一次
  • 也就是重复消费

所以大多数系统宁可接受“可能重复”,也不接受“直接丢失”。

这就是 Kafka 里最常见的处理语义来源:

at-least-once(至少一次)