✅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
假设有两个消费者 C1 和 C2,它们组成一个消费者组。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 的另一种消费位移管理方式。消费者可以在处理完消息后,显式地提交位移。通过设置 enable.auto.commit 为 false,并使用 commitSync() 或 commitAsync() 方法来手动提交位移。commitSync() 会阻塞等待位移提交成功,而 commitAsync() 会异步提交位移,不会阻塞消费者。
手动提交的方案,只有在消费者成功处理消息后,位移才会提交,这能确保消息处理的“至少一次”语义,避免消息丢失。开发者可以根据业务逻辑在合适的时机提交位移,比如处理完一批消息后,或者在处理出错时避免提交。
但是他的缺点就是需要你自己手动管理提交操作。
区别对比
| 特点 | 自动提交 | 手动提交 |
|---|---|---|
| 实现复杂度 | 简单,自动管理Offset | 复杂,需要手动控制Offset的提交 |
| 可靠性 | 较低,可能导致消息丢失或重复消费 | 高,能确保消息处理的可靠性 |
| 适用场景 | 对消息丢失不敏感的应用 | 需要保证消息处理成功的应用 |
| 提交频率控制 | 由 Kafka 控制,每 5 秒提交一次 | 完全由消费者控制,灵活可定制 |
| 性能 | 更高,提交较少 | 性能较低,提交频繁 |
| 使用方式 | 设置 enable.auto.commit=true |
设置 enable.auto.commit=false,手动提交 |
| 位移提交时机 | 每次消费后自动提交 | 消费者处理完消息后,手动提交 |
怎么选?
- 如果你的应用需要高可靠性,确保消息不丢失且每条消息至少处理一次:
- 使用手动提交,并确保在消息成功处理后才提交位移。你可以使用
commitSync()来同步提交,确保提交成功。
- 使用手动提交,并确保在消息成功处理后才提交位移。你可以使用
- 如果你不太关心消息丢失或重复消费(如日志、统计等):
- 使用自动提交,能够简化代码逻辑,提高性能。
- 在某些场景下,可以结合两者的优点:
- 自动提交:用于在处理速度至关重要时,允许 Kafka 定期提交位移。
- 手动提交:在处理完关键数据或一批消息后,显式提交位移,确保关键数据的可靠性。