kafka消费者分区分配策略的魔鬼细节

  • Post author:
  • Post category:其他


消费者启动时通过参数partition.assignment.strategy指定消费者的分区策略

取值可以为:

  • org.apache.kafka.clients.consumer.RangeAssignor
  • org.apache.kafka.clients.consumer.RoundRobinAssignor
  • org.apache.kafka.clients.consumer.StickyAssignor
  • org.apache.kafka.clients.consumer.CooperativeStickyAssignor

其中CooperativeStickyAssignor是2.3版本之后新增的策略,在3.x版本之前partition.assignment.strategy的默认值值是RangeAssignor,在3.x版本之后默认值是RangeAssignor + CooperativeStickyAssignor。

默认的RangeAssignor策略在某些情况下会导致分区的倾斜,例如:

消费者C0、C1、C2订阅了主题T0、T1、T2,每个主题都只有一个分区。

如果使用默认的range分区策略,则会导致一下分配结果:

消费者C0:消费T0、T1、T2

消费者C1:无分区分配

消费者C2:无分区分配

这是情况下会导致所有数据都由第一个消费者处理,所以需要调整一下分区策略,使用RoundRobinAssignor、StickyAssignor、CooperativeStickyAssignor任意一个代替。

每种分区的具体分配规则及实现细节在kafka的源码类上是有注释的,还有分配的例子,可以自行观看我就不做二道贩子了。


kafka/StickyAssignor.java GitHub源码


kafka/RoundRobinAssignor.java GitHub源码


kafka/RangeAssignor.java GitHub源码


kafka/CooperativeStickyAssignor.java GitHub源码

这里面有提到新版是默认range + CooperativeSticky,就是partition.assignment.strategy是支持多个策略同时设置的,但具体是怎么生效的没有说明,经过自己的测试和stackoverflow上的讨论得到了以下几点:

  • 当有多个值的时候,按照顺序选择,例如range + CooperativeSticky,那么生效的是range
  • 既然配置多个只有第一个生效,那配置多个有什么意义?官方的例子是做滚动升级的场景?大致意思是例如旧版本机器是低版本的,使用的是range,你新版本的直接配置CooperativeSticky就会报错,使用range + CooperativeSticky就可以兼容旧版本,然后你逐步重启每个消费,升级为CooperativeSticky。group当前使用了CooperativeSticky,但是你的某个consumer配置了range是无法joinGroup的,会报错

既然range很容易导致分区分配的倾斜,那为什么还要默认用它?stackoverflow上也有个老哥提出了相同的问题。

Kafka RangeAssignor benefits over RoundRobin – Stack Overflow

只有一个答复说是range能让同一个topic下的分区连续分配给一个消费者,这样方便做连接操作,类似flink里面做流连接或是sql里面的join?



版权声明:本文为cs4290790原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。