当消费者启动之后,kafka会为消费者分配分区进行消费。当消费者和分区的关系发生了变化之后,就会重新分配分区给消费者,例如:
- 某个消费者挂了
- 来了个新的消费者
- 主题增加了分区
重新分配分区这个动作就叫做Rebalance。
Rebalance过程
假设现在有3个分区,2个消费者c1和c2,然后新来了一个消费者c3,触发了Rebalance,整个过程如下:
- broker中的组协调者(Group Coordinator)收到c3的
Join Group
请求,知道有新消费者来了 - 组协调者在心跳中告知c1和c2
- c1和c2放弃已持有的分区,此时c1和c2也相当于一个新的消费者,给组协调者发送
Join Group
请求 - 组协调者按定好分配方案,将分配方案发给每个消费者
- 3个消费者开始消费
分配策略
分配分区有几种策略,可以使用partition.assignment.strategy
进行配置,默认值为:
org.apache.kafka.clients.consumer.RangeAssignor,org.apache.kafka.clients.consumer.CooperativeStickyAssignor
range策略
partition.assignment.strategy
设置为org.apache.kafka.clients.consumer.RangeAssignor
这种策略下,分配方式是在平均分的基础上,多出来的先给排在前面的消费者,举几个例子:
假设3个分区,3个消费者,则是每个消费者分配1个分区
假设4个分区,3个消费者,则是0,1分区给第一个消费,2,3分区分别给其他2个消费者
轮训策略
partition.assignment.strategy
设置为org.apache.kafka.clients.consumer.RoundRobinAssignor
这种策略下,分区会按顺序依次分配给消费者,例如有10个分区,3个消费者:
- 0分区给消费者0
- 1分区给消费者1
- 2分区给消费者2
- 3分区给消费者0
- 4分区给消费者1
- 依次类推
sticky策略
partition.assignment.strategy
设置为org.apache.kafka.clients.consumer.StickyAssignor
这是带有粘性的策略,它会在发生Rebalance时:
- 尽可能保持原来的分配关系
- 尽可能均匀的分配分区。
Cooperative Sticky策略
partition.assignment.strategy
设置为org.apache.kafka.clients.consumer.CooperativeStickyAssignor
这是2.4版本新增的策略,原有的sticky策略虽然可以尽量保证原有的分配分案,但是每一个消费者仍然需要先释放已持有的分区资源。
于是就有新Cooperative Sticky
策略,这个策略相比于旧的策略有什么优势呢?为此,我们需要先了解旧的策略有什么劣势。
在旧策略中,当发生再平衡时,会发生STW(Stop The Word):所有的消费者需要先放弃当前已经持有的分区资源,等待重新分配。
也就是说在这段时间内,主题资源处于不可用状态,直到rebalance结束,才会重新开始消费。
如果是大规模集群,这种大规模的STW是一种灾难。
而新的Cooperative Sticky
策略,将原来的一次大规模rebalance操作,拆分成了多次小规模的rebalance,直至最终平衡完成。
仍然假设现在有3个分区,2个消费者c1和c2,c1消费分区0和1,c2消费分区2。
然后新来了一个消费者c3,触发了Rebalance,具体步骤如下:
- 新消费者来时,组协调者通知消费者,和旧策略不同,c1,c2发送
Join Group
给组协调者时,不必放弃已持有的分区,并将当前持有的分区信息告知组协调者 - 组协调者综合现在所有的情况,通知c1放弃分区1,此时算一次小规模rebalance完成。
- 接着继续rebalance,将暂时无人消费的分区1分配给新来的c2即可,rebalance全部完成。