kafka教程-消费者分区分配策略(Range、RoundRobin、Sticky) 作者:马育民 • 2022-12-02 13:25 • 阅读:10244 # 提出问题 下图,主题中有 `3` 个分区,消费者组中有 `3` 个消费者,哪个消费者消费哪个分区的消息? 这就涉及到 Kafka 消费者的 **分区分配策略** [](/upload/0/0/1IX4oaLGDITK.png) # 分区分配策略 一个 consumer group 中有多个 consumer,一个 topic 有多个 partition 有两种策略,决定哪个 partition 由哪个 consumer 来消费: - Range,范围分区,默认使用 - RoundRobin,轮询分区 - sticky ## Range 让 **所有 consumer 平均消费 partition ** **默认策略** 对同一个topic中的 partition **按照序号排序**,并对 consumer **按照字典顺序排序** 为每个consumer划分固定的分区范围,如果不够平均分配,那么排序靠前的 consumer 会 **多分配分区** 如下图:因为 10除3除不尽,所以 consumer0 会多分配一个分区 [](https://www.malaoshi.top/upload/pic/kafka/QQ20210111210033.png) ### 缺点 如上,只是针对 1 个 topic 而言,消费者 `consumer0` 多消费1个分区影响不是很大。 如果有 N 多个 topic,那么针对每个 topic,消费者 `consumer0` 都将多消费 1 个分区,topic越多,`consumer0` 消费的分区会比其他消费者 **多消费 N 个分区**。 这就是 Range 范围分区的一个很明显的弊端了 **解决:**可通过 RoundRobin 轮询分区策略 ## RoundRobin 将消费组内所有消费者,消费者订阅的所有主题的分区按照字典序排序,然后通过轮询方式逐个将分区依次分配给每个消费者。 ### 情况一 同一个消费组内,所有的消费者的订阅信息都是 **相同** 的,那么分区分配是 **均匀** 的 #### 例子 消费组中有2个消费者,都订阅了主题 `t0` 和 `t1`,并且每个主题都有 `3` 个分区 订阅的所有分区可以标识为:`t0p0`、`t0p1`、`t0p2`、`t1p0`、`t1p1`、`t1p2` 分配结果如下图: [](/upload/0/0/1IX4ob6kKAWx.png) ``` 消费者C0:t0p0、t0p2、t1p1 消费者C1:t0p1、t1p0、t1p2 ``` ### 情况二 同一个消费组内,所有的消费者的订阅信息 **不相同**,那么在执行分区分配的时候就不是完全的轮询分配,有可能导致分区分配得 **不均匀** #### 例子 同一消费者组中,有3个消费者 `C0`、`C1` 和 `C2`,他们共订阅了 `3` 个主题: - t0,有1个分区(p0) - t1,有2个分区(p0、p1) - t2,有3个分区(p0、p1、p2)) 分区情况如下图: [](/upload/0/0/1IX4obKu40rL.png) ``` 消费者C0:t0p0 消费者C1:t1p0 消费者C2:t1p1、t2p0、t2p1、t2p2 ``` ### 缺点 从情况二可以看到 `RoundRobinAssignor` 策略也不是十分完美,这样分配其实并不是最优解 ### 类 ``` org.apache.kafka.clients.consumer.RoundRobinAssignor ``` # Sticky `sticky` 这个单词可以翻译为“黏性的”,Kafka 从 0.11.x 版本开始引入这种分配策略 目标: - 分区的分配要尽可能均匀 - 分区的分配尽可能与上次分配的保持相同 当两者发生冲突时,第一个目标优先于第二个目标。鉴于这两个目标,StickyAssignor 分配策略的具体实现要复杂得多。 ### 情况一:订阅信息相同 #### 例子 消费组内有3个消费者(C0、C1 和 C2),它们都订阅了4个主题(t0、t1、t2、t3),并且每个主题有2个分区。也就是说,整个消费组订阅了 t0p0、t0p1、t1p0、t1p1、t2p0、t2p1、t3p0、t3p1 这8个分区。 分配结果如下图: [](/upload/0/0/1IX4obaJU5De.jpg) ``` 消费者C0:t0p0、t1p1、t3p0 消费者C1:t0p1、t2p0、t3p1 消费者C2:t1p0、t2p1 ``` 看上去似乎与采用 RoundRobinAssignor 分配策略所分配的结果相同 #### 例子2 假设此时消费者 `C1` 脱离了消费组,那么消费组就会执行再均衡操作,进而消费分区会重新分配。 分配结果如下图: [](/upload/0/0/1IX4obnvFi75.png) ``` 消费者C0:t0p0、t1p1、t3p0、t2p0 消费者C2:t1p0、t2p1、t0p1、t3p1 ``` 可以看到分配结果中 **保留了上一次分配** 中对消费者 `C0` 和 `C2` 的所有分配结果,并将原来消费者 `C1` 的分区分配给了剩余的两个消费者 `C0` 和 `C2`,最终 `C0` 和 `C2` 的分配还保持了均衡。 ### 情况二:订阅信息不同 同样消费组内有3个消费者(C0、C1 和 C2),集群中有3个主题(t0、t1 和 t2),这3个主题分别有1、2、3个分区。 也就是说,集群中有 `t0p0、t1p0、t1p1、t2p0、t2p1、t2p2` 这6个分区。消费者 `C0` 订阅了主题 `t0`,消费者 `C1` 订阅了主题 `t0` 和 `t1`,消费者 `C2` 订阅了主题 `t0`、`t1` 和 `t2` 分配结果如下图: [](/upload/0/0/1IX4oc4twjUV.png) ``` 消费者C0:t0p0 消费者C1:t1p0、t1p1 消费者C2:t2p0、t2p1、t2p2 ``` 可以看到这才是一个最优解(消费者 C0 没有订阅主题 t1 和 t2,所以不能分配主题 t1 和 t2 中的任何分区给它,对于消费者 C1 也可同理推断) 参考: https://blog.csdn.net/qq_21383435/article/details/108720155 https://cloud.tencent.com/developer/article/1791969 原文出处:http://www.malaoshi.top/show_1IX4WGfvTBk5.html