kafka技术内幕读书笔记(七):控制器

Kafka 的控制器除了分区的分配、分区的选举,还有下面这些工作。
1.代理节点启动或下线时,处理代理节点的故障转移。
2.新创建或删除主题,或新增加分区时,处理分区的重新分配。
3.管理所有分区的状态机和副本的状态机, 处理状态机的变化事件。

控制器选举:

Kafka利用了ZK 的领导选举机制,每个代理节点都会参与竞选主控制器,但只有一个代理节点可以成为主控制器,其他代理节点只有在主控制器出现故障或者会话失效时参与领导选举。Kafka实现领导选举的做法是: 每个代理节点都会作为ZK的客户端,向ZK服务端尝试创建/controller临时节点,但最终只有一个代理节点可以成功创建/controller节点。由于主控制器创建的ZK节点是临时节点,因此当主控制器出现故障,或者会话失效时,临时节点会被删除。这时候所有的代理节点都会尝试重新创建/controller节点,并选举出新的主控制器。

控制器上下文:

Kafka最重要的两个概念是“主题”和“分区”, ZK 中主题节点记录了所有分区的副本,分区节点记录了分区的LeaderAndIsr信息。下面的示例假设管理员创建了名称为test 的主题,它有三个分区、三个副本。通过zkCli.sh 连接到ZK服务端,查询一些ZK节点的结果如下:

以主题test 为例,控制器上下文中用下面的两个变量表示Kafka集群的主题和分区信息。

1.partitionReplicaAssignment :分配给分区的所有副本。
2.partitionLeadershipInfo :分区的主副本、ISR 集合。

控制器上下文对象(下文简称“上下文”)可以认为是控制器工作时的数据存储和共享介质,控制器的具体动作主要通过事件的监昕器触发。“上下文”和事件监听器都与ZK有关,前者从ZK读取数据, 后者注册监听器到ZK节点。控制器、监昕器、ZK三者完成一次事件处理的步骤如下。

(1)“控制器”向“ZK节点”注册“监昕器” , 每种“监昕器”都有具体的事件处理逻辑。
  (2)管理员更新“ ZK节点”的数据,触发“监昕器”调用不同的回调方法( 比如子节点变化、数据变化)。

   (3)“控制器”执行具体的事件处理逻辑,处理完成后,再次注册“监昕器”,为下次事件触发做准备。

分区状态机和副本状态机:

状态机一般用在事件处理中,并且事件会有多种状态。当事件的状态发生变化时,会触发对应的事件处理动作。Kafka控制器启动状态机时有下面两个特点。

1.因为分区状态机和副本状态机需要分别获取集群的所有分区和所有副本,而初始化控制器上下文会从ZK读取集群的所有分区与副本,所以初始化控制器上下文后,才能启动状态机。
2.因为分区包含了多个副本, 只有集群中所有副本的状态都初始化完毕,才可以初始化分区的状态。所以控制器会先启动副本状态机,然后才启动分区状态机。

分区状态机和副本状态机分别维护集群中所有分区和副本的状态,它们的状态有四种: 新建( New ) 、在线( Online )、下线( Offline )、不存在( NonExistent )。如图7-4所示,从一个状态转变为另一个状态都对应了不同的事件。比如副本状态从“新建”转为“在线”,它对应的事件是副本在分区的集合中;分区状态从“新建”转为“在线”,它对应的事件是分区选举出了主副本。

下面列举了副本状态机中副本的状态和状态转移。
1.NewReplica 。新创建主题,重新分配分区时创建新副本,副本状态为“新建” 。该状态下副本只能收到“成为备份副本”的请求。
2.OnlineReplica 。 当副本启动,并且是分区副本集的一部分, 副本状态为“在线” 。该状态下可以收到“成为备份副本”或“ 成为主副本” 的请求。
3.OfflineReplica 。代理节点看机后,节点上的所有副本状态为“下线” 。
4.NonExistentReplica . 剧本被成功删除后,状态为“不存在” 。

下面列举了分区状态机中分区的状态和状态转移。
1.NonExistentPartition 。 分区没有创建或者创建后立即被删除掉, 状态为“不存在” 。
2.NewPartitlon 。新创建分区,状态为“新建” 。
3.OnlinePartitlon 。分区选举出主副本,状态为“上线” 。
4.OffllnePartition 。分区有主副本, 但是主副本所在的节点宕机了,状态为“下线” 。

 

图7-6总结了Kafka控制器(图中深色背景部分)创建主题的过程,主要步骤如下。
(1) 管理员创建主题,会在/brokers/topics/下创建主题的子节点。
(2)“更改主题监昕器”调用onNewTopicCreation ()方法,向ZK节点注册“更改分区监昕器”,并对所有分区调用onNewPa rtitionCreation()方法。
(3)控制器分别对分区、所有的副本进行状态转换,最后分区和副本都转为“上线状态”
(4)分区从“新建状态”,到“上线状态”,控制器会选举出主副本、创建分区状态的ZK节点、发送LeaderAndIsr请求给分区的所有副本(即图中下方的三个代理节点)。

为分区选举主副本时,优先从ISR 中选择第一个副本作为主副本。如果能够从ISR集合中选举主副本,可以保证数据不会丢失。如果ISR都挂了, 则选择AR 中第一个存活的副本作为主副本。这种场景下,从不在ISR 的副本集合中选举主副本后,丢失数据的可能性就比较大。选举分区的主副本,这个副本必须是存活的。

