Apache kafka Kafka循环分区器未将消息分发到所有分区
我试图使用Kafka的RoundRobinPartitioner类在所有分区上均匀地分发消息。我的卡夫卡主题配置如下: 名称:multischemakafkatopicodd 分区数目:16 复制因子:2 比方说,如果我生成100条消息,那么每个分区应该有6或7条消息。但是,我得到了类似的结果:Apache kafka Kafka循环分区器未将消息分发到所有分区,apache-kafka,kafka-producer-api,round-robin,partitioner,Apache Kafka,Kafka Producer Api,Round Robin,Partitioner,我试图使用Kafka的RoundRobinPartitioner类在所有分区上均匀地分发消息。我的卡夫卡主题配置如下: 名称:multischemakafkatopicodd 分区数目:16 复制因子:2 比方说,如果我生成100条消息,那么每个分区应该有6或7条消息。但是,我得到了类似的结果: sh /usr/hdp/current/kafka-broker/bin/kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list 10.0
sh /usr/hdp/current/kafka-broker/bin/kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list 10.0.55.211:9092 --topic multischemakafkatopicodd --time -1
multischemakafkatopicodd:0:26
multischemakafkatopicodd:5:0
multischemakafkatopicodd:10:24
multischemakafkatopicodd:15:0
multischemakafkatopicodd:13:0
multischemakafkatopicodd:8:26
multischemakafkatopicodd:2:26
multischemakafkatopicodd:12:24
multischemakafkatopicodd:14:24
multischemakafkatopicodd:9:0
multischemakafkatopicodd:11:0
multischemakafkatopicodd:4:26
multischemakafkatopicodd:1:0
multischemakafkatopicodd:6:24
multischemakafkatopicodd:7:0
multischemakafkatopicodd:3:0
我认为这可能是因为我没有生成足够的消息,所以我尝试使用1M记录,并将分区数设置为奇数:
主题:多模式
分区数目:31
复制因子:2
…我得到了这个。这一次,每个分区中的消息数量在某种程度上是均匀分布的
sh /usr/hdp/current/kafka-broker/bin/kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list 10.0.55.211:9092 --topic multischemakafkatopicodd --time -1
multischemakafkatopicodd:0:33845
multischemakafkatopicodd:5:34388
multischemakafkatopicodd:10:33837
multischemakafkatopicodd:20:33819
multischemakafkatopicodd:15:33890
multischemakafkatopicodd:25:34414
multischemakafkatopicodd:30:33862
multischemakafkatopicodd:26:34066
multischemakafkatopicodd:9:34088
multischemakafkatopicodd:11:34124
multischemakafkatopicodd:16:33802
multischemakafkatopicodd:4:34061
multischemakafkatopicodd:17:34977
multischemakafkatopicodd:3:34084
multischemakafkatopicodd:24:33849
multischemakafkatopicodd:23:34111
multischemakafkatopicodd:13:34062
multischemakafkatopicodd:28:33876
multischemakafkatopicodd:18:34098
multischemakafkatopicodd:22:34058
multischemakafkatopicodd:8:34079
multischemakafkatopicodd:2:33839
multischemakafkatopicodd:12:34075
multischemakafkatopicodd:29:34132
multischemakafkatopicodd:19:33924
multischemakafkatopicodd:14:34109
multischemakafkatopicodd:1:34088
multischemakafkatopicodd:6:33832
multischemakafkatopicodd:7:34080
multischemakafkatopicodd:27:34188
multischemakafkatopicodd:21:34684
我再次进行了相同的测试,但将分区的数量减少到了8个,我得到了这样的结果:我们可以清楚地看到,一些分区有接近15K的消息,而另一些分区有大约10K的消息:
multischemakafkatopicodd:0:155927
multischemakafkatopicodd:5:105351
multischemakafkatopicodd:1:107382
multischemakafkatopicodd:4:160533
multischemakafkatopicodd:6:158007
multischemakafkatopicodd:7:105608
multischemakafkatopicodd:2:157934
multischemakafkatopicodd:3:105599
我做错了什么吗?或者这就是它的工作原理?
为什么信息分布如此不平等
如果有人能帮我,那就太好了。谢谢。据我所知,分区器工作正常。但您必须了解生产商为了最大限度地提高性能所做的优化:
- 生产者不会为每个发送调用将每条消息生成到不同的分区,因为这样做会造成过度杀伤力
保证类似的分发,但可以发送批。这意味着,它将根据循环
的代码中执行的(而不是模数!)操作来缓冲一定数量的发送到分区的消息:RoundRobinPartitioner
int part = Utils.toPositive(nextValue) % availablePartitions.size();
nextValue
是一个AtomicInteger
,它为每个分区/发送调用增加1。因此,如果在该过程中没有分区被声明为不可用,那么剩余部分也将始终以1的增量递增(以循环方式递增,例如使用4个分区:0-1-2-3-0-1-2-3-…
)。如果发生这种情况,循环可能看起来像0-1-2-(partition4fails)-0-1-2-(partition4OK)-3-0-…
例子
- 带有4个分区的主题
- 每个分区的生产者分区器线程的缓冲区包含3条消息
新的原子整数(0)
)
当生成第9条消息时,第一个分区的缓冲区已经完成(因为它已经保存了3条消息),因此准备发送给kafka。如果在此处停止进程,则4个分区将如下所示:
Partition Offset
0 3
1 0
2 0
3 0
当生成第10条消息时,第二个分区的缓冲区也将准备就绪,可以从线路中发送,主题如下:
Partition Offset
0 3
1 3
2 0
3 0
Partition Offset
0 1000
1 1000
2 0
3 0
Partition Offset
0 2997
1 1996
2 999
3 998
在现实生活中,缓冲区通常包含大量的消息(这也可以被挖掘)。比如说,存储了1000条消息。对于相同的场景,分区如下所示:
Partition Offset
0 3
1 3
2 0
3 0
Partition Offset
0 1000
1 1000
2 0
3 0
Partition Offset
0 2997
1 1996
2 999
3 998
因此,增加分区之间的“视觉”差异。批处理大小/缓冲区大小越大,问题就越严重
这与生产者的partitioner
线程本身的性质有关:默认情况下,它不会独立地发送每条消息,而是存储它们,以便在每次代理调用时都能发送消息,从而优化系统性能
批处理是提高效率的主要驱动因素之一,并使
批处理卡夫卡制作者将尝试在内存中累积数据
并在单个请求中发送更大的批次
如果停止/启动生产者,这种不平衡可能会更加臭名昭著,因为它将重新启动机制,而不管先前选择的分区是什么(因此它可以开始发送到停止前刚刚选择的同一个分区,从而增加上次执行时与其他未选择分区的差异)
在新的执行中,缓冲区将全部为空,因此无论哪个分区接收最多,进程都将重新启动
因此,您可以在此处停止此过程:
Partition Offset
0 1000
1 1000
2 0
3 0
保存每个主题的消息数计数器的映射将重新启动,因为它不是来自生产者的代理类的一部分。如果生产者未正确关闭和/或刷新,则缓存的消息也将丢失。因此,在这个场景中,您得到的是前面逻辑的重复:
MsgN % Partitions Partition
0%4 0
1%4 1
2%4 2
3%4 3
(...)
这将在某个时刻导致这种情况:
Partition Offset
0 2000
1 2000
2 0
3 0
这是由于发送进程的非连续执行而产生的不平衡,但它超出了RoundRobinPartitioner
的范围,后者的本质是基于连续进程(不间断)
您可以通过在发送消息时检查每个分区的偏移量来验证此行为:仅当所选分区存储n消息时,下一个选中的分区将获得其批n消息
注:示例中显示的数字表示“完美”场景;在现实生活中,消息也可以被撤销、压缩、失败、刷新,而不管缓冲区大小、分区不可用等等,。。。导致偏移数,如问题中所示
最后一个刷新场景示例:
Partition Offset
0 1000
1 1000
2 0
3 0
进程已停止,但生产者已正确关闭并刷新其消息,因此主题如下:
Partition Offset
0 1997
1 1996
2 999
3 998
进程将重新启动。刷新第一个分区的缓冲区后,将如下所示:
Partition Offset
0 3
1 3
2 0
3 0
Partition Offset
0 1000
1 1000
2 0
3 0
Partition Offset
0 2997
1 1996
2 999
3 998
因此,增加了对该机制“公平”的困惑。但这不是它的错,因为分区器的映射、计数器和缓冲区中没有持久性。如果让流程连续几天不停地执行,您会发现它确实以“近乎相等”的方式平衡了消息
'sreleva