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

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 探究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 进行截断,产生数据丢失及不一致

目录
相关文章
|
8天前
|
消息中间件 存储 缓存
大厂面试高频:Kafka 工作原理 ( 详细图解 )
本文详细解析了 Kafka 的核心架构和实现原理,消息中间件是亿级互联网架构的基石,大厂面试高频,非常重要,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:Kafka 工作原理 ( 详细图解 )
|
20天前
|
消息中间件 存储 监控
构建高可用性Apache Kafka集群:从理论到实践
【10月更文挑战第24天】随着大数据时代的到来,数据传输与处理的需求日益增长。Apache Kafka作为一个高性能的消息队列服务,因其出色的吞吐量、可扩展性和容错能力而受到广泛欢迎。然而,在构建大规模生产环境下的Kafka集群时,保证其高可用性是至关重要的。本文将从个人实践经验出发,详细介绍如何构建一个高可用性的Kafka集群,包括集群规划、节点配置以及故障恢复机制等方面。
54 4
|
1月前
|
消息中间件 缓存 分布式计算
大数据-59 Kafka 高级特性 消息发送03-自定义拦截器、整体原理剖析
大数据-59 Kafka 高级特性 消息发送03-自定义拦截器、整体原理剖析
27 2
|
1月前
|
消息中间件 缓存 大数据
大数据-57 Kafka 高级特性 消息发送相关01-基本流程与原理剖析
大数据-57 Kafka 高级特性 消息发送相关01-基本流程与原理剖析
40 3
|
1月前
|
消息中间件 NoSQL Kafka
大数据-116 - Flink DataStream Sink 原理、概念、常见Sink类型 配置与使用 附带案例1:消费Kafka写到Redis
大数据-116 - Flink DataStream Sink 原理、概念、常见Sink类型 配置与使用 附带案例1:消费Kafka写到Redis
131 0
|
3月前
|
消息中间件 Kafka 数据库
深入理解Kafka的数据一致性原理及其与传统数据库的对比
【8月更文挑战第24天】在分布式系统中,确保数据一致性至关重要。传统数据库利用ACID原则保障事务完整性;相比之下,Kafka作为高性能消息队列,采用副本机制与日志结构确保数据一致性。通过同步所有副本上的数据、维护消息顺序以及支持生产者的幂等性操作,Kafka在不牺牲性能的前提下实现了高可用性和数据可靠性。这些特性使Kafka成为处理大规模数据流的理想工具。
82 6
|
3月前
|
分布式计算 搜索推荐 物联网
大数据及AI典型场景实践问题之通过KafKa+OTS+MaxCompute完成物联网系统技术重构如何解决
大数据及AI典型场景实践问题之通过KafKa+OTS+MaxCompute完成物联网系统技术重构如何解决
|
3月前
|
消息中间件 负载均衡 Kafka
Kafka 实现负载均衡与故障转移:深入分析 Kafka 的架构特点与实践
【8月更文挑战第24天】Apache Kafka是一款专为实时数据处理和流传输设计的高性能消息系统。其核心设计注重高吞吐量、低延迟与可扩展性,并具备出色的容错能力。Kafka采用分布式日志概念,通过数据分区及副本机制确保数据可靠性和持久性。系统包含Producer(消息生产者)、Consumer(消息消费者)和Broker(消息服务器)三大组件。Kafka利用独特的分区机制实现负载均衡,每个Topic可以被划分为多个分区,每个分区可以被复制到多个Broker上,确保数据的高可用性和可靠性。
70 2
|
1月前
|
消息中间件 存储 运维
为什么说Kafka还不是完美的实时数据通道
【10月更文挑战第19天】Kafka 虽然作为数据通道被广泛应用,但在实时性、数据一致性、性能及管理方面存在局限。数据延迟受消息堆积和分区再平衡影响;数据一致性难以达到恰好一次;性能瓶颈在于网络和磁盘I/O;管理复杂性涉及集群配置与版本升级。
|
1月前
|
消息中间件 Java Kafka
Flink-04 Flink Java 3分钟上手 FlinkKafkaConsumer消费Kafka数据 进行计算SingleOutputStreamOperatorDataStreamSource
Flink-04 Flink Java 3分钟上手 FlinkKafkaConsumer消费Kafka数据 进行计算SingleOutputStreamOperatorDataStreamSource
47 1