Controller核心源码解析
下文基于Kafka 2.2对Controller进行分析,涉及内容较多,从Controller启动流程、选举流程、初始化工作、以及Controller的主要工作原理都有详细说明,还请大家耐心浏览
1、Controller启动流程【主要看写的源码注释】
/**
* KafkaController#startup中为每一个server都会启动一个eventManager
*
* 集群首次启动时,Controller 尚未被选举出来。
* 于是,Broker 启动后,首先将 Startup 这 个 ControllerEvent 写入到事件队列中,然后启动对应的事件处理线程和 ControllerChangeHandler ZooKeeper 监听器,
* 最后依赖事件处理线程进行 Controller 的选举。
* 在源码中,KafkaController 类的 startup 方法就是做这些事情的。
* 当Broker 启动时,它会调用这个方法启动 ControllerEventThread 线程。值得注意的是,每个 Broker 都需要 做这些事情,
* 不是说只有 Controller 所在的 Broker 才需要执行这些逻辑。
*
* 首先,startup 方法会注册 ZooKeeper 状态变更监听器,用于监听 Broker 与 ZooKeeper 之间的会话是否过期。
* 接着,写入 Startup 事件到事件队列,然后启动 ControllerEventThread 线程,开始处理事件队列中的 Startup 事件。
*/
def startup() = {
/**
* controller组件启动监听器的方式是在zk上面注册一个stateChangeHandler
* 在KafkaController.startup()方法中首先通过zk注册监听事件,监听StateChangeHandler
* registerStateChangeHandler用于session过期后触发重新选举
*
* 第1步:注册Zookeeper状态变更监听器,它是用于监听Zookeeper和broker会话过期的
*/
zkClient.registerStateChangeHandler(new StateChangeHandler {
override val name: String = StateChangeHandlers.ControllerHandler
override def afterInitializingSession(): Unit = {
eventManager.put(RegisterBrokerAndReelect)
}
override def beforeInitializingSession(): Unit = {
val expireEvent = new Expire
eventManager.clearAndPut(expireEvent)
// Block initialization of the new session until the expiration event is being handled,
// which ensures that all pending events have been processed before creating the new session
/**
* 阻塞等待时间被处理结束,session过期触发重新选举,必须等待选举这个时间完成Controller才能正常工作
*/
expireEvent.waitUntilProcessingStarted()
}
})
/** Startup是一个ControllerEvent,ControllerEventThread会执行它的process方法
* Startup 类型的 ControllerEvent 被放入到 eventmanager中,被 KafkaController#process 方法调用,在下面有定义
* 在Startup的回调方法process()中,首先在zk中监听/controller路径。并且调用elect()进行选举过程。
*
* case object Startup extends ControllerEvent {
* def state = ControllerState.ControllerChange
* override def process(): Unit = {
* zkClient.registerZNodeChangeHandlerAndCheckExistence(controllerChangeHandler)
* // elect就是尝试竞选controller
* elect()
* }
* }
*
* 调用elect(),进行选举,在onControllerFailover()中
* 放入Startup并启动eventManager后台线程开始选举, Startup 是个事件
*
* put 方法 在 core/src/main/scala/kafka/controller/ControllerEventManager.scala#def put(event: ControllerEvent): Unit = inLock(putLock) {
* 第2步:写入Startup事件到事件队列
*/
eventManager.put(Startup)
/** 启动了ControllerEventManager
* KafkaController#startup 中为每一个 server 都会启动一个 eventManage
* 启动eventManager来处理event queue中的任务
*
* ControllerEventThread在
* core/src/main/scala/kafka/controller/ControllerEventManager.scala中定义
*
* 第3步:内部启动ControllerEventThread线程,开始处理事件队列中的ControllerEvent
*/
eventManager.start()
}
2、Controller选举流程【主要看写的源码注释】
/**
* elect方法是关于Controller选举的核心方法
* elect就是尝试竞选controller,如果我们当前节点真的被选为controller(onControllerFailover()–故障转移)
*