前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >脱离ZooKeeper | Kafka Controller Quorum(KRaft)机制浅析

脱离ZooKeeper | Kafka Controller Quorum(KRaft)机制浅析

作者头像
大数据真好玩
发布2022-03-28 08:05:27
8080
发布2022-03-28 08:05:27
举报
文章被收录于专栏:暴走大数据暴走大数据

从单点Controller到Controller Quorum

现阶段的Kafka Controller本质上就是Kafka集群中的一台Broker,通过ZK选举出来,负责根据ZK中的元数据维护所有Broker、Partition和Replica的状态。但是,一旦没有了ZK的辅助,Controller就要接手ZK的元数据存储,并且单点Controller失败会对集群造成破坏性的影响。因此,在3.0版本中,Controller会变为一个符合Quorum原则(过半原则)的Broker集合,如下图所示。

也就是说,在实际应用中要求Controller Quorum的节点数为奇数且大于等于3,最多可以容忍(n / 2 - 1)个节点失败。当然,只有一个节点能成为领导节点即Active Controller,领导选举就依赖于内置的Raft协议变种(又称为KRaft)实现。按照介绍Raft的思路,首先来看看Controller Quorum节点的状态与转移规则。

Quorum节点状态机

在KRaft协议下,Quorum中的一个节点可以处于以下4种状态之一。

  • Candidate(候选者)——主动发起选举;
  • Leader(领导者)——在选举过程中获得多数票;
  • Follower(跟随者)——已经投票给Candidate,或者正在从Leader复制日志;
  • Observer(观察者)——没有投票权的Follower,与ZK中的Observer含义相同,本文暂不考虑。

状态转换图如下所示。看官可以与经典Raft协议的状态转换图对比一下,基本是相似的。

消息定义

经典Raft协议只定义了两种RPC消息,即AppendEntries与RequestVote,并且是以推模式交互的。为了适应Kafka环境,KRaft协议以拉模式交互,定义的RPC消息有如下几种。

  • Vote:选举的选票信息,由Candidate发送;
  • BeginQuorumEpoch:新Leader当选时发送,告知其他节点当前的Leader信息;
  • EndQuorumEpoch:当前Leader退位时发送,触发重新选举,用于graceful shutdown;
  • Fetch:复制Leader日志,由Follower/Observer发送——可见,经典Raft协议中的AppendEntries消息是Leader将日志推给Follower,而KRaft协议中则是靠Fetch消息从Leader拉取日志。同时Fetch也可以作为Follower对Leader的活性探测。

根据KIP-595的说明,采用拉模式可以将一致性检查的工作放在Leader端,同时也可以更快速地bootstrap一个全新的Follower(直接从offset 0开始复制日志即可)以及淘汰过期的Follower。拉模式的缺点主要是处理僵尸Leader和Fetch的延迟可能较大。

领导选举

当满足以下三个条件之一时,Quorum中的某个节点就会触发选举:

  1. 向Leader发送Fetch请求后,在超时阈值quorum.fetch.timeout.ms之后仍然没有得到Fetch响应,表示Leader疑似失败;
  2. 从当前Leader收到了EndQuorumEpoch请求,表示Leader已退位;
  3. Candidate状态下,在超时阈值quorum.election.timeout.ms之后仍然没有收到多数票,也没有Candidate赢得选举,表示此次选举作废,重新进行选举。

接下来的投票流程与经典Raft协议相同,不再赘述。当然,选举过程中仍然要对无效的选票进行处理,如集群ID或纪元值过期的选票。

元数据日志复制

与维护Consumer offset的方式类似,脱离ZK之后的Kafka集群将元数据视为日志,保存在一个内置的Topic中,且该Topic只有一个Partition。

元数据日志的消息格式与普通消息没有太大不同,但必须携带Leader的纪元值(即之前的Controller epoch):

代码语言:javascript
复制
Record => Offset LeaderEpoch ControlType Key Value Timestamp

这样,Follower以拉模式复制Leader日志,就相当于以Consumer角色消费元数据Topic,符合Kafka原生的语义。

那么在KRaft协议中,是如何维护哪些元数据日志已经提交——即已经成功复制到多数的Follower节点上的呢?Kafka仍然借用了原生副本机制中的概念——high watermark(HW,高水位线)保证日志不会丢失,HW的示意图如下。

如果看官不了解HW,可以去搜索对应的资料,本文不废话了。

状态机安全性保证

在安全性方面,KRaft与传统Raft的选举安全性、领导者只追加、日志匹配和领导者完全性保证都是几乎相同的。下面只简单看看状态机安全性是如何保证的,仍然举论文中的极端栗子:

  1. 在时刻a,节点S1是Leader,epoch=2的日志只复制给了S2就崩溃了;
  2. 在时刻b,S5被选举为Leader,epoch=3的日志还没来得及复制,也崩溃了;
  3. 在时刻c,S1又被选举为Leader,继续复制日志,将epoch=2的日志给了S3。此时该日志复制给了多数节点,但还未提交;
  4. 在时刻d,S1又崩溃,并且S5重新被选举为领导者,将epoch=3的日志复制给S0~S4。

此时日志与新Leader S5的日志发生了冲突,如果按上图中d1的方式处理,消息2就会丢失。传统Raft协议的处理方式是:在Leader任期开始时,立刻提交一条空的日志,所以上图中时刻c的情况不会发生,而是如同d2一样先提交epoch=4的日志,连带提交epoch=2的日志。

与传统Raft不同,KRaft附加了一个较强的约束:当新的Leader被选举出来,但还没有成功提交属于它的epoch的日志时,不会向前推进HW。也就是说,即使上图中时刻c的情况发生了,消息2也被视为没有成功提交,所以按照d1方式处理是安全的。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-02-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 大数据真好玩 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 从单点Controller到Controller Quorum
  • Quorum节点状态机
  • 消息定义
  • 领导选举
  • 元数据日志复制
  • 状态机安全性保证
相关产品与服务
数据保险箱
数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档