问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Kafka集群架构设计原理详解

创作时间:
作者:
@小白创作中心

Kafka集群架构设计原理详解

引用
CSDN
1.
https://blog.csdn.net/qq_41804775/article/details/136261228

Kafka集群架构设计原理详解

Kafka核心总控制器

  • leader:负责给定Partition的所有读写请求
  • replicas:表示某个Partition在那些Broker上存在备份,列举出节点信息
  • AR(Assigned Replicas):分区中的所有副本(存活和不存活的)
  • ISR(In-Sync Replicas):在AR中,存活的并且能与leader正常同步的分区副本
  • 进入ISR列表的条件
  • 副本节点不能产生分区以及能与ZK和leader副本保持稳定联系
  • 副本能进行leader副本同步操作,并且数据不能滞后太多
  • OSR(Out-of-Sync Replicas):表示从ISR中踢出的节点,记录的是那些服务有问题、延迟过多的副本

Controller Broker选举机制

  • Kafka集群启动时,会自动选举一个Broker作为控制器来管理整个集群,选举的过程是集群中每个Broker都会尝试在ZK上创建/contrller临时节点并将自己的brokerid写入,ZK会保证只有一个Broker创建成功成为集群的核心控制器
  • 当这个核心控制器出现故障,此时ZK上对应的临时节点会被删除,集群中其它Broker由于监听着这个节点的变化,会再次去竞争选举成为新的核心控制器
  • 简概:抢创ZK上/controller临时节点,监控该节点的状态变化

Leader Partition选举机制

  • 控制器感知到分区leader副本所在的Broker出现故障,满足AR排名最靠前并且在ISR中得成为leader
  • 满足分区副本排名靠前并且存活的会优先成为leader

Leader Partition自平衡机制

  • 在一组分区副本中,leader分区负责与客户端数据交互以及向follower同步数据,通常情况下是比较繁忙的,所以默认情况下Kafka会尽量将leader分区分配到不同的Broker节点上,来保证整个集群的压力平均,但是经过leader分区选举之后,这种平衡可能会被打破,如果让过多的leader分区集中到同一个Broker就会导致该节点压力过大,所以Kafka设计了leader分区自平衡机制
  • Kafka会认为AR中的第一个节点为leader节点,控制器会定期检查集群中所有Broker的分区的平衡情况,当某个Broker的分区数量高于阈值时,会触发自平衡
  • leader分区自平衡是一个非常重的操作,会涉及大量数据的同步与转移,可能会造成消息丢失,所以对于业务要求较高的场景建议关闭

消费者消费消息的offset记录机制

  • 每个消费者会定期将自己消费分区的offset提交给Kafka内部的Topic(_cosumer_offsets),Kafka会定期清理Topic中的消息,最后保留最新的那条数据,因为该Topic可能会接受高并发的请求,Kafka默认给其分配了50个分区,这样可以通过加机器来抗大并发

消费者Rebalance机制

  • 如果消费组里的消费者数量有变化或消费的分区数有变化,Kafka会重新分配消费者消费分区的关系,比如消费组中的某个消费者挂了,此时会将已分配给它的分区转交给其它的消费者,如果它重启了,那么会将之前的分区还给它
  • Rebalance只针对subscribe这种不指定分区消费的情况,如果通过assign这种消费方式指定的了分区,Kafka不会进行Rebalance
  • Rebalance过程中,消费者无法从Kafka消费消息,这对Kafka的TPS会有影响,如果kafKafkaa集群内节点较多,那重平衡可能会耗时极多,所以应尽量避免在系统高峰期的重平衡发生
  • 问题:触发消费者Rebalance机制的情况
  • 消费者组里消费者变化
  • 动态给Topic增加分区
  • 消费组订阅了更多的Topic

Rebalance流程

  • 三阶段
  • 选出组协调器:每个消费组都会选择一个Broker作为自己的组协调器,负责监控这个消费组里的所有消费者是否存活(心跳),然后开启消费者Rebalance,消费者组中的每个消费者启动时会向Kafka集群中的某个节点发送查找请求来查找对应的组协调器,并建立连接
  • 组协调器选择方式:公式:hash(consumer group id) % __consumer_offsets主题的分区数
  • 加入消费组:在成功找到消费组所对应的组协调器之后就会进入该阶段,此时消费者会向组协调器发送加入请求并处理响应,然后组协调器会从消费者组中选择第一个加入到组的消费者作为leader(消费组协调器),把消费者组的情况发送给这个leader,并让它负责制定分区方案
  • 同步消费组:消费者leader通过组协调器发送同步请求,然后组协调器会将分区方案发到各个消费者,然后所有消费者会根据指定分区的leader broker进行网络连接和消息消费

