【1】控制器:Controller
Kafka是分布式消息传输系统,所以存在多个Broker服务节点,但是它的软件架构采用的是分布式系统中比较常见的主从(Master - Slave)架构,也就是说需要从多个Broker中找到一个用于管理整个Kafka集群的Master节点,这个节点,我们就称之为Controller。
它是Apache Kafka的核心组件非常重要。它的主要作用是在Apache Zookeeper的帮助下管理和协调控制整个Kafka集群。
如果在运行过程中,Controller节点出现了故障,那么Kafka会依托于ZooKeeper软件选举其他的节点作为新的Controller,让Kafka集群实现高可用。
Kafka集群中Controller的基本功能:
- Broker管理
- 监听 /brokers/ids节点相关的变化:
- Broker数量增加或减少的变化
- Broker对应的数据变化
- Topic管理
- 新增:监听 /brokers/topics节点相关的变化
- 修改:监听 /brokers/topics节点相关的变化
- 删除:监听 /admin/delete_topics节点相关的变化
- Partation管理
- 监听 /admin/reassign_partitions节点相关的变化
- 监听 /isr_change_notification节点相关的变化
- 监听 /preferred_replica_election节点相关的变化
- 数据服务
- 启动分区状态机和副本状态机
【2】选举机制
① 如何实现Kafka的节点选举
Kafka集群中含有多个服务节点,而分布式系统中经典的主从(Master - Slave)架构就要求从多个服务节点中找一个节点作为集群管理Master,Kafka集群中的这个Master,我们称之为集群控制器Controller
如果此时Controller节点出现故障,它就不能再管理集群功能,那么其他的Slave节点该如何是好呢?
如果从剩余的2个Slave节点中选一个节点出来作为新的集群控制器是不是一个不错的方案,我们将这个选择的过程称之为:选举(elect)。Kafka是依赖于ZooKeeper软件实现Broker节点选举功能。
ZooKeeper如何实现Kafka的节点选举呢?这就要说到我们用到ZooKeeper的3个功能:
- 一个是在ZooKeeper软件中创建节点Node,创建一个Node时,我们会设定这个节点是持久化创建,还是临时创建。所谓的持久化创建,就是Node一旦创建后会一直存在,而临时创建,是根据当前的客户端连接创建的临时节点Node,一旦客户端连接断开,那么这个临时节点Node也会被自动删除,所以这样的节点称之为临时节点。
- ZooKeeper节点是不允许有重复的,所以多个客户端创建同一个节点,只能有一个创建成功。
- 另外一个是客户端可以在ZooKeeper的节点上增加监听器,用于监听节点的状态变化,一旦监听的节点状态发生变化,那么监听器就会触发响应,实现特定监听功能。
Kafka是如何利用ZooKeeper实现Controller节点的选举的:
- 第一次启动Kafka集群时,会同时启动多个Broker节点,每一个Broker节点就会连接ZooKeeper,并尝试创建一个临时节点 /controller
- 因为ZooKeeper中一个节点不允许重复创建,所以多个Broker节点,最终只能有一个Broker节点可以创建成功,那么这个创建成功的Broker节点就会自动作为Kafka集群控制器节点,用于管理整个Kafka集群。
- 没有选举成功的其他Slave节点会创建Node监听器,用于监听 /controller节点的状态变化。
- 一旦Controller节点出现故障或挂掉了,那么对应的ZooKeeper客户端连接就会中断。ZooKeeper中的 /controller 节点就会自动被删除,而其他的那些Slave节点因为增加了监听器,所以当监听到 /controller 节点被删除后,就会马上向ZooKeeper发出创建 /controller 节点的请求,一旦创建成功,那么该Broker就变成了新的Controller节点了。
总结来讲就是broker节点进行抢占,谁先抢占到谁就是Controller,其他则监听该节点。如果Controller挂掉,其他节点继续抢占去成为Controller。
② 脑裂现象
有一种特殊的情况,就是Controller节点并没有宕掉,而是因为网络的抖动,不稳定,导致和ZooKeeper之间的会话超时。那么此时,整个Kafka集群就会认为之前的Controller已经下线(退出)从而选举出新的Controller,而之前的Controller的网络又恢复了,以为自己还是Controller了,继续管理整个集群。
那么此时,整个Kafka集群就有两个controller进行管理,那么其他的broker就懵了,不知道听谁的了,这种情况,我们称之为脑裂现象。
为了解决这个问题,Kafka通过一个任期(epoch:纪元)的概念来解决。也就是说,每一个Broker当选Controller时,会告诉当前Broker是第几任Controller。一旦重新选举时,这个任期会自动增1。那么不同任期的Controller的epoch值是不同的,那么旧的controller一旦发现集群中有新任controller的时候,那么它就会完成退出操作(清空缓存,中断和broker的连接,并重新加载最新的缓存),让自己重新变成一个普通的Broker。