Kafka 消费者分区策略

kafka 允许通过配置 partition.assignment.strategy 来改变消费组的分区策略。
kafka 提供了以下几个分区策略

  • RangeAssignor
  • RoundRobinAssignor
  • StickyAssignor

默认使用的是 RangeAssignor

同时,kafka 也允许我们自定义分区策略,只需要继承 AbstractPartitionAssignor 抽象类即可。

1、RangeAssignor

现假设有消费组 c1, c2,均订阅 t0, t1, 每个 topic 下均有 2 个分区 t0p0, t0p1, t1p0, t1p1
那么分区如下:

1
2
c1: t0p0, t1p0
c2: t0p1, t1p1

如果每个 topic 有 3 个分区,那么分配将会不均匀

1
2
c1: t0p0, t0p1,   t1p0, t1p1
c2: t0p2, t1p2

算法按照每个 topic 下的分区数,进行均分。

2、RoundRobinAssignor

将消费组按字典排序,然后轮询分配。
现假设有消费组 c1, c2。均订阅 t0, t1。 每个 topic 下均有 3 个分区。
分区如下

1
2
c1: t0p0, t0p2, t1p1
c2: t0p1, t1p0, t1p2

现假设有消费组 c1, c2, c3。其中
c1 订阅 t0,
c2 订阅 t1,
c3 订阅 t0, t1, t2,
t0 有 1 个分区 t0p0,
t1 有 2 个分区 t1p0, t1p1,
t2 有 3 个分区 t2p0, t2p1, t2p3
分区如下

1
2
3
c1: t0
c2: t1p0
c3: t1p1, t2p0, t2p1, t2p3

3、StickyAssignor

该分配策略,遵循以下 2 个原则

  1. 分区的分配要尽可能均匀
  2. 分区的分配要尽可能与上次分配的保持相同

两者发生冲突,第一个条件优先级大于第二个

现假设有消费组 c1, c2, c3。均订阅 t0, t1, 每个分区均有 3 个分区
分区如下

1
2
3
c1: t0p0, t1p0
c2: t0p1, t1p1
c3: t0p2, t1p2

可以看到,与 RoundRobinAssignor 算法相似。

再来看,不同消费组订阅的分区不一致时,会发生什么
现假设有消费组 c1, c2, c3。其中
c1 订阅 t0,
c2 订阅 t1,
c3 订阅 t0, t1, t2,
t0 有 1 个分区 t0p0,
t1 有 2 个分区 t1p0, t1p1,
t2 有 3 个分区 t2p0, t2p1, t2p3
分区如下

1
2
3
c1: t0p0
c2: t1p0, t1p1
c3: t2p0, t2p1, t2p3

这边贴一下 RoundRobinAssignor 算法的分区,进行对比

1
2
3
c1: t0p0
c2: t1p0
c3: t1p1, t2p0, t2p1, t2p3

可以看到 StickyAssignor 算法的分配比 RoundRobinAssignor 更优。就是 分区的分配要尽可能均匀

再假设如果 c1 退出订阅,这个时候,分区分配会怎么样?

1
2
c2: t0p0, t1p0, t1p1
c3: t2p0, t2p1, t2p3

4、总结

RocketMQ 建议 消费组只订阅一个 topic,在本人实际开发过程中也基本是如此。如果订阅多个 topic,消费组将无法正常工作。对于 kafka 而言,消费组可以订阅多个 topic 来说,确实是很灵活。