Partition故障恢复机制

  • 参数说明

  • LEO(Log End Offset):每个分区的最后一个offset

  • HW(High Watermark):一组分区中最小的LEO

  • 机制

  • 在一组分区选举出一个leader分区之后,该leader分区就会优先写入消息,再将消息同步给其它follower分区

  • 当leader分区所在的Broker发生故障时,Kafka就会触发leader分区选举机制,为了保证消息能够在多个分区中保持数据同步,每个分区都会记录自己保存的消息offset,leader分区每写入一条消息都会将LEO值+1,follower分区会从leader分区中同步消息,每同步一次,自己的LEO值+1并且同步给leader分区,leader分区通过follower返回的LEO值计算出HW值,最终会将HW值同步给所有follower

  • 对于HW之前的消息是所有follower分区完成数据同步的,是安全的,可以被消费者使用

  • 对于HW之后的消息是可能丢失的,是不安全的,所以不能被消费者使用

  • 问题:分区出现故障应对方式

  • leader分区所在的Broker出现故障

  • 当leader分区所在的Broker出现故障时,会从ISR中的所有follower中进行选举出新的leader,此时新leader的LEO值会低于之前leader的LEO值,follower只能以leader为主将各自高于HW值的部分全部删除,重新从leader中同步,旧leader恢复之后也只能跟其它follower一样如此操作

  • follower分区所在的Broker出现故障

  • 当follower分区所在的Broker出现故障时,不会影响消息写入,只是写好了一个备份

  • Kafka会将follower节点临时剔除ISR,而其他leader和follower能继续正常工作,等follower节点恢复之后,不会立即加入到ISR中,follower节点会读取本地上一次的HW值,将高于HW值的部分信息全部删除,然后从HW值位置重新消息同步,等到follower的LEO值不小于整个分区的HW值后,就会重新加入到ISR中(follower的消息同步进度追上了leader)

HW一致性保障-Epoch更新机制

  • 问题:对于Partition故障恢复机制使用到了LEO和HW,如何保证各个Broker中记录的HW一致
  • 实际上HW值在一组分区里并不是总是一致的,对于follower分区需要先从leader分区将消息拉回本地,才能上报LEO值,当所有follower分区上报完之后,leader分区才会计算出HW值,然后告知follower进行拉取最新的HW值,所以leader分区的LEO值更新与follower分区的LEO值更新存在一定延迟,这样就间接导致HW值存在一定延迟
  • 如果服务一切正常,leader分区还是可以正常推进HW之的,是能保证最终一致性的
  • 当leader分区出现切换,所有follower分区都只能按照各自的HW值进行数据恢复,会导致数据不一致的情况
  • Kafka通过Epoch机制来保证HW的一致性
  • 每次发生leader变更时,都会维护一个递增的epoch号以及当前分区写入的首个消息offset,并且持久化到文件中,其它follower会同步该文件,当出现leader变更时,follower就可以直接依赖最新的epoch去判断拉取消息的起点,避免使用自身的HW值去判断

Producer发布消息机制

  • 写入方式:生产者采用推模式将消息发布到Broker,每条消息都被追加到分区中,属于顺序写磁盘(顺序写磁盘效率比随机写内存效率要高,保障Kafka吞吐率)
  • 消息路由:生产者发送消息到Broker时,会根据分区算法选择将其存到某个分区
  • 路由机制
  • 指定了分区
  • 未指定分区但指定key,通过对key的值进行hash
  • 未指定分区和key,通过轮询
  • 写入流程:生产者先从ZK的state节点下找到分区的leader,然后将消息发送给leader,leader将消息持久化到本地log,follower从leader拉取消息成功之后发生ACK,leader收到所有ISR中节点的ACK之后,维护HW值再向生产者发送ACK
  • 采用稀疏索引(类似数据库中的非聚集索引),通过二分查找进行定位,效率较高

日志存储

  • 问题:Topic下的消息是如何存储的
  • Kafka每个分区都会对应一个文件夹,以topic + 分区号命名,消息在分区内采用分段存储,每个段的消息都存到不同的日志文件中,这样能保证旧文件可以定期被快速删除,另外为了方便将数据刷到内存,所以规定每个段的日志文件最大为1G
  • 整个文件结构采用稀疏索引结构,这样可以加速日志文件的读取,并且采用顺序写磁盘的方式(只支持追加,不支持修改和删除)进行追加内容,提升了写入的效率

文件高效读写机制

  • 文件结构
  • 同一个Topic下的多个分区采用单独的日志文件进行存储,可以并行读取,这样可以加速读取Topic下的数据
  • 采用稀疏索引结构,可以加快日志文件的检索速度
  • 顺序写磁盘
  • 对于每个日志文件,Kafka都提前规划了固定的大小,这样保证在申请文件时可以提前占据一块连续的磁盘空间
  • 日志文件采用顺序写磁盘的方式,不用浪费时间去寻找空闲空间,就可以基于之前申请的文件进行追加,提升写入效率
  • 顺序写:以追加的形式在同一个文件中进行写入,写入效率极高
  • 随机写:寻找空闲的磁盘空间进行写入,磁盘中的空闲空间可能不是连续的,所以写入效率很低
  • 零拷贝
  • 配合内核态的复制机制,减少用户态和内核态之间的内容拷贝
  • 实现方式
  • mmap文件映射机制:用户态不缓存整个IO过程,只通过文件的映射信息进行内核态的读写,类似于JDK中的DirectByteBuffer实现机制
  • sendfile文件传输机制:向内核态发送sendfile指令操控它进行文件复制
  • 在Kafka中,当消费者从Broker上拉消息时,用户态只需要向内核态发送sendfile指令,此时Broker就会从磁盘读出数据,复制到网卡的socket缓冲区中,再通过网络传输出去
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号