一、控制器是什么
其实控制器也是一个broker,控制器也叫leader broker。Kafka的集群由n个的broker所组成,每个broker就是一个kafka的实例或者称之为kafka的服务。
二、控制器选举
kafka每个broker启动的时候,都会实例化一个KafkaController,并将broker的id注册到zookeeper。
集群在启动过程中,通过选举机制选举出其中一个broker作为leader,也就是前面所说的控制器。
有三种情况触发控制器选举:
1、集群启动
2、控制器所在代理发生故障
3、zookeeper心跳感知,控制器与自己的session过期
假设此集群有三个broker,同时启动。
(一)3个broker从zookeeper获取/controller临时节点信息。/controller存储的是选举出来的leader信息。此举是为了确认是否已经存在leader。

(二)如果还没有选举出leader,那么此节点是不存在的,返回-1。如果返回的不是-1,而是leader的json数据,那么说明已经有leader存在,选举结束。

(三)三个broker发现返回-1,了解到目前没有leader,于是均会触发向临时节点/controller写入自己的信息。最先写入的就会成为leader。

(四)假设broker 0的速度最快,他先写入了/controller节点,那么他就成为了leader。而broker1、broker2很不幸,因为晚了一步,他们在写/controller的过程中会抛出ZkNodeExistsException,也就是zk告诉他们,此节点已经存在了。

经过以上四步,broker 0成功写入/controller节点,其它broker写入失败了,所以broker 0成功当选leader。
三、控制器初始化
控制器的初始化,其实是初始化控制器所用到的组件及监听器,准备元数据。
前面提到过每个broker都会实例化并启动一个KafkaController。KafkaController和他的组件关系,以及各个组件的介绍如下图:

图中箭头为组件层级关系,组件下面还会再初始化其他组件。可见控制器内部还是有些复杂的,主要有以下组件:
1、ControllerContext,此对象存储了控制器工作需要的所有上下文信息,包括存活的代理、所有主题及分区分配方案、每个分区的AR、leader、ISR等信息。
2、一系列的listener,通过对zookeeper的监听,触发相应的操作,黄色的框的均为listener
3、分区和副本状态机,管理分区和副本。
4、当前代理选举器ZookeeperLeaderElector,此选举器有上位和退位的相关回调方法。
5、分区leader选举器,PartitionLeaderSelector
6、主题删除管理器,TopicDeletetionManager
7、leader向broker批量通信的ControllerBrokerRequestBatch。缓存状态机处理后产生的request,然后统一发送出去。
8、控制器平衡操作的KafkaScheduler,仅在broker作为leader时有效。
四、控制器功能
(1)故障转移
故障转移其实就是leader所在broker发生故障,leader转移为其他的broker。转移的过程就是重新选举leader的过程。
重新选举leader后,需要为该broker注册相应权限,调用的是ZookeeperLeaderElector的onControllerFailover()方法。在这个方法中初始化和启动了一系列的组件来完成leader的各种操作。具体如下,其实和控制器初始化有很大的相似度。
1、注册分区管理的相关监听器
监听名称监听zookeeper节点作用PartitionsReassignedListener/admin/reassign_partitions节点变化将会引发分区重分配IsrChangeNotificationListener/isr_change_notification处理分区的ISR发生变化引发的操作PreferredReplicaElectionListener/admin/preferred_replica_election将优先副本选举为leader副本
2、注册主题管理的相关监听
监听名称监听zookeeper节点作用TopicChangeListener/brokers/topics监听主题发生变化时进行相应操作DeleteTopicsListener/admin/delete_topics完成服务器端删除主题的相应操作。否则客户端删除主题仅仅是表示删除
3、注册代理变化监听器
监听名称监听zookeeper节点作用BrokerChangeListener/brokers/ids代理发生增减的时候进行相应的处理
4、重新初始化ControllerContext,
5、启动控制器和其他代理之间通信的ControllerChannelManager
6、创建用于删除主题的TopicDeletionManager对象,并启动。
7、启动分区状态机和副本状态机
8、轮询每个主题,添加监听分区变化的PartitionModificationsListener
9、如果设置了分区平衡定时操作,那么创建分区平衡的定时任务,默认300秒检查并执行。
(2)代理上下线
有新的broker加入集群时,称为代理上线。反之,当broker关闭,推出集群时,称为代理下线。
代理上线:
1、新代理启动时向/brokers/ids写数据
2、BrokerChangeListener监听到变化。对新上线节点调用controllerChannelManager.addBroker(),完成新上线代理网络层初始化
3、调用KafkaController.onBrokerStartup()处理
3.1通过向所有代理发送UpdateMetadataRequest,告诉所有代理有新代理加入
3.2根据分配给新上线节点的副本集合,对副本状态做变迁。对分区也进行处理。
3.3触发一次leader选举,确认新加入的是否为分区leader
3.4轮询分配给新broker的副本,调用KafkaController.onPartitionReassignment(),执行分区副本分配
3.5恢复因新代理上线暂停的删除主题操作线程
代理下线:
1、查找下线节点集合
2、轮询下线节点,调用controllerChannelManager.removeBroker(),关闭每个下线节点网络连接。清空下线节点消息队列,关闭下线节点request请求
3、轮询下线节点,调用KafkaController.onBrokerFailure处理
3.1处理leader副本在下线节点上上的分区,重新选出leader副本,发送updateMetadataRequest请求。
3.2处理下线节点上的副本集合,做下线处理,从ISR集合中删除,不再同步,发送updateMetadataRequest请求。
4、向集群全部存活代理发送updateMetadataRequest请求
(3)主题管理
通过分区状态机及副本状态机来进行主题管理
1、创建主题
/brokers/topics下创建主题对应子节点
TopicChangeListener监听此节点
变化时获取重入锁ReentrantLock,调用handleChildChange方法进行处理。
通过对比zookeeper中/brokers/topics存储的主题集合及控制器的ControllerContext中缓存的主题集合的差集,得到新增的主题。反过来求差集,得到删除的主题。
接下来遍历新增的主题集合,进行主题操作的实质性操作。之前仅仅是在zookeeper中添加了主题。新增主题涉及的操作有分区、副本状态的转化、分区leader的分配、分区存储日志的创建等。
2、删除主题
/admin/delete_topics创建删除主题的子节点
DeleteTopicsListener监听此节点,
变化时获取重入锁ReentrantLock,进行处理
(4)分区管理
1、分区自动平衡
onControllerFailover方法中启动分区自动平衡任务。定时检查是否失去平衡。
自动平衡的操作就是把优先副本选为分区leader,AR中第一个副本为优先副本。
先查出所有可用副本,以分区AR头节点分组。
轮询代理节点,判断分区不平衡率是否超过10%(leader为非优先副本的分区/该代理分区总数),则调用onPreferredReplicaElection(),让优先副本成为leader。达到自动平衡。
分区平衡操作的流程已经在第三章做了很详细的讲解,此处不再重复,可以参考kafka核心概念。
2、分区重分配
当zk节点/admin/reassign_partitions变化时,触发分区重分配操作。该节点存储分区重分配的方案。
通过计算主题分区原AR(OAR)和重新分配后的AR(RAR),分别做相应处理:
1、OAR+RAR:更新到该主题分区AR,并通知副本节点同步。leader_epoch+1
2、RAR-OAR:副本设为NewReplica。
3、(OAR+RAR)- RAR:需要下线的副本,做下线操作
更多内容:
本文深入解析Kafka控制器的功能,涵盖控制器的定义、选举过程、初始化步骤及其关键职责,如故障转移、代理上下线处理、主题管理和分区管理等。
9809

被折叠的 条评论
为什么被折叠?



