kafka
允许通过配置
partition.assignment.strategy
来改变消费组的分区策略。
kafka
提供了以下几个分区策略
RangeAssignor
RoundRobinAssignor
StickyAssignor
默认使用的是 RangeAssignor
同时,kafka
也允许我们自定义分区策略,只需要继承 AbstractPartitionAssignor
抽象类即可。
1、RangeAssignor
现假设有消费组 c1, c2
,均订阅 t0, t1
, 每个 topic
下均有 2 个分区 t0p0, t0p1, t1p0, t1p1
那么分区如下:
c1: t0p0, t1p0
c2: t0p1, t1p1
如果每个 topic
有 3 个分区,那么分配将会不均匀
c1: t0p0, t0p1, t1p0, t1p1
c2: t0p2, t1p2
算法按照每个 topic
下的分区数,进行均分。
2、RoundRobinAssignor
将消费组按字典排序,然后轮询分配。
现假设有消费组 c1, c2
。均订阅 t0, t1
。 每个 topic
下均有 3 个分区。
分区如下
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
分区如下
c1: t0
c2: t1p0
c3: t1p1, t2p0, t2p1, t2p3
3、StickyAssignor
该分配策略,遵循以下 2 个原则
- 分区的分配要尽可能均匀
- 分区的分配要尽可能与上次分配的保持相同
两者发生冲突,第一个条件优先级大于第二个
现假设有消费组 c1, c2, c3
。均订阅 t0, t1
, 每个分区均有 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
分区如下
c1: t0p0
c2: t1p0, t1p1
c3: t2p0, t2p1, t2p3
这边贴一下 RoundRobinAssignor
算法的分区,进行对比
c1: t0p0
c2: t1p0
c3: t1p1, t2p0, t2p1, t2p3
可以看到 StickyAssignor
算法的分配比 RoundRobinAssignor
更优。就是 分区的分配要尽可能均匀
再假设如果 c1 退出订阅,这个时候,分区分配会怎么样?
c2: t0p0, t1p0, t1p1
c3: t2p0, t2p1, t2p3
4、总结
RocketMQ
建议 消费组只订阅一个 topic,在本人实际开发过程中也基本是如此。如果订阅多个 topic
,消费组将无法正常工作。对于 kafka
而言,消费组可以订阅多个 topic
来说,确实是很灵活。