快来看关于kafka分区副本重分配的一个Bug

简介: 【kafka】关于kafka分区副本重分配的一个Bug

注意我这里说的是 ”可能“ , 那么到底是不是bug,

需要你看完这篇文章之后做出判断, 欢迎留言一起讨论!

【领取kafka大全PDF】: https://www.szzdzhp.com/szzInfo.html

这个 " Bug " ,发生在分区副本进行分配的时候, 为了让大家更好的理解,我把kafka里面所有情况的分区分配规则给大家详细讲解一下 「 不想看过程,可以直接看最后的总结部分 」

在kafka需要进行分区副本分配计算的地方有三个地方

  1. 「 Topic创建 」的时候
  2. 「 分区扩容 」的时候
  3. 「 分区副本重分配 」的时候

副本分配方式

副本分配的几个原则:

  1. 将副本平均分布在所有的 Broker 上;
  2. partition 的多个副本应该分配在不同的 Broker 上;
  3. 如果所有的 Broker 有机架信息的话, partition 的副本应该分配到不同的机架上。
这里我们为了描述简单,不分析有机架的情况

不管是什么时候的分配规则,最终调用的都是下面这个方法,为了分析分配情况,我加了一些日志
在这里插入图片描述
通过这个分配方法我们可以得知,影响最终分配的方式有几个变量

  1. Broker List 的顺序
  2. 起始随机分配BrokerID startIndex
  3. 第一个副本跟第二个副本的 起始间隔偏移量 nextReplicaShift

我们通过 创建Topic的情景来分析一下整体的分配规则;

创建Topic分区分配

创建Topic流程请看 TODO...

我们先看一个副本的分配情况

启动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)

在这里插入图片描述

起始随机startIndex:2currentPartitionId:0;起始随机nextReplicaShift:4;brokerArray:ArrayBuffer(0, 1, 4, 2, 3)
(p-0,ArrayBuffer(4, 2, 3))
(p-1,ArrayBuffer(2, 3, 0))
(p-2,ArrayBuffer(3, 0, 1))
(p-3,ArrayBuffer(0, 1, 4))
(p-4,ArrayBuffer(1, 4, 2))
变更nextReplicaShift:5
(p-5,ArrayBuffer(4, 3, 0))
(p-6,ArrayBuffer(2, 0, 1))
(p-7,ArrayBuffer(3, 1, 4))
(p-8,ArrayBuffer(0, 4, 2))
(p-9,ArrayBuffer(1, 2, 3))

这个得到的排列最终会写的zk中, 这些就是AR的值; 第一个为Leader

  1. Broker List = {0,1,4,2,3}
  2. startIndes = 2
  3. nextReplicaShift = 4 这里跟 nextReplicaShift = 0 是一样的 (nextReplicaShift%(BrokerSize-1))

这里跟单副本的时候基本上参数是一样, nextReplicaShift = 4 表示的是 第一副本和第二副本起始间隔4, 总共5个Broker,最终效果和起始0间隔是一样的,可以看下图,
在这里插入图片描述
这个间隔的含义理解了,那我们看看这个整体的分配布局
在这里插入图片描述

从这里我们不难看出:

随机的startIndex 可以尽量的让Leader不会分区堆积的情况,如果每次都是从0开始,那么每个Topic创建的时候第一个分区都落在0,假设分区不多,那么就会全部堆积到前面的Broker中,后面的Broker分配不到;

nextReplicaShitf: 尽量让单个Topic的副本分配的更散列一些

分区扩容分配方式

分区扩容的情况,也是调用上面的方法,分配规则都是一样的; 但是入参却又有一些不一样

不一样的地方,我把关键scala代码贴出来看看

在这里插入图片描述

