探究Kafka原理-6.CAP理论实践(下)

简介: 探究Kafka原理-6.CAP理论实践

探究Kafka原理-6.CAP理论实践(上):https://developer.aliyun.com/article/1413725


解决“消费者所见不一致” (消费者只允许看到 HW 以下的 message)



解决“分区副本数据最终不一致” (follower 数据按HW截断)


high watermark


代表数据在多副本备份的进度


hw就代表offset < hw的数据已经在所有isr副本间全部备份完毕。


所以,offset < hw的数据,让消费者可见,是相对安全的


HW 方案的天生缺陷


如前所述,看似 HW 解决了“分区数据最终不一致”的问题,以及“消费者所见不一致”的问题,但其实,这里面存在一个巨大的隐患,导致:


“分区数据最终不一致”的问题依然存在


producer 设置 acks=all 后,依然有可能丢失数据的问题


产生如上结果的根源是:HW 高水位线的更新,与数据同步的进度,存在迟滞!

Step 1:leader 和 follower 副本处于初始化值,follower 副本发送 fetch 请求,由于 leader 副本没有数据,因此不会进行同步操作;


Step 2:生产者发送了消息 m1 到分区 leader 副本,写入该条消息后 leader 更新 LEO = 1;


Step 3:follower 发送 fetch 请求,携带当前最新的 offset = 0,leader 处理 fetch 请求时,更新 remote LEO = 0,对比 LEO 值最小为 0,所以 HW = 0,leader 副本响应消息数据及 leader HW = 0 给follower,follower 写入消息后,更新 LEO 值,同时对比 leader HW 值,取最小的作为新的 HW 值,此时 follower HW = 0,这也意味着,follower HW 是不会超过 leader HW 值的。


Step 4:follower 发送第二轮 fetch 请求,携带当前最新的 offset = 1,leader 处理 fetch 请求时,更新 remote LEO = 1,对比 LEO 值最小为 1,所以 HW = 1,此时 leader 没有新的消息数据,所以直接返回 leader HW = 1 给 follower,follower 对比当前最新的 LEO 值 与 leader HW 值,取最小的作为新的 HW 值,此时 follower HW = 1。


从以上步骤可看出,leader 中保存的 remote LEO 值的更新(也即 HW 的更新)总是需要额外一轮fetch RPC 请求才能完成,这意味着在 leader 切换过程中,会存在数据丢失以及数据不一致的问题!


HW 会产生数据丢失和副本最终不一致问题


数据丢失的问题(即使 produce 设置 acks=all,依然会发生)

注意回顾:leader 中的 HW 值是在 follower 下一轮 fetch RPC 请求中完成更新的


如上图所示:


  • 状态起始: B 为 leader,A 为 follower; 最新消息 m2 已同步,但 B 的 HW 比 A 的HW 大
  • A 在此时崩溃(即 follower 没能通过下一轮请求来更新 HW 值)
  • A 重启时,会自动将 LEO 值调整到之前的 HW 值,即会进行日志截断
  • B 重启后,会从 向 A 发送 fetch 请求,收到 fetch 响应后,拿到 HW 值,并更新本地 HW 值,这时 B 会做日志截断,因此,offsets = 1 的消息被永久地删除了。


副本间数据最终不一致的问题(即使 produce 设置 acks=all,依然会发生)

如上图所示:


  • 状态起始: A 为 leader,B 为 follower; 最新消息 m2 已同步,但 B 的 HW 比 A 的 HW 小
  • A 在此时崩溃(即 follower 没能通过下一轮请求来更新 HW 值)
  • B 先重启,会自动将 LEO 值调整到之前的 HW 值,即会进行日志截断,并在此刻接收了新的消息 m3,HW 随之上升为 2
  • 然后,A 重启上线,会从 向 B 发送 fetch 请求,收到 fetch 响应后,拿到 HW 值,并更新本地 HW 值,发现不需要截断,从而已经产生了“副本间数据最终不一致”!


