热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

KafkaHW和LeaderEpoch

本地LEO和RemoteLEOKafka分区的follower副本的LEO属性保存了两份:本地LEO:在follower副本所在broker的缓存中保存一份RemoteLEO:在l

本地LEO和Remote LEO

Kafka分区的follower副本的LEO属性保存了两份:



  1. 本地LEO:在follower副本所在broker的缓存中保存一份

  2. Remote LEO:在leader副本所在的broker的缓存中保存一份(Remote LEO)

本地LEO很简单,就是follower本地日志文件的LEO,即它向leader发送FETCH请求得到结果后写入log文件时,该LEO增加

Remote LEO在leader接收到follower的FETCH请求后,读取自己的log文件,返回给follower之前更新


保存两份LEO是为分区HW在主从间的更新服务



HW更新机制

follower HW更新机制

follower在更新LEO之后更新HW

leader在FETCH响应中会提供自己的HW,也就是分区HW,分区HW受分区ISR中所有主从节点的写入情况限制,follower要保证自己的HW不超过分区HW,所以,follower会选择当前自己的LEO和leader的HW值中最小的那个


follower同步的比其它从节点快时,其它从节点的LEO可能比它小,这时它不能简单的将自己的LEO设置为高水位



leader HW更新机制

leader在下面四种情况下更新HW



  1. 自己刚刚成为leader副本时

  2. 有broker发生崩溃导致某副本被踢出ISR

  3. producer向leader副本写入消息时

  4. leader处理follower FETCH请求时

leader更新HW是在所有满足要求的副本中取最小的LEO作为它的HW,因为leader保存了所有副本的Remote LEO,所以它可以做到。

上面所说的满足要求,就是要最少满足下面两个条件的其中一个:



  1. 副本处于ISR中

  2. 副本落后于leader LEO的时间不大于replica.lag.time.max.ms参数

第二点是为了那些已经追上leader进度但尚未进入ISR(比如刚从故障中恢复的节点)考虑的,它们稍后就会进入ISR,如果不考虑它们,并且在下次leader更新HW之前,它们进入ISR,那它们的LEO值就不在此次HW的考虑范围内,万一它是ISR中最小的LEO,那就出现HW超过ISR分区最小LEO的情况了。


假设1:Producer发送消息到topic

当前,所有leader和follower的LEO=0



  1. leader收到消息,写入底层日志,更新自己的LEO属性=1

  2. leader尝试更新HW,所有follower的LEO为0,HW为0

  3. follower发送FETCH请求

  4. leader读取底层日志,更新Remote LEO为0,因为follower尚未收到该日志。

  5. leader尝试更新HW,LEO=1,Remote LEO=0,分区HW值=0

  6. leader将消息返回给follower,携带分区HW为0

  7. follower接收到响应,写入日志,更新自己的LEO为1,HW=Math.min(self.LEO, partition.HW)=0

第一轮结束,leader.LEO = 1, leader.HW=0, remote.leo = 0, follower.leo = 1, follower.HW = 0


注意,在第一轮中,leader尚不能确定follower已经成功写入消息,它不知道follower的leo已经为1,所以HW还是0。


开始第二轮



  1. follower再次FETCH消息,携带自己的offset,也就是自己的LEO=1

  2. leader读取log文件,根据FETCH携带的offset更新它的remote LEO=1

  3. leader更新分区HW为1

  4. leader将消息返回给follower(如果这期间没有新消息,就是空),并携带分区HW=1

  5. follower接收到响应,更新自己的LEO,并且设置自己的HW为1


这展示了HW的一个弊端,就是leader得在follower成功写入后的下一次请求时才能知道它成功写入了,而follower要在成功写入的下一次请求的响应中才能更新自己的HW,这引发了两个问题。


Kafka的分区宕机重启后,会将HW作为新的LEO,然后做日志截断,即将HW后面的全扔掉,问题就出在这里,分区自己的HW时不可靠的,时任leader的状态才可靠。


消息丢失

img

如上图,假设A接到了两条消息,A和B虽然都已经写入,LEO=2(注意LEO是下一条消息的写入位置),但B的HW还是0,因为它要等到A做完消息1的FETCH响应后才能更新HW。

