KafKaController相关的类图如下
Kafka2.2.2版本的broker通过Zookeeper实现KafkaController主节点的选举,在整个集群中只有一个broker能当选为KafkaController节点,当活跃的KafkaController节点崩溃时,剩下的broker会再次选举出KafkaController主节点。
Kafka.main()方法中创建KafkaServer对象,然后调用KafkaServer.startup()方法启动broker。KafkaServer启动过程中创建KafkaController对象,并启动KafkaController。
class KafkaServer {
def startup() {
kafkaController = new KafkaController(config, zkClient, time, metrics, brokerInfo, brokerEpoch, tokenManager, threadNamePrefix)
kafkaController.startup()
}
}
KafkaController的启动过程如下图所示
KafkaController启动的主要步骤如下:
(1)在zooKeeperClient中注册controller的controller-state-change-handler状态变化处理器。
(2)在事件管理器eventManager中添加Startup启动事件。
(3)启动Controller事件处理线程,执行ControllerEventThread.run()方法,进入事件处理循环。事件处理线程执行的第一个任务为Startup启动事件。
ControllerEventThread线程的事件处理循环的运行逻辑如下图所示
(1)从ControllerEvent事件队列中取出一个事件。
(2)如果是ShutdownEventThread事件,执行关闭ControllerEventThread线程操作。
(3)如果不是ShutdownEventThread事件, 调用process()方法,执行相应的任务。
(4)如果调用process()方法抛出ControllerMovedException异常,表示当前broker节点失去controller角色,调用KafkaController.maybeResign(),执行controller转移操作。
(5)调用KafkaController.updateMetrics(),更新controller事件处理监控指标。
Startup启动事件的处理过程如下图所示
(1)监听"/controller"临时节点,回调处理器为ControllerChangeHandler。
(2)检查"/controller"临时节点。
(3)获取"/controller"节点的内容(保存的是单选为controller主节点的broker的Id),如果不是-1,表示主节点已经存在,结束Startup事件处理。
(4)如果是-1,通过zookeeper选举controller主节点。
(5)如果选举成功,调用onControllerFailover(),执行controller初始化操作。
(6)如果选举失败会抛出异常。对于ControllerMovedException异常,调用maybeResign()方法,执行controller释放操作。对于其他异常,调用triggerControllerMove()方法,主动放弃controller主节点角色。
KafkaController.onControllerFailover()的主要执行过程如下:
(1)监听"/brokers/ids"子节点,处理器为BrokerChangeHandler。
(2)监听“/brokers/topics"子节点,处理器为TopicChangeHandler。
(3)监听"/admin/delete_topics"子节点,处理器为TopicDeletionHandler。
(4)监听"/log_dir_event_notification"子节点,处理器为LogDirEventNotificationHandler。
(5)监听"/isr_change_notification"子节点,处理器为IsrChangeNotificationHandler。
(6)监听"/admin/preferred_replica_election"节点,处理器为PreferredReplicaElectionHandler。
(7)监听"/admin/reassign_partitions"节点,处理器为PartitionReassignmentHandler。
(8)调用KafkaController.initializeControllerContext()方法,初始化controller上下文。
(9)调用KafkaController.sendUpdateMetadataRequest()方法,向集群中活着的broker发送“修改元数据请求”。
(10)启动KafkaScheduler。
(11)启动AutoLeaderRebalace定时任务。
KafkaController.initializeControllerContext()的处理过程如下图所示
(1)从zookeeper获取"/brokers/ids"的所有子节点列表。
(2)从zookeeper获取所有"/borkers/ids/$borkerid"的内容,获取broker的ip,端口等信息。
(3)从zookeeper获取"/brokers/topics"的所有子节点列表,获取集群中所有的主题(topic)。
(4)监听所有"/brokers/topics/$topic"节点,处理器为PartitionModificationsHandler,监听各个主题的分区变化事件。
(5)从zookeeper获取所有主题节点"/brokers/topics/$topic"的内容,获取到所有主题的所有分区的副本。
(6)更新controller上下文(内存)中各个主题的各个分区的副本信息。
(7)清除controller上下文(内存)中的各个主题的各个主分区的信息。
(8)监听每一个"/brokers/ids/$brokerId"节点,处理器为BrokerModificationsHandler,监听各个broker节点的变化事件。
(9)从zookeeper获取所有主题的所有分区的状态信息,获取"/brokers/topics/$topic/partitions/$partition/state"节点内容。
(10)更新controller上下文(内存)中的分区的主分区,isr副本集合信息。
(11)调用startChannelManager()方法,把每个broker对应的ControllerBrokerStateInfo对象加入controller上下文(内存)中,启动每个broker的请求发送线程(RequestSendThread)。
KafkaController会为每一个broker节点创建一个RequestSendThread线程,用于向broker节点发送请求。
KafkaController.sendUpdateMetadataRequest()的处理过程如下图所示
(1)检查之前batch是否是空,如果不是空抛出异常。
(2)增加发送请求的broker集合。
(3)向各个broker的RequsetSendThread线程的消息队列添加ApiKeys.UPDATE_METADATA请求。请求内容如下图所示。