分区重分配指的是将分区的副本重新分配到不同的代理节点上。如果ZK节点中分区的副本的新副本集合和当前分区副本集合相同,这个分区就不需要重新分配了。
分区重分配是通过监听ZK的 /admin/reassign_partitions 节点触发的,Kafka也提供了相应的脚本工具进行分区重分配,使用方法如下:
其中 XXX.json 是分区重分配的JSON文件,格式如下:
假设主题 product 的分区数只有 {P0, P1},当执行上面的脚本时。此时会发现P4的分区对于 product 主题根本就不存在,此时就会忽略掉P4的副本迁移。对于P0和P1的副本重分配,可以简单的理解为下面的过程。
分区重分配命令接收
当使用脚本提交分区重分配时,接收命令的是 kafka.admin.ReassignPartitionsCommand#executeAssignment():
提交命令时,如果分区重分配还在进行,那么本次无法提交,意味着当前只能有一个执行的分区重分配。
重分配监听执行整体流程
当 /admin/reassign_partitions 被修改后,监听器会触发 PartitionReassignment 事件,其代码执行链如下所示:
下面我们看一下代码执行流程的展开。
分区重分配流程
控制器事件模型中 PartitionReassignment 事件,会触发调用processPartitionReassignment()。此时会注册监听ZK节点 /admin/reassign_partitions 变化,当重分配策略更新到ZK上时,该监听器就会被触发,然后执行分区重分配逻辑。
前置判断
对于是否需要分区重分配,在 maybeTriggerPartitionReassignment() 中做了一些判断取舍,其代码实现如下:
对于前置校验的流程如下:
1、如果topic已经设置了删除,不进行重分配(从需要副本迁移的集合中移除);
2、如果分区副本都不存活,不进行重分配;
3、如果新副本与已经存在的副本相同,不进行重分配;
4、注册ISR变化监听;
5、设置将要迁移的副本为不能删除;
6、调用 onPartitionReassignment() 执行重分配。
执行分区重分配
分区重分配的执行是在 onPartitionReassignment() 中实现的,下面说明一下官方给出的几个技术名词:
RAR:新分配的副本列表;
OAR:原先的分区副本列表;
AR:当前副本列表,随着分配过程不断变化;
RAR-OAR:RAR与OAR的差集,即需要创建、数据迁移的新副本;
OAR-RAR:OAR与RAR的差集,即迁移后需要下线的副本。
重分配的具体代码实现如下所示:
上面代码执行的过程描述如下:
1.将AR更新为OAR+RAR;
2.向上面AR(OAR+RAR)中的所有副本发送LeaderAndIsr请求;
3.新分配的副本状态更新为NewReplica(第2步中发送LeaderAndIsr时, 新副本会开始创建并且同步数据);
4.等待所有的RAR都在ISR中;
5.将副本状态设置为OnlineReplica;
6.将上下文中的AR设置为RAR;
7.新加入的副本已经同步完成, LeaderAndIsr都更新到最新的结果;
8-9.将旧的副本下线;
10.将ZK中的AR设置为RAR;
11.分区重分配完成, 从ZK /admin/reassign_partitions 节点删除迁移报文;
12.发送metadata更新请求给所有存活的broker;
重分配简单描述
通过代码层面看起来不是很好理解,下面简单描述一下执行过程:
1、创建新的副本,开始同步数据,等所有新副本都加入了ISR后,在RAR中进行Leader选举;
2、下线不需要的副本(OAR-RAR),下线完成后将AR(即RAR)信息更新到ZK中;
3、发送LeaderAndIsr给存活broker。
假如初始情况下,分区副本在 {1,2,3} 三个 Broker 上;重分配之后在{4,5,6}上,此时变化过程如下图所示:
参考:《Kafka技术内幕》、《Apache Kafka 源码剖析》、Kafka源码