假设这时,B宕机重启,它的LEO会被设置成1,消息1被丢弃,而此时,副本A又挂了,B成为了新的Leader,消息1就永远丢失了。


消息顺序错乱

由于原书的黑白印刷导致图片展示不清晰,这里选了网上的其它图片

img

假设A和B一同宕机(已经没有可用的副本了,Kafka无需保证消息可靠性),A作为原leader,它的HW是1,B作为原follower,它的HW是0。

若此时重启后,B做了leader,并且它接收新消息m3,并更新自己的HW为1,此时A重启做了follower,A根据自己的HW对消息进行截断,显然它不用截断,此时,B和A的HW都为2,看似一切正常,但实际上offset为1的消息已经不是同一条了。


上图的第一个状态好像不可能发生,因为只有当B实际写入了m2后A才会更新自己的HW。但存在B写入到pagecache但未刷盘的情况。



Leader Epoch

Leader Epoch用于解决上面的问题。

Epoch,可以被翻译为纪元、时期...一次leader更换,就看作一个Leader Epoch。

Leader Epoch是一个(epoch, offset)的二元组,epoch是一个整数,代表自己的代,比如第一个leader的epoch是0,下一个选举出来的leader的epoch是1,offset代表该版本Leader写入第一条消息的位移。

第一个leader的Epoch肯定是(0, 0),假设现在有第二个leader,它的Epoch是(1, 120),则代表它是从offset 120位置开始写的消息,这也就证明第一个leader写入了[0, 199]这些消息。Kafka Broker会在内存中为每个分区缓存Leader Epoch数据,同时还会定期的将它们持久化到checkpoint文件中

当一个follower副本宕机重启时,它会向leader发起一个LeaderEpochRequest,并携带自己所处的纪元,如果请求的纪元就是leader所在的纪元,leader就返回自己的LEO,否则返回follower所在纪元的下一个纪元的start offset(即它所在纪元的leader最后写入的消息位置)

follower使用这个返回值来截断自己的消息,而非自己的HW。此时再看上面两个问题

img

第一个问题,由于B重启后发送请求给leader,leader与它在同一个epoch,所以,直接返回自己的LEO,也就是2,B不用做任何截断,此时A宕机,B成为leader,在Producer首次写入新消息时增加自己的缓存项[epoch=1, offset=2]

img

第二个问题,由于B重启后,已经进入了纪元1,它接到m3时,写入[epoch=1, offset=1],A重启后,向B发起LeaderEpochRequest,携带它所在纪元0,B发现不是同一个纪元,就返回A所在纪元的下一个纪元的offset值,也就是自己的写入起始值,也就是1,此时,A需要使用1进行截断,消息m2被丢弃,m3被正常写入offset1的位置。消息错乱解决了。


看完了理解的还是不透彻,只是明白Kafka怎么做了,没消化这个设计思想,吃完饭回来再看看吧。



参考

  • 为什么Kafka需要Leader Epoch?



推荐阅读
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 显卡驱动对游戏的影响及其提升效果的研究
    本文研究了显卡驱动对游戏体验的提升效果,通过比较新旧驱动加持下的RTX 2080Ti显卡在游戏体验上的差异。测试平台选择了i9-9900K处理器和索泰RTX 2080Ti玩家力量至尊显卡,以保证数据的准确性。研究结果表明,显卡驱动的更新确实能够带来近乎50%的性能提升,对于提升游戏体验具有重要意义。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了在Oracle数据库中创建序列时如何选择cache或nocache参数。cache参数可以提高序列的存取速度,但可能会导致序列丢失;nocache参数可以避免序列丢失,但在高并发访问时可能导致性能问题。文章详细解释了两者的区别和使用场景。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • 开发笔记:计网局域网:NAT 是如何工作的?
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了计网-局域网:NAT是如何工作的?相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 达人评测 酷睿i5 12450h和锐龙r7 5800h选哪个好 i512450h和r75800h对比
    本文介绍了达人评测酷睿i5 12450h和锐龙r7 5800h选哪个好的相关知识,包括两者的基本配置和重要考虑点。希望对你在选择时提供一定的参考价值。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
author-avatar
霸气胡志刚_你活埋了木有
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有