只要新一届 leader 在老 leader 重启上线前,接收了新的数据,就可能发生上图中的场景,根源也在于HW 的更新落后于数据同步进度


Leader-Epoch 机制的引入


为了解决 HW 更新时机是异步延迟的,而 HW 又是决定日志是否备份成功的标志,从而造成数据丢失和数据不一致的现象,Kafka 引入了 leader epoch 机制;


在每个副本日志目录下都创建一个 leader-epoch-checkpoint 文件,用于保存 leader 的 epoch 信息


leader-epoch 的含义


如下,leader epoch 长这样:

它的格式为 (epoch offset),epoch 指的是 leader 版本,它是一个单调递增的一个正整数值,每次 leader变更,epoch 版本都会 +1,offset 是每一代 leader 写入的第一条消息的位移值,比如:

(0,0)
(1,300)

以上第 2 个版本是从位移 300 开始写入消息,意味着第一个版本写入了 0-299 的消息。


这里面记录信息的本质试:从哪个offset开始的数据,是从那届leader写入的。


leader epoch 具体的工作机制:


  • 当副本成为 leader 时:

这时,如果此时生产者有新消息发送过来,会首先更新 leader epoch 以及 LEO ,并添加到leader-epoch-checkpoint 文件中


  • 当副本变成 follower 时

发送 LeaderEpochRequest 请求给 leader 副本,该请求包括了 follower 中最新的 epoch 版本;leader 返回给 follower 的响应中包含了一个 LastOffset,如果 follower last epoch = leader last epoch(纪元相同),则 LastOffset = leader LEO,否则取 大于 follower last epoch 中最小的 leader epoch 的 start offset值;


举个例子:假设 follower last epoch = 1,此时 leader 有 (1, 20) (2, 80) (3, 120),则 LastOffset = 80;


follower 拿到 LastOffset 之后,会对比当前 LEO 值是否大于 LastOffset,如果当前 LEO 大于LastOffset,则从 LastOffset 截断日志;follower 开始发送 fetch 请求给 leader 保持消息同步。


leader epoch 如何解决 HW 的备份缺陷


解决数据丢失:


如上图所示:


A 重启之后,发送 LeaderEpochRequest 请求给 B,由于 B 还没追加消息,此时 epoch = request epoch = 0,因此返回 LastOffset = leader LEO = 2 给 A


A 拿到 LastOffset 之后,发现等于当前 LEO 值,故不用进行日志截断。就在这时 B 宕机了,A 成为 leader,在 B 启动回来后,会重复 A 的动作,同样不需要进行日志截断,数据没有丢失。


解决数据最终不一致问题:


如上图所示:


  • A 和 B 同时宕机后,B 先重启回来成为分区 leader,这时候生产者发送了一条消息过来,leader epoch 更新到 1
  • 此时 A 启动回来后,发送 LeaderEpochReques(t follower epoch = 0)给 B,B 判断 follower epoch不等于最新的 epoch,于是找到大于 follower epoch 最小的 epoch = 1,即 LastOffset = epoch start offset = 1
  • A 拿到 LastOffset 后,判断小于当前 LEO 值,于是从 LastOffset 位置进行日志截断,接着开始发送 fetch 请求给 B 开始同步消息,避免了消息不一致/离散的问题。


HW的时候,计算producer把acks = all,依然会丢数据,因为它是依赖HW来进行数据截断的。


而HW的更新是相对于数据同步进度落后一轮请求的。


而现在,acks = all依赖于 leader epoch的话,不会再有数据丢失发生了,也不会再有消息不一致情况了。


LEO/HW/LSO 等相关术语速查


LEO:(last end offset)就是该副本中消息的最大偏移量的值+1


HW:(high watermark)各副本中 LEO 的最小值。这个值规定了消费者仅能消费 HW 之前的数据


LEO 与 HW 与数据一致性密切相关;

