Kafka - 4 Kafka的副本同步机制
- 副本同步机制
- offset
- [高水位(Height WaterMark)](#高水位(Height WaterMark))
-
- 什么是高水位
- 高水位的作用
- 高水位更新机制
-
- Leader副本与Follower副本的不同操作
-
- [Leader 副本](#Leader 副本)
- [Follower 副本](#Follower 副本)
- [Leader Epoch](#Leader Epoch)
- 总结
- 往期推荐
副本同步机制
什么是副本同步机制
副本同步机制是分布式系统中确保数据一致性和高可用性的核心机制,通过主副本(Leader)与从副本(Follower)的协同工作,实现数据的实时复制和故障自动转移。
在Kafka中的同步流程
- 数据写入:Producer发送消息至Leader,Leader写入本地日志后,异步复制到所有Follower。
- 高水位(HW)控制:HW是ISR中最小的LEO(Log End Offset),消费者只能读取到HW位置,确保数据一致性。
- 故障恢复:Leader宕机时,从ISR中选举新Leader,Follower继续同步新Leader数据。
offset
什么是offset
在Kafka中,每一个分区中的消息都会有一个唯一的编号,这个编号被称为"偏移量"。Kafka的消费者可以通过offset来获取到自己当前的消费位置。
offset提交方式
自动提交
Kafka的默认提交方式就是自动提交,在自动提交的情况下,消费者每次拉取数据之后,Kafka会自动提交位移。
- enable.auto.commit // 提交方式的配置项,默认为true,自动提交
- auto.commit.interval.ms // 提交位移时间的配置项,默认为5000,即5秒提交一次。
优点:配置相对简单,不需要手动控制位移的提交,减少网络延迟与操作负担
缺点:有可能出现重复消费和消息丢失的情况,自动提交也可能会将未消费成功的位移提交掉。
手动提交
当消费者处理完消息之后,可以使用 commitSync()或者commitAsync()方法来手动提交位移, commitSync()会阻塞等待位移提交成功,commitAsync()会异步提交位移,不会阻塞。
优点:只有当消费者成功处理消息之后位移才会被提交,这样可以确保消息至少能被处理一次,避免消息丢失。
缺点:需要自己在合适的时候进行手动管理提交操作。
主要区别
| 复杂度 | 可靠性 | 性能 | 提交控制频率 | |
|---|---|---|---|---|
| 自动提交 | 简单 | 较低,容易出现消息丢失或者重复消费 | 高 | 由Kafka控制,默认5s |
| 手动提交 | 较为复杂,需要自己进行手动管理 | 较高,能保证消息处理的可靠性 | 低,频繁提交导致效率较低 | 可以自己手动管理 |
高水位(Height WaterMark)
什么是高水位
高水位:通过标识了一个特定的消息偏移量来管理消费者的进度和保证数据的可靠性。
高水位的作用
在Kafka中,高水位主要有以下两个作用
- 定义消息可见性,告诉我们哪些消息是可以进行消费的
- 帮助Kafka完成副本同步的机制
每个Kafka副本对象都包含两个重要的属性: LEO和HW。
- LEO:Log End Offset,他是日志最后消息的偏移量,标识了日志文件中下一条待写入消息的Offset。
- HW:Height WaterMark,对于同一个副本对象,HW值永远不会超越ELO。
高水位更新机制
通过上文,我们知道了每个副本对象都保存了一组HW和LEO,但是实际在Leader副本所在的Broker0中,还保存了其他Follower副本的LEO值,这些副本也被成为远程副本。

- 更新时
- Broker0上的Leader副本的HW与LEO,Follower副本的LEO
- Broker1上的Follower副本的HW与ELO
在Broker0上保存其余Follower副本的原因:帮助Leader副本确定分区高水位
Leader副本与Follower副本的不同操作
Leader 副本
- 处理生产者的逻辑如下:
- 写入消息到磁盘
- 更新 LEO 值
- 更新分区高水位值
- 获取 leader 副本所在 Broker 保存的所有远程副本 LEO 值,如:LEO-1、LEO-2、LEO-3...
- 获取 Leader 副本的高水位值:currentHW
- 更新高水位为:HW = Math.max(currentHW,Math.min(LEO-1,LEO-2,LEO-3...));
- 处理 Follower 副本拉取消息的逻辑如下:
- 读取磁盘(页缓存)中的消息数据
- 使用 Follower 副本发送消息请求中的位移值更新远程副本 LEO 值
- 更新分区高水位值(同上)
Follower 副本
- 从 Leader 拉取消息的处理逻辑如下:
- 写入消息到本地磁盘,更新 LEO 值
- 更新高水位
- 获取 Leader 发送的高水位值:currentHW
- 获取步骤 2 中更新的 LEO 值:currentLEO
- 更新高水位为:HW = Math.min(currentHW, currentLEO);
Leader Epoch
当Leader副本发生故障的时候,Kafka会选择一个新的Leader副本,在切换副本的过程中,我们需要保证数据的一致性,为了实现这个目标,Kafka引入了Leader Epoch 的概念。
Leader Epoch是一对值:(epoch,offset)
- epoch:代表当前 leader 的版本号,从0开始,当 Leader 变更过一次时,我们的 epoch 就会 +1
- offset:该 epoch 版本的 Leader 写入第一条消息的位移
在副本切换的过程中,Kafka会从ISR中选举出一个新的Follower副本作为新的Leader副本,被选中的新的Leader副本会增加自己的Leader Epoch,使其大于之前的Leader Epoch,表示进入了一个新的任期,新的Leader副本会验证旧Leader副本的Leader Epoch与高水位,如果旧Leader副本的Leader Epoch小于等于新Leader副本的Leader Epoch,并且旧Leader副本的高水位小于等于新Leader副本的高水位 ,就证明这个新Leader副本可以正常使用,此时,新的Leader副本将会开始从ISR中的一部分副本复制数据,确保新Leader副本上的数据与旧Leader副本上的一致。
当新Leader副本复制了旧Leader副本的所有数据,并达到了与旧Leader副本相同的高水位,副本切换过程就完事了。
总结
- offset总共有两种提交方式,一般比较推荐使用手动提交的方式。
- 高水位的作用
- 定义消息可见性
- 帮助Kafka完成副本同步
- 在分区高水位一下的消息被认为是已提交消息,消费者只能读取已提交消息。
- 日志末端位移(LEO) :表示副本写入下一条消息的位移值。
- Leader Epoch:由两部分数据组成(Epoch,offset)
- Epoch(单调增加的版本号):每当副本领导权发生变更时,都会增加该版本号。小版本号的 Leader被认为是过期Leader。
- offset(起始位移) :Leader副本 在该 Epoch 值上写入的首条消息的位移。
往期推荐
Kafka-1 基本概念
Kafka-2 Kafka的特点
番外 - 何为零拷贝
Kafka -3 Kafka是如何保证消息会被至少消费一次的