最终也是调用了AdminUtils.assignReplicasToBrokers方法; 但是入参有些不同

  1. Broker List allBrokers; 这里allBrokers是从下面方法里获取的,从zk里面拿到Brokers节点再进行排序之后的列表; 如{0,1,2,3,4,5}
    在这里插入图片描述
  2. startIndex: 在这里并不是一个随机值了,而是existingAssignmentPartition0.head获取的值; 这个表示的是当前Topic的第一个分区的第一个副本 在 Brokerlist中的索引值;
  3. nextReplicaShitf: 这里跟startIndex是一个值; 如果入参指定了startIndexnextReplicaShitf:跟它一样,如下图代码
    在这里插入图片描述
  4. startPartitionId: 这里的值是已经存在的分区数; 创建topic的时候这个值是0;
    在这里插入图片描述
那么那么把上面创建的t2(10分区,3副本), 执行一下分区扩容,扩容到13个;

在这里插入图片描述
在这里插入图片描述
这是扩分区后的情况, 因为这里刚好是 轮训两次再进行扩容的,可能看不出来问题,我们看另一个case

创建新Topic t5, 3个分区,1副本 如下
在这里插入图片描述
扩分区到5个,新增的分区分配如下
在这里插入图片描述
分配图
在这里插入图片描述

如果要均衡分配的话,至少是 1、1、1、1、1 才算是均衡,现在是直接有一个Broker没有用上了;

为什么会出现这种情况?

我们先分析一下 写这段代码的人想做什么?

上图左边是最终扩容之后的分配,右边是扩容时候的计算方式;
从上我们可以分析得出

  1. 分区扩容不会变更之前的分配情况,只会变更重新计算扩容的那部分分区的分配规则;
  2. 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的时候就是有序的,那么这里就肯定不会出现扩容分区不均匀的情况啊!

那我们接着分析 分区副本重分配的方式

分区副本重分配方式

分区副本重分配的源码解析过程请看: TODO...

这里就不再赘述了,直接抛出结果;

我们把上面扩容之后的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节点;

  1. 先排序了!!!
  2. 然后通过这个BrokerID又去zk获取每个Broker的具体信息
  3. 返回结果最终 toMap 了放到Map对象去了,所以这也就是为什么不是有序的原因了;

这里排序不是有一点脱裤子放屁💨多此一举的感觉吗

总结

那是不是bug呢? 我认为是的, 理由有以下几点

  1. 现有的情况,在扩分区的时候有可能会造成分区分配不均匀的情况
  2. 「 Topic创建 」的时候没有排序,可是「 扩分区」「 重分配 」 却又是排序了
  3. 的时候没有排序,可是「 扩分区」的时候,它的计算逻辑是按照原有的分配方式就是顺序的
  4. 如果创建的时候是顺序的,那么的时候没有排序,可是「 扩分区」造成分配不均匀的情况就不会出现
  5. 「 Topic创建 」的时候,它先是排序了,可是最后却放到Map里面了,如果它不是最终想排序,为啥一开始的时候就排序?,因为这里的排序完全没有必要;

以上是我分析的过程,和我的观点,水平有限,欢迎提出不同看法,评论区讨论!

【领取kafka大全PDF】【进滴滴技术交流群】: https://www.szzdzhp.com/szzInfo.html