“最优副本选举”的目的是平衡分区,这是因为Kafka的分区分配算法保证了:分区的主副本会均匀分布在所有的代理节点上。如果频繁出现第一个副本不是主副本的情况,有可能某些节点上的分区主副本太集中了,就会对客户端的读写带来影响。分区平衡作为一个后台线程,会定时检查“最优的副本”(即第一个副本)是不是主副本。如果不是,在重新平衡分区时,控制器将最优的副本,也就是原来的主副本作为分区最新的主副本。

如图7-9 所示,假设主题的副本数为三个,四个分区[P1,P2,P3, P4 ) 分布在三个代理节点上,分区
[Pl,P4]的主副本在第一个代理节点上。当第一个代理节点宕机后,控制器为会分区[P1 , P4 ]重新选举主副本。比如,分区P1 新的主副本在第二个代理节点( Broker2 ),分区P4 新的主副本在第三个代理节点( Broker3 )。最后,这两个分区的状态从“下线”回到“上线” 。

删除主题流程:

如图7 - 18 所示,副本状态机处理副本状态转为“下线”“开始删除”, 都会发送StopReplica 请求给副本编号对应的代理节点。不同的是, 后者带有删除标记( deletePartition=true ),并传递了处理StopReplica响应的回调方法。正常情况下,被删除主题对应的副本状态从“下线” 到“开始删除” 在startReplicaDeletion ()方法中触发,从“开始删除”到“删除成功”在回调方法中触发。

重新分配分区流程:
重新分配分区之前,分区的AR和ISR等于RAR ; 重新分配分区之后,分区的AR和ISR都等于RAR 。RAR要能够作为分区的ISR,它里面的每个副本都应该赶上分区原来的主副本。如图7-21 所示,从具体的算法实现角度来看, RAR要先加入分区的AR中,然后在确保RAR都加入ISR后,才将OAR分别从AR和ISR中移除,这样才能保证重新分配分区后,分区的AR和ISR都等于RAR。重新分配分区的大致步骤如下。

(1)将RAR加入AR , 此时AR=OAR + RAR。
(2)将RAR加入ISR ,此时ISR = OAR+ RAR。
(3)   ISR不变,但分区的主副本从RAR中选举。
(4)将OAR从ISR中移除,此时ISR=RAR。
(5)将OAR从AR中移除,此时AR=RAR。

(1)  将ZK 中的AR更新为OAR + RAR (原始的副本集加上重新分配的副本集)。
  (2)  发送LeaderAndIsr请求给AR集合的每个副本。
  (3)  将RAR-OAR的新副本转换为“新建状态” 。
  (4)  等待RAR的所有副本都与旧的主副本同步,并加入ISR 。
  (5)  将RAR 的所有副本转换为“上线状态” 。
  (6)  将“上下文”中的AR设置为RAR。
  (7)  如果主副本不在RAR ,从RAR 中选举新的主副本,并发送LeaderAndIsr请求 。
  (8)  将OAR-RAR 的旧副本转换为“下线状态”,更新ZK 的JSR 、发送StopReplica请求。
  (9)  将OAR -RAR的旧副本转换为“不存在状态”,并将副本从磁盘上删除。
  (10)将ZK 中的AR设置为RAR 。
  (11)删除/admin/reassign_partition节点中分区对应的数据。
  (12)选举新主副本后, AR和JSR都变化,重新发送UpdateMetadata请求。

创建主副本、备份副本:

副本管理器的becol'leleaderOrFollower()方法处理Lea derAndIsr请求,具体步骤如下。

(1 )创建分区对象,如果分区已经存在,则使用LeaderAndIsr请求中的最新分区状态。
  (2)对“成为主副本”的分区调用makeleaders() 方法,为这些分区创建主副本。
  (3 )对“成为备份副本”的分区调用makeFollowers () 方法,为这些分区创建备份副本。
  (4)如果代理节点是第一次收到LeaderAndIsr请求, 则启动最高水位的检查点线程。

( 5 )移除空闲的拉取线程,并调用onleadershipChange () 回调方法。

分区与拉取管理器:

 

如图7-39 所示,当代理节点2 出现故障时,控制器为分区P 2选举的新主副本在代理节点3 上。除了正常的主副本与备份副本的状态转换(比如更新分区的主副本、AR 、ISR信息),代理节点3还需要调用loadGroupsForPartition () 方法恢复消费组group2 的元数据缓存。另外,由于分区的主副本发生变化,消费组group2联系的协调者也转为代理节点3 。

元数据缓存:

控制器发送LeaderAndIsr请求,一般只发送给分区副本对应的代理节点;但控制器发送UpdateMetadata 请求, 则会发送给所有存活的代理节点。

控制器向代理节点发送的请求类型有三种:分区的主副本和ISR信息( LeaderAndIsr)、更新元数据( UpdateMetadata )、停止副本( StopReplicas ) 。代理节点处理这三种请求,都会转交给副本管理器执行具体的业务逻辑。由于这三种请求都会更新分区的副本状态,因此这三个操作都会使用同一个对象锁( replicaStateChangeLock)进行同步。

服务端处理“控制器”发送的“更新元数据请求”( UpdateMetadata ),会调用元数据缓存对象( MetadataCache )的updateCache() 方法更新缓存。服务端处理“客户端”发送的“获取元数据请求”( Metadata ),会调用元数据缓存对象的getTopicMetadata () 方法,从缓存中构造主题的元数据信息。

 

展开阅读全文

没有更多推荐了,返回首页