✅Kafka 中的Offset是什么?

✅Kafka 中的Offset是什么?

典型回答

在 Kafka 中, 每个分区中的每条消息都有一个唯一的编号,称为该消息的“偏移量”(Offset)。偏移量是从 0 开始的整数,表示该分区中消息的顺序。例如,分区中的第一条消息的位移为 0,第二条为 1,依此类推。

Offset也是 Kafka 消费者在某个分区中消费消息的位置标识,即通过位移就知道自己消费到哪了(这里记录的是 Consumer 要消费的下一条消息的位移!!!)。

假设一个parition中有 10 条消息,从 0 到 9。 假设Consumer 已消费了6条消息,这就说明该 Consumer 消费了位移为 0 到 5 的消息,此时 Consumer 的位移应该是 6,而不是5。

Kafka的consumer还会通知kafka自己的消费进度,避免万一消费过程中挂了,下次不知道该从哪开始消费了。所以有两种方式来管理消费位移:

  • 自动提交:消费者会定期自动提交它们的消费位移。这样 Kafka 知道每个消费者上次消费到哪里。
  • 手动提交:消费者可以选择在特定时刻(例如,成功处理完消息后)手动提交位移,确保只有在消息成功处理后才更新位移。

位移、偏移量、都是offset,没有什么固定的叫法和翻译,只不过我认为在队列中叫偏移量,在消费者中叫位移更合适。

假设有一个 Kafka 主题 my_topic,它有 3 个分区,每个分区中有 5 条消息。

  • 分区 0:msg_0, msg_1, msg_2, msg_3, msg_4
  • 分区 1:msg_0, msg_1, msg_2, msg_3, msg_4
  • 分区 2:msg_0, msg_1, msg_2, msg_3, msg_4

假设有两个消费者 C1C2,它们组成一个消费者组。C1 负责消费分区 0 和分区 1,C2 负责消费分区 2。

  • 如果 C1 在消费分区 0 时已处理到 msg_2(位移为 2),则下一次它会从 msg_3(位移为 3)继续消费。
  • 同样,C2 在消费分区 2 时已处理到 msg_1(位移为 1),则下一次它会从 msg_2(位移为 2)继续消费。

扩展知识

手动提交&自动提交

自动提交

自动提交是 Kafka 默认的方式,消费者会周期性地自动提交它们消费的位移。Kafka 提供了一个配置项:enable.auto.commit,默认情况下它是 true,即开启自动提交。

在自动提交的情况下,在消费者每次拉取数据后,Kafka 会自动提交位移。默认情况下,位移提交间隔是每 5 秒(配置项:auto.commit.interval.ms),也就是说,消费者每 5 秒就会提交一次位移。

自动提交配置相对简单,不需要手动控制位移的提交。而且不需要频繁的处理一条消息就提交位移,减少了网络延迟和操作负担。

但是他也有缺点,那就是有可能会出现重复消费和消息丢失的情况,因为自动提交的这个过程可能会把未消费成功的位移提交掉,也可能会未来的及提交消息就重投了。(具体的场景在自动提交原理中介绍。)

自动提交通常不能保证消息的“至少一次”或“恰好一次”语义,尤其在消费者崩溃的情况下。

✅Kafka怎么保证消费只消费一次的?

手动提交

手动提交是 Kafka 的另一种消费位移管理方式。消费者可以在处理完消息后,显式地提交位移。通过设置 enable.auto.commitfalse,并使用 commitSync()commitAsync() 方法来手动提交位移。commitSync() 会阻塞等待位移提交成功,而 commitAsync() 会异步提交位移,不会阻塞消费者。

手动提交的方案,只有在消费者成功处理消息后,位移才会提交,这能确保消息处理的“至少一次”语义,避免消息丢失。开发者可以根据业务逻辑在合适的时机提交位移,比如处理完一批消息后,或者在处理出错时避免提交。

但是他的缺点就是需要你自己手动管理提交操作。

区别对比

特点 自动提交 手动提交
实现复杂度 简单,自动管理Offset 复杂,需要手动控制Offset的提交
可靠性 较低,可能导致消息丢失或重复消费 高,能确保消息处理的可靠性
适用场景 对消息丢失不敏感的应用 需要保证消息处理成功的应用
提交频率控制 由 Kafka 控制,每 5 秒提交一次 完全由消费者控制,灵活可定制
性能 更高,提交较少 性能较低,提交频繁
使用方式 设置 enable.auto.commit=true 设置 enable.auto.commit=false
,手动提交
位移提交时机 每次消费后自动提交 消费者处理完消息后,手动提交

怎么选?

  1. 如果你的应用需要高可靠性,确保消息不丢失且每条消息至少处理一次
    • 使用手动提交,并确保在消息成功处理后才提交位移。你可以使用 commitSync() 来同步提交,确保提交成功。
  2. 如果你不太关心消息丢失或重复消费(如日志、统计等)
    • 使用自动提交,能够简化代码逻辑,提高性能。
  3. 在某些场景下,可以结合两者的优点
    • 自动提交:用于在处理速度至关重要时,允许 Kafka 定期提交位移。
    • 手动提交:在处理完关键数据或一批消息后,显式提交位移,确保关键数据的可靠性。