共计 4868 个字符,预计需要花费 13 分钟才能阅读完成。
控制器组件(Controller),是 Apache Kafka 的外围组件。它的次要作用是在 Apache ZooKeeper 的帮忙下治理和协调整个 Kafka 集群。集群中任意一台 Broker 都能充当控制器的角色,然而,在运行过程中,只能有一个 Broker 成为控制器,行使其治理和协调的职责。接下来,咱们将探讨 Controller 原理和外部运行机制。通过本文你能够理解到:
- 什么是 Controller Broker
- Controller Broker 是怎么被选举的
- Controller Broker 次要作用是什么
- Kafka 是如何解决脑裂的
在分布式系统中,通常须要有一个协调者,该协调者会在分布式系统产生异样时施展非凡的作用。在 Kafka 中该协调者称之为控制器(Controller), 其实该控制器并没有什么非凡之处,它自身也是一个一般的 Broker,只不过须要负责一些额定的工作(追踪集群中的其余 Broker,并在适合的时候解决新退出的和失败的 Broker 节点、Rebalance 分区、调配新的 leader 分区等)。值得注意的是:Kafka 集群中始终只有一个 Controller Broker。
Controller Broker 是如何被选出来的
上一大节解释了什么是 Controller Broker,并且每台 Broker 都有充当控制器的可能性。那么,控制器是如何被选出来的呢?当集群启动后,Kafka 怎么确认控制器位于哪台 Broker 呢?
实际上,Broker 在启动时,会尝试去 ZooKeeper 中创立 /controller 节点。Kafka 以后选举控制器的规定是:第一个胜利创立 /controller 节点的 Broker 会被指定为控制器。
Controller Broker 的具体作用是什么
Controller Broker 的主要职责有很多,次要是一些治理行为,次要包含以下几个方面:
- 创立、删除主题,减少分区并调配 leader 分区
- 集群 Broker 治理(新增 Broker、Broker 被动敞开、Broker 故障)
- preferred leader选举
- 分区重调配
解决集群中下线的 Broker
当某个 Broker 节点因为故障来到 Kafka 群集时,则存在于该 Broker 的 leader 分区将不可用(因为客户端仅对 leader 分区进行读写操作)。为了最大水平地缩小停机工夫,须要疾速找到代替的 leader 分区。
Controller Broker 能够对失败的 Broker 做出响应,Controller Broker 能够从 Zookeeper 监听 (zookeeper watch) 中获取告诉信息,ZooKeeper 赋予客户端监控 znode 变更的能力,即所谓的 Watch 告诉性能。一旦 znode 节点被创立、删除,子节点数量发生变化,抑或是 znode 所存的数据自身变更,ZooKeeper 会通过节点变更监听器 (ChangeHandler) 的形式显式告诉客户端。
每个 Broker 启动后,会在 zookeeper 的 /Brokers/ids 下创立一个长期 znode。当 Broker 宕机或被动敞开后,该 Broker 与 ZooKeeper 的会话完结,这个 znode 会被主动删除。同理,ZooKeeper 的 Watch 机制将这一变更推送给控制器,这样控制器就能晓得有 Broker 敞开或宕机了,从而进行后续的协调操作。
Controller 将收到告诉并对此采取行动,决定哪些 Broker 上的分区成为 leader 分区,而后,它会告诉每个相干的 Broker,要么将 Broker 上的主题分区变成 leader,要么通过 LeaderAndIsr
申请从新的 leader 分区中复制数据。
解决新退出到集群中的 Broker
通过将 Leader 分区正本平均地散布在集群的不同 Broker 上,能够保障集群的负载平衡。在 Broker 产生故障时,某些 Broker 上的分区正本会被选举为 leader,会造成一个 Broker 上存在多个 leader 分区正本的状况,因为客户端只与 leader 分区正本交互,所以这会给 Broker 减少额定的累赘,并侵害集群的性能和运行状况。因而,尽快恢复均衡对集群的衰弱运行是无益的。
Kafka 认为 leader 分区正本最后的调配(每个节点都处于沉闷状态)是平衡的。这些被最后选中的分区正本就是所谓的 首选领导者 (preferred leaders)。因为 Kafka 还反对 机架感知的 leader 选举(rack-aware leader election) , 即尝试将 leader 分区和 follower 分区搁置在不同的机架上,以减少对机架故障的容错能力。因而,leader 分区正本的存在地位会对集群的可靠性产生影响。
默认状况下 auto.leader.rebalance.enabled 为 true,示意容许 Kafka 定期地对一些 Topic 分区进行
Leader 重选举。大部分状况下,Broker 的失败很短暂,这意味着 Broker 通常会在短时间内复原。所以当节点来到群集时,与其相关联的元数据并不会被立刻删除。
当 Controller 留神到 Broker 已退出集群时,它将应用 Broker ID 来查看该 Broker 上是否存在分区,如果存在,则 Controller 告诉新退出的 Broker 和现有的 Broker,新的 Broker 下面的 follower 分区再次开始复制现有 leader 分区的音讯。为了保障负载平衡,Controller 会将新退出的 Broker 上的 follower 分区选举为 leader 分区。
留神 :下面提到的选 Leader 分区,严格意义上是换 Leader 分区,为了达到负载平衡,可能会造成原来失常的 Leader 分区被强行变为 follower 分区。换一次 Leader 代价是很高的,本来向 Leader 分区 A(原 Leader 分区) 发送申请的所有客户端都要切换成向 B (新的 Leader 分区) 发送申请,倡议你在生产环境中把这个参数设置成 false。
同步正本 (in-sync replica ,ISR) 列表
ISR 中的正本都是与 Leader 进行同步的正本,所以不在该列表的 follower 会被认为与 Leader 是不同步的. 那么,ISR 中存在是什么正本呢?首先能够明确的是:Leader 正本总是存在于 ISR 中。而 follower 正本是否在 ISR 中,取决于该 follower 正本是否与 Leader 正本放弃了“同步”。
始终保障领有足够数量的同步正本是十分重要的。要将 follower 晋升为 Leader,它必须存在于 同步正本列表中。每个分区都有一个同步正本列表,该列表由 Leader 分区和 Controller 进行更新。
抉择一个同步正本列表中的分区作为 leader 分区的过程称为 clean leader election。留神,这里要与在非同步正本当选一个分区作为 leader 分区的过程辨别开,在非同步正本当选一个分区作为 leader 的过程称之为unclean leader election。因为 ISR 是动静调整的,所以会存在 ISR 列表为空的状况,通常来说,非同步正本落后 Leader 太多,因而,如果抉择这些正本作为新 Leader,就可能呈现数据的失落。毕竟,这些正本中保留的音讯远远落后于老 Leader 中的音讯。在 Kafka 中,选举这种正本的过程能够通过 Broker 端参数 unclean.leader.election.enable 管制是否容许 Unclean 领导者选举。开启 Unclean 领导者选举可能会造成数据失落,但益处是,它使得分区 Leader 正本始终存在,不至于进行对外提供服务,因而晋升了高可用性。反之,禁止 Unclean Leader 选举的益处在于保护了数据的一致性,防止了音讯失落,但就义了高可用性。分布式系统的 CAP 实践说的就是这种状况。
可怜的是,unclean leader election的选举过程仍可能会造成数据的不统一,因为同步正本并不是 齐全 同步的。因为复制是 异步 实现的,因而无奈保障 follower 能够获取最新消息。比方 Leader 分区的最初一条音讯的 offset 是 100,此时正本的 offset 可能不是 100,这受到两个参数的影响:
- replica.lag.time.max.ms:同步正本滞后与 leader 正本的工夫
- zookeeper.session.timeout.ms:与 zookeeper 会话超时工夫
脑裂
如果 controller Broker 挂掉了,Kafka 集群必须找到能够代替的 controller,集群将不能失常运行。这外面存在一个问题,很难确定 Broker 是挂掉了,还是仅仅只是短暂性的故障。然而,集群为了失常运行,必须选出新的 controller。如果之前被取代的 controller 又失常了,他并不知道本人曾经被取代了,那么此时集群中会呈现两台 controller。
其实这种状况是很容易产生。比方,某个 controller 因为 GC 而被认为曾经挂掉,并抉择了一个新的 controller。在 GC 的状况下,在最后的 controller 眼中,并没有扭转任何货色,该 Broker 甚至不晓得它曾经暂停了。因而,它将持续充当以后 controller,这是分布式系统中的常见状况,称为脑裂。
如果,处于沉闷状态的 controller 进入了长时间的 GC 暂停。它的 ZooKeeper 会话过期了,之前注册的 /controller
节点被删除。集群中其余 Broker 会收到 zookeeper 的这一告诉。
因为集群中必须存在一个 controller Broker,所以当初每个 Broker 都试图尝试成为新的 controller。假如 Broker 2 速度比拟快,成为了最新的 controller Broker。此时,每个 Broker 会收到 Broker2 成为新的 controller 的告诉,因为 Broker3 正在进行 ”stop the world” 的 GC,可能不会收到 Broker2 成为最新的 controller 的告诉。
等到 Broker3 的 GC 实现之后,仍会认为本人是集群的 controller,在 Broker3 的眼中如同什么都没有产生一样。
当初,集群中呈现了两个 controller,它们可能一起收回具备抵触的命令,就会呈现脑裂的景象。如果对这种状况不加以解决,可能会导致重大的不统一。所以须要一种办法来辨别谁是集群以后最新的 Controller。
Kafka 是通过应用epoch number(纪元编号,也称为隔离令牌)来实现的。epoch number 只是枯燥递增的数字,第一次选出 Controller 时,epoch number 值为 1,如果再次选出新的 Controller,则 epoch number 将为 2,顺次枯燥递增。
每个新选出的 controller 通过 Zookeeper 的条件递增操作取得一个全新的、数值更大的 epoch number。其余 Broker 在晓得以后 epoch number 后,如果收到由 controller 收回的蕴含较旧(较小)epoch number 的音讯,就会疏忽它们,即 Broker 依据最大的 epoch number 来辨别以后最新的 controller。
上图,Broker3 向 Broker1 收回命令: 让 Broker1 上的某个分区正本成为 leader,该音讯的 epoch number 值为 1。于此同时,Broker2 也向 Broker1 发送了雷同的命令,不同的是,该音讯的 epoch number 值为 2,此时 Broker1 只服从 Broker2 的命令(因为其 epoch number 较大),会疏忽 Broker3 的命令,从而防止脑裂的产生。
总结
本文次要解说了什么是 Kafka Controller,它其实就是一个一般的 Broker,除了须要负责一些额定的工作之外,其角色与其余的 Broker 根本一样。另外还介绍了 Kafka Controller 的主要职责,并对其中的一些职责进行了具体解释,最初还阐明了 kafka 是如何防止脑裂的。
公众号『大数据技术与数仓』,回复『材料』支付大数据资料包