相关文章
|
15天前
|
消息中间件 负载均衡 Kafka
【赵渝强老师】Kafka的主题与分区
Kafka 中的消息按主题分类,生产者发送消息到特定主题,消费者订阅主题消费。主题可分多个分区,每个分区仅属一个主题。消息追加到分区时,Broker 分配唯一偏移量地址,确保消息在分区内的顺序性。Kafka 保证分区有序而非主题有序。示例中,Topic A 有 3 个分区,分区可分布于不同 Broker 上,支持负载均衡和容错。视频讲解及图示详见原文。
|
24天前
|
消息中间件 监控 负载均衡
在Kafka中,如何进行主题的分区和复制?
在Kafka中,如何进行主题的分区和复制?
|
1月前
|
消息中间件 监控 负载均衡
在Kafka中,如何进行主题的分区和复制?
在Kafka中,如何进行主题的分区和复制?
|
15天前
|
消息中间件 Kafka
【赵渝强老师】Kafka分区的副本机制
在Kafka中,每个主题可有多个分区,每个分区有多个副本。其中仅有一个副本为Leader,负责对外服务,其余为Follower。当Leader所在Broker宕机时,Follower可被选为新的Leader,实现高可用。文中附有示意图及视频讲解。
|
1月前
|
消息中间件 存储 运维
为什么说Kafka还不是完美的实时数据通道
【10月更文挑战第19天】Kafka 虽然作为数据通道被广泛应用,但在实时性、数据一致性、性能及管理方面存在局限。数据延迟受消息堆积和分区再平衡影响;数据一致性难以达到恰好一次;性能瓶颈在于网络和磁盘I/O;管理复杂性涉及集群配置与版本升级。
|
1月前
|
消息中间件 Java Kafka
Flink-04 Flink Java 3分钟上手 FlinkKafkaConsumer消费Kafka数据 进行计算SingleOutputStreamOperatorDataStreamSource
Flink-04 Flink Java 3分钟上手 FlinkKafkaConsumer消费Kafka数据 进行计算SingleOutputStreamOperatorDataStreamSource
49 1
|
3月前
|
消息中间件 Java Kafka
Kafka不重复消费的终极秘籍!解锁幂等性、偏移量、去重神器,让你的数据流稳如老狗,告别数据混乱时代!
【8月更文挑战第24天】Apache Kafka作为一款领先的分布式流处理平台,凭借其卓越的高吞吐量与低延迟特性,在大数据处理领域中占据重要地位。然而,在利用Kafka进行数据处理时,如何有效避免重复消费成为众多开发者关注的焦点。本文深入探讨了Kafka中可能出现重复消费的原因,并提出了四种实用的解决方案:利用消息偏移量手动控制消费进度;启用幂等性生产者确保消息不被重复发送;在消费者端实施去重机制;以及借助Kafka的事务支持实现精确的一次性处理。通过这些方法,开发者可根据不同的应用场景灵活选择最适合的策略,从而保障数据处理的准确性和一致性。
300 9
|
3月前
|
消息中间件 负载均衡 Java
"Kafka核心机制揭秘:深入探索Producer的高效数据发布策略与Java实战应用"
【8月更文挑战第10天】Apache Kafka作为顶级分布式流处理平台,其Producer组件是数据高效发布的引擎。Producer遵循高吞吐、低延迟等设计原则,采用分批发送、异步处理及数据压缩等技术提升性能。它支持按消息键值分区,确保数据有序并实现负载均衡;提供多种确认机制保证可靠性;具备失败重试功能确保消息最终送达。Java示例展示了基本配置与消息发送流程,体现了Producer的强大与灵活性。
68 3
|
3月前
|
vr&ar 图形学 开发者
步入未来科技前沿:全方位解读Unity在VR/AR开发中的应用技巧,带你轻松打造震撼人心的沉浸式虚拟现实与增强现实体验——附详细示例代码与实战指南
【8月更文挑战第31天】虚拟现实(VR)和增强现实(AR)技术正深刻改变生活,从教育、娱乐到医疗、工业,应用广泛。Unity作为强大的游戏开发引擎,适用于构建高质量的VR/AR应用,支持Oculus Rift、HTC Vive、Microsoft HoloLens、ARKit和ARCore等平台。本文将介绍如何使用Unity创建沉浸式虚拟体验,包括设置项目、添加相机、处理用户输入等,并通过具体示例代码展示实现过程。无论是完全沉浸式的VR体验,还是将数字内容叠加到现实世界的AR应用,Unity均提供了所需的一切工具。
142 0
|
3月前
|
消息中间件 存储 关系型数据库
实时计算 Flink版产品使用问题之如何使用Kafka Connector将数据写入到Kafka
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
下一篇
无影云桌面