如图,各副本中最小的 LEO 是 3,所以 HW 是 3,所以,消费者此刻最多能读Msg2;


不清洁选举[了解]


不清洁选举,是指允许“非 ISR 副本”可以被选举为 leader;非 ISR 副本被选举为 leader,将极大增加数据丢失及数据不一致的可能性!由参数 unclean.leader.election.enable=false(默认) 控制;


初始状态: follower2 严重落后于 leader,并且不属于 ISR 副本

此刻,所有 ISR 副本宕机

Follower2 成为新的 leader,并接收数据

之前宕机副本重启,按照最新 leader 的最新 leo 进行截断,产生数据丢失及不一致

目录
相关文章
|
3月前
|
消息中间件 存储 负载均衡
kafka核心原理,藏在这 16 张图里
kafka核心原理,藏在这 16 张图里
25 0
|
1月前
|
消息中间件 存储 负载均衡
Kafka【付诸实践 01】生产者发送消息的过程描述及设计+创建生产者并发送消息(同步、异步)+自定义分区器+自定义序列化器+生产者其他属性说明(实例源码粘贴可用)【一篇学会使用Kafka生产者】
【2月更文挑战第21天】Kafka【付诸实践 01】生产者发送消息的过程描述及设计+创建生产者并发送消息(同步、异步)+自定义分区器+自定义序列化器+生产者其他属性说明(实例源码粘贴可用)【一篇学会使用Kafka生产者】
168 4
|
3月前
|
消息中间件 存储 设计模式
Kafka原理篇:图解kakfa架构原理
Kafka原理篇:图解kakfa架构原理
74 1
|
19天前
|
消息中间件 监控 Kafka
【Kafka】Kafka 数据一致性原理
【4月更文挑战第7天】【Kafka】Kafka 数据一致性原理
|
29天前
|
消息中间件 存储 Kafka
【深入浅出 RocketMQ原理及实战】「底层源码挖掘系列」透彻剖析贯穿一下RocketMQ和Kafka索引设计原理和方案
【深入浅出 RocketMQ原理及实战】「底层源码挖掘系列」透彻剖析贯穿一下RocketMQ和Kafka索引设计原理和方案
48 1
|
1月前
|
消息中间件 Kafka Linux
Kafka【付诸实践 03】Offset Explorer Kafka 的终极 UI 工具安装+简单上手+关键特性测试(一篇学会使用 Offset Explorer)
【2月更文挑战第21天】Kafka【付诸实践 03】Offset Explorer Kafka 的终极 UI 工具安装+简单上手+关键特性测试(一篇学会使用 Offset Explorer)
190 2
|
1月前
|
消息中间件 网络协议 Kafka
Kafka【付诸实践 02】消费者和消费者群组+创建消费者实例+提交偏移量(自动、手动)+监听分区再平衡+独立的消费者+消费者其他属性说明(实例源码粘贴可用)【一篇学会使用Kafka消费者】
【2月更文挑战第21天】Kafka【付诸实践 02】消费者和消费者群组+创建消费者实例+提交偏移量(自动、手动)+监听分区再平衡+独立的消费者+消费者其他属性说明(实例源码粘贴可用)【一篇学会使用Kafka消费者】
81 3
|
1月前
|
消息中间件 Java Kafka
【Spring底层原理高级进阶】Spring Kafka:实时数据流处理,让业务风起云涌!️
【Spring底层原理高级进阶】Spring Kafka:实时数据流处理,让业务风起云涌!️
|
2月前
|
消息中间件 安全 Kafka
2024年了,如何更好的搭建Kafka集群?
我们基于Kraft模式和Docker Compose同时采用最新版Kafka v3.6.1来搭建集群。
438 2
2024年了,如何更好的搭建Kafka集群?
|
3月前
|
消息中间件 存储 数据可视化
kafka高可用集群搭建
kafka高可用集群搭建
44 0

热门文章

最新文章