原创:石头哥@大数据架构师  2021年8月2日   微信:nevian668899


概念和作用

kafka Controller作用_Zookeeper

1、Kafka Controller是Kakfa服务端Broker的概念,Broker集群有多台,但只有一台Broker可以扮演控制器的角色;
2、某台Broker一旦成为Controller,它用于以下权力:完成对集群成员管理、主题维护和分区的管理,如集群broker信息、Topic维护、Partition维护、分区选举ISR、同步元信息给其他Broker等。

为何要引入Controller角色?

我们暂且不深入分析他的作用,先思考下为何要引入控制器角色。前面也简单提到,它是控制器,完成对集群Broker、主题和分区等管理工作,而且只有一个leader对外提供服务,是否我们可以猜测元数据的管理工作集中化管理和维护,再分布式同步给所有控制器,这样有利于维护元数据的一致性和稳定性。进一步,我们回溯Kafka的历史版本,以前版本的架构是严重依赖zk的watch机制,这里不再赘述watch监听的原理,不清楚可以自行查找资料熟悉下。先看下Kafka旧版本的元数据维护架构图:

kafka Controller作用_Zookeeper_02

图1:老版本的Kafka元数据同步机制

历史版本的实现架构如上图所示,对于分区和副本的状态的管理依赖于zookeeper的Watcher和队列:每一个broker都会在zookeeper注册Watcher,所以zookeeper就会出现大量的Watcher, 如果宕机的broker上的partition比较多,会造成多个Watcher触发,造成集群内大规模调整;每一个replica都要去再次zookeeper上注册监视器,当集群规模很大的时候,zookeeper负担很重。所以严重依赖zk实现元数据的协调同步,这样做的弊端有以下几点:

  1. 当Kafka集群规模很大的时候,zookeeper负担很重。因为所有Broker的所有主题分区都要与zk建立连接,分区上下线和Broker的宕机或重新启动,会触发多个watch,给zk带来大量的写压力;
  2. zk压力大,容易引起网络风暴,不利于Kafka元数据的稳定性;
  3. 这种设计容易出现脑裂(zk集群的brain-split原理,请自行补充知识)和羊群效应


架构优化

Kafka官方团队也意识到严重依赖zk带来的弊端,于是对架构做了优化和调整。核心思想:

  • 降低对zk的依赖程度,减少zk压力
  • 元数据的控制和管理由中心化节点维护;
  • 异步化同步元数据给集群所有节点,并做好同步的容错处理。

基于控制器概念的新版架构如下图所示:

kafka Controller作用_消息中间件_03

图2:基于控制器的元数据维护架构图

Kafka集群中多个broker,每个broker启动时都会创建KafkaController对象,但只有一个会被选举为Controller leader,其他节点为Controller Follower。

控制器的启动初始化

1、当broker启动的时候,都会创建KafkaController对象;
2、每个节点上的KafkaController会在指定的zookeeper路径下创建临时节点,只有第一个成功创建的节点的KafkaController才可以成为leader,其余的都是follower;
3、集群中只能有一个leader对外提供服务;

控制器运行时对元信息的处理流程

只有Controller leader向zk注册watch并监听元数据的变化,其他broker不用监听zookeeper的状态变化。大概流程:
1. 用户通过命令或控制台执行集群的管理操作,比如:扩锁容Broker集群、创建/删除Topic、扩/缩容Partition;
2. 第一步会触发集群在zk对应路径上变更节点信息,比如/brokers/topics;
3. Controller leader收到watch的监听推送消息,通过监听接口收到对应的变更信息,比如主题信息、分区信息、集群Broker信息等;
4. Controller leader根据推送的事件类型,做不同的逻辑处理。比如:Broker加入或删除的相关流程、Topic新增或删除的相关流程、 分区重分配引起的重分配相关流程 、Partition扩展的相关流程(即分区leader选举和ISR同步);
5. Controller leader同步元信息至集群的Controller Follower节点。

控制器Leader如何Failover

如果控制器Leader所在broker退出、崩溃或与ZK会话失效则ZK会删除/controller内该子节点,各个broker的监视器收到这种变化后,每个broker开始竞争直到有一个竞争成为新的控制器Leader,并向/controller注册子节点,以及向/controller_EPOCH注册子节点。此时,新一轮的controller周期开始运行,新的leader节点继续肩负起监听元数据变化、处理元信息并同步给集群的任务。