解决方案
您应该使用DefaultPartitioner 而不是RoundRobinPartitioner。
对 DefaultPartitioner.java 的评论说:
默认分区策略:
如果记录中指定了分区,则使用它
如果未指定分区但存在键,则根据键的散列选择分区
如果不存在分区或键,请选择在批处理已满时更改的粘性分区。
有关粘性分区的详细信息,请参阅 KIP-480。
不为您的生产者记录提供指定的分区号或分区键,然后粘性分区将起作用,这大致使您的 Kafka 分区上的记录均匀。见Tip #2: Learn about the new sticky partitioner in the producer API
内部
再次,我想解释一下为什么 RoundRobinPartitioner 总是不能以通常假定的循环方式工作。
RoundRobinPartitioner中的“partition()”只能保证调用partition()方法的数量分布是循环的,不足以保证我们在partition上的记录是偶数的。
注意KafkaProducer.doSend()中partition()的调用很奇怪(可能连续两次调用partition())。
当分区数为偶数时,此处的细微代码可能会导致分区分配不均。
假设我们有 4 个分区(0,1,2,3)和 8 条记录。
record 1 -> 2 **partition()** call(return 0, return 1), finally assigned to partition 1
record 2 -> 2 **partition()** call(return 2, return 3), finally assigned to partition 3
record 3 -> 2 **partition()** call(return 0, return 1), finally assigned to partition 1
record 4 -> 2 **partition()** call(return 2, return 3), finally assigned to partition 3
record 5 -> 2 **partition()** call(return 0, return 1), finally assigned to partition 1
....
看到了吗?记录只会分发到分区 1 和 3!
结论
RoundRobinPartitioner 有一个令人困惑的名字,它提供调用 partition() 的 RoundRobin,而不是 KafkaProducer.send() 的 RoundRobin。
为确保记录在所有分区中均匀分布,请使用 DefaultPartitioner!