分区分配指的是Kafka依据什么样的分配方式将多个主题中的多个分区与多个消费者进行对应。

Range

按范围分配。对于每个主题,我们按数字顺序排列可用分区,并按字典顺序排列消费者。然后,我们将分区数除以消费者总数,以确定要分配给每个消费者的分区数。如果它不能平均分配,那么前几个消费者将会有一个额外的分区。

partition数/consumer数

比如现在有两个消费者
C0C1
两个主题
t0t1
每个主题有3个分区,结果如下
t0p0, t0p1, t0p2, t1p0, t1p1, t1p2

最终分配结果如下
C0: [t0p0, t0p1, t1p0, t1p1]
C1: [t0p2, t1p2]

这种方式的弊端在于如果分区和消费者不能平均分配的话就会造成前几个消费者多分配分区,导致资源负载不均衡。

RoundRobin

循环分配将列出所有可用分区和所有可用的消费者。然后,它继续执行从分区到消费者的循环分配。如果所有消费者实例的订阅都相同,则分区将被均匀分布。(也就是说,分区所有权计数将在所有消费者中正好为1的增量范围内。)

两个消费者
C0C1
两个主题
t0t1
每个主题有3个分区,结果如下
t0p0, t0p1, t0p2, t1p0, t1p1, t1p2

结果如下:
C0: [t0p0, t0p2, t1p1]
C1: [t0p1, t1p0, t1p2]

当消费者实例的订阅不同时,指派过程仍会以循环方式考虑每个消费者执行个体,但如果实例没有订阅主题,则会跳过该实例。与订阅相同的情况不同,这可能导致分配不平衡。

比如有3个消费者
C0, C1, C2
3个主题,3个主题分别有1个、2个和3个分区
t0, t1, t2,
那么得到的主题分区关系如下
t0p0, t1p0, t1p1, t2p0, t2p1, t2p2.

假设:
C0 订阅 t0;
C1 订阅 t0, t1;
C2 订阅 t0, t1, t2.

最终分配结果如下:
C0: [t0p0]
C1: [t1p0]
C2: [t1p1, t2p0, t2p1, t2p2]

所以这种分配方式的问题在于,如果消费者之间订阅的主题不相同时,则会造成资源分配不均衡。

Sticky

我们可以叫他粘粘性分配策略。这种策略主要有两个用途:

首先,它保证分配尽可能平衡,数字分配给消费者的主题分区的数目最多相差一个;或者每个消费者比其他消费者少2个以上的主题分区,则无法将这些主题分区中的任何一个传送给它。

其次,当分区再均衡发生时,它保留了尽可能多的现有赋值。这有助于在主题分区从一个消费者移动到另一个消费者时节省一些开销处理。

上面的第一个目标优先于第二个目标。

实际上为了实现这两个目标,这种分配策略要比前两种分配策略复杂的多。

第一种场景

3个消费者,每个消费者都订阅了所有主题
C0, C1, C2
4个主题
t0, t1, t2, t3
每个主题有2个分区,得到结果如下
t0p0, t0p1, t1p0, t1p1, t2p0,t2p1, t3p0, t3p1

分配结果如下:
C0: [t0p0, t1p1, t3p0]
C1: [t0p1, t2p0, t3p1]
C2: [t1p0, t2p1]

现在假设C1消费者被删除了,即将发生分区再均衡,如果是RoundRobin策略,则结果为:
C0: [t0p0, t1p0, t2p0, t3p0]
C2: [t0p1, t1p1, t2p1, t3p1]

而按照Sticky策略,则结果为:
C0 [t0p0, t1p1, t3p0, t2p0]
C2 [t1p0, t2p1, t0p1, t3p1]

很明显Sticky策略,保留所有以前的分配。

第二种场景
3个消费者
C0, C1, C2
3个主题
t0, t1, t2
3个主题分别有1个、2个和3个分区,得到结果如下
t0p0, t1p0, t1p1, t2p0,t2p1, t2p2.
假设:
C0 订阅 t0;
C1 订阅 t0, t1;
C2 订阅 t0, t1, t2.

上文已经介绍过了按照RoundRobin的分配结果如下:
C0: [t0p0]
C1: [t1p0]
C2: [t1p1, t2p0, t2p1, t2p2]

Sticky的分配结果则如下:
C0 [t0p0]
C1 [t1p0, t1p1]
C2 [t2p0, t2p1, t2p2]

现在假设C0消费者被删除了

RoundRobin重新分配结果如下:
C1 [t0p0, t1p1]
C2 [t1p0, t2p0, t2p1, t2p2]
分配结果保留了3个分区未被移动。

Sticky重新分配结果如下:
C1 [t1p0, t1p1, t0p0]
C2 [t2p0, t2p1, t2p2]
分配结果保留了5个分区未被移动。

使用粘性分配策略还可以为那些在onPartitionsRevoked()回调监听器中有一些分区清理代码的消费者提供一些优化。清理代码放在回调监听器中,因为消费者在使用range或round-robin策略时,不会假设或希望在分区再均衡后留其分配的任何分区。

如上所述,sticky assignor的一个优点是,一般来说,它减少了在重新分配期间实际从一个消费者移动到另一个消费者的分区的数量。因此,它可以让消费者更有效地进行清理。当然,它们仍然可以在onPartitionsRevoked()监听器中执行分区清理,但它们可以更高效地在分区再均衡之前和之后记录下自己的分区,并且在分区再均衡之后只对丢失的分区进行清理(这通常不是很多)。

Logo

Kafka开源项目指南提供详尽教程,助开发者掌握其架构、配置和使用,实现高效数据流管理和实时处理。它高性能、可扩展,适合日志收集和实时数据处理,通过持久化保障数据安全,是企业大数据生态系统的核心。

更多推荐