这个 bug, 你中招了吗!!!
在这里插入图片描述
kafka 管控平台推荐使用滴滴开源 的Kafka运维管控平台(戳我呀)更符合国人的操作习惯、更强大的管控能力、更高效的问题定位能力、更便捷的集群运维能力、更专业的资源治理、更友好的运维生态、
Hello~~ 大家好,我是石臻臻~~~~
在这里插入图片描述
今天这篇文章,给大家分享一下最近看 kafka 源码时候,困扰我几天的疑惑,供大家一起思考讨论,确定一下它是不是一个 Bug 欢迎留言一起探讨!
这个 " Bug ",发生在分区副本进行分配的时候, 为了让大家更好的理解,我把 kafka 里面所有情况的分区分配规则给大家详细讲解一下「 不想看过程,可以直接看最后的总结部分 」
在 kafka 需要进行分区副本分配计算的地方有三个地方
「 Topic 创建 」的时候
「 分区扩容 」的时候
「 分区副本重分配 」的时候
Part1 副本分配方式
副本分配的几个原则:
将副本平均分布在所有的 Broker 上;
partition 的多个副本应该分配在不同的 Broker 上;
如果所有的 Broker 有机架信息的话, partition 的副本应该分配到不同的机架上。
这里我们为了描述简单,不分析有机架的情况
不管是什么时候的分配规则,最终调用的都是下面这个方法,为了分析分配情况,我加了一些日志
通过这个分配方法我们可以得知,影响最终分配的方式有几个变量
Broker List
的顺序起始随机分配 BrokerID
startIndex
第一个副本跟第二个副本的 起始间隔偏移量
nextReplicaShift
我们通过 创建 Topic 的情景来分析一下整体的分配规则;
1 创建 Topic 分区分配
Topic 的创建可以看: 你知道Kafka创建Topic这个过程做了哪些事情吗?(附视频)
我们先看一个副本的分配情况
启动 5 个 Broker, 创建一个 Topic, 分区数 10 副本数 1
单副本分配
分配情况可以用如下图表示
起始随机索引是2
, 也就是说起始 BrokerId= Broker-4; 那么第一个副本 P0-1(Leader
)就从它开始分配了,后续的分配就是按照 BrokerList 就行遍历平均分配了,这样就让每个分区的Leader
副本都均匀的分配到了不同的 Broker 上; 因为是单副本分配,newxtReplicaShit
这个参数并没有用上;
多副本分配
启动 5 个 Broker, 创建一个 Topic, 分区数 10 副本数 3;(还是跟上面一样,但是这个时候将副本数变成 3 个; 创建一个新的 Topic = Test_Topic)
在这里插入图片描述
这个得到的排列最终会写的 zk 中, 这些就是 AR 的值; 第一个为 Leader
Broker List
= {0,1,4,2,3}startIndes
= 2nextReplicaShift
= 4 这里跟nextReplicaShift
= 0 是一样的 (nextReplicaShift%(BrokerSize-1)
)
这里跟单副本的时候基本上参数是一样, nextReplicaShift
= 4 表示的是 第一副本和第二副本起始间隔 4, 总共 5 个 Broker,最终效果和起始 0 间隔是一样的,可以看下图,
这个间隔的含义理解了,那我们看看这个整体的分配布局
从这里我们不难看出:
随机的startIndex
可以尽量的让 Leader 不会分区堆积的情况,如果每次都是从 0 开始,那么每个 Topic 创建的时候第一个分区都落在 0,假设分区不多,那么就会全部堆积到前面的 Broker 中,后面的 Broker 分配不到;
nextReplicaShitf:
尽量让单个 Topic 的副本分配的更散列一些
2 分区扩容分配方式
分区扩容的情况,也是调用上面的方法,分配规则都是一样的; 但是入参却又有一些不一样
不一样的地方,我把关键 scala 代码贴出来看看
在这里插入图片描述
最终也是调用了AdminUtils.assignReplicasToBrokers
方法; 但是入参有些不同
Broker List
是allBrokers
; 这里allBrokers
是从下面方法里获取的,从 zk 里面拿到 Brokers 节点再进行排序之后的列表; 如{0,1,2,3,4,5}
startIndex:
在这里并不是一个随机值了,而是existingAssignmentPartition0.head
获取的值; 这个表示的是当前 Topic 的第一个分区的第一个副本 在Brokerlist
中的索引值;nextReplicaShitf:
这里跟startIndex
是一个值; 如果入参指定了startIndex
则nextReplicaShitf:
跟它一样,如下图代码
startPartitionId:
这里的值是已经存在的分区数; 创建 topic 的时候这个值是 0;
那么那么把上面创建的 t2(10 分区,3 副本), 执行一下分区扩容,扩容到 13 个;
这是扩分区后的情况, 因为这里刚好是 轮训两次再进行扩容的,可能看不出来问题,我们看另一个 case
创建新 Topic t5, 3 个分区,1 副本 如下
扩分区到 5 个,新增的分区分配如下
分配图
如果要均衡分配的话,至少是 1、1、1、1、1 才算是均衡,现在是直接有一个 Broker 没有用上了;
为什么会出现这种情况?
我们先分析一下 写这段代码的人想做什么?
上图左边是最终扩容之后的分配,右边是扩容时候的计算方式;从上我们可以分析得出
分区扩容不会变更之前的分配情况,只会变更重新计算扩容的那部分分区的分配规则;
starIndex
是第一分区的第一个副本在排序之后的 BrokerList 中的索引值; 然后按照分配规则进行分配,并且这个时候有startPartitionId
截断前面的配置,只计算扩分区的这一部分;
从它这代码分析不就是想接着上一次继续分配吗?它把 Broker List 排序了; 然后又是接着原来的计算方式进行分配①. starIndex
会让起始的分区副本相同, ok,这个变量相同了②. nextReplicaShitf
这个变量不会影响分区的 Leader 均衡,它的作用是尽量的离散一下副本
上面 2 个变量确定了,那么只要保证 第三个变量 broker List
的顺序,那么分配肯定就跟创建的时候一样(排除手动改掉的情况); 也就会总体分配均衡了;那么实际情况 broker List
这个变量相同吗?
答案: 不相同!!!!!
创建的时候是 {0,1,4,2,3} 未经过排序扩分区的时候 {0,1,2,3,4} 经过了排序
为什么?为什么?为什么?
你要么就都排序,你要么就都接着用上一次的列表不好吗?
分析到这里, 我们已经肯定确定 分区扩容有可能会造成分区分区不均衡的情况虽然这种影响很小,你我可能根本感知不出来,但是如果整个集群批量做扩容的时候, 会不会就扩大了这个问题的影响范围呢?
到这里我们可能不能确定说它是一个 bug, 只是有一个怀疑的因子
但是如果创建 Topic 的时候就是有序的,那么这里就肯定不会出现扩容分区不均匀的情况啊!
那我们接着分析 分区副本重分配的方式
3 分区副本重分配方式
分区副本重分配的源码解析过程请看:3万字长文呕心沥血教你彻底搞懂数据迁移原理(附配套教学视频)
这里就不再赘述了,直接抛出结果;
我们把上面扩容之后的 topic = t5 来进行一下重分配,看看 kafka 会给我们推荐什么样子的分配方式;
在这里插入图片描述
看图,我可以分析得出, brokerList = {0,1,2,3,4} ;不管你执行几次 --generate
它的 brokerList 都是{0,1,2,3,4} 有序的;当然 startIndex
和 nextReplicaShift
都还是随机的;
至少重新分配之后, 分区是均衡的了
而且看源码, 是特意排序过的
凭什么只有创建 Topic 的时候不排序?
好,我思考思考,可能是有意为之,有一些其他的考量; 那么再贴出来创建 Topic 的时候 Broker List 的源码
再往上
在这里插入图片描述
在这里插入图片描述
重点是在最后一张图创建 Topic 拿到的 Broker List 是 Controller 初始化的时候去 zk 里面获取的 Broker 节点;
先排序了!!!
然后通过这个 BrokerID 又去 zk 获取每个 Broker 的具体信息
返回结果最终
toMap
了放到 Map 对象去了,所以这也就是为什么不是有序的原因了;
这里排序不是有一点脱裤子放屁💨多此一举的感觉吗
在这里插入图片描述
Part2 总结
那是不是 bug 呢? 我认为是的, 理由有以下几点
现有的情况,在扩分区的时候有可能会造成分区分配不均匀的情况
「 Topic 创建 」的时候没有排序,可是「 扩分区」、「 重分配 」却又是排序了
「 Topic 创建 」的时候没有排序,可是「 扩分区」的时候,它的计算逻辑是按照原有的分配方式就是顺序的
如果创建的时候是顺序的,那么「 扩分区」造成分配不均匀的情况就不会出现
「 Topic 创建 」的时候,它先是排序了,可是最后却放到 Map 里面了,如果它不是最终想排序,为啥一开始的时候就排序?,因为这里的排序完全没有必要;
以上是我分析的过程,和我的观点,水平有限,欢迎提出不同看法,评论区讨论!
在这里插入图片描述
版权声明: 本文为 InfoQ 作者【石臻臻的杂货铺】的原创文章。
原文链接:【http://xie.infoq.cn/article/3e65c284ccf373b391160e942】。未经作者许可,禁止转载。
评论