kafka消费者分区分配策略

2021-11-05 09:19:45 浏览数 (1)

概述

kakfa的topic有多个partition,而消费端是以消费组为单元进行分区的消息,那么如何将一个topic下面的partition合理的分配给消费者中的消费者。Kafka有几种分配策略

RangeAssignor

RangeAssignor 策略是基于每个topic之上的,对于每个topic而言,kafka 列出可用的分区,对于每个topic,我们按数字顺序排列可用分区,以消费者的名称的词典顺序列出消费者。然后,我们将分区数量除以消费者总数,以确定分配给每个消费者的分区数量。如果它不均匀地划分,那么前几个消费者将有一个额外的分区。

如下图,有topic t1 和 消费组,t1 有四个分区,消费组有三个消费者。

分区依次为:t1.p0,t1.p1,t1.p2,t1.p3

假设N = 分区数,M=消费者数量

N/M = 4/3 = 1

N%M = 4%3 = 1

分配:前(N%M)个消费者,分配N 1(1 1) = 2 个分区,其余的消费者分配 N 个

所以,最终的分配结果就是:

c0: t1.p0,t1.p1

c1: t1.p2

c2:t1.p3

如果同时订阅了多个主题,则按每个主题分配后,会出现不均衡的情况,如下图,有两个主题t1和t2

分配后的结果为:

c0: t1.p0, t1.p1, t2.p0,t2.p1

c1: t1.p2, t2.p2

c2: t1.p3, t2,p3

RoundRobinAssignor

循环赋值器列出所有可用分区和所有可用使用者。然后,它继续执行从分区到使用者的循环分配。如果所有使用者实例的订阅都相同,则分区将均匀分布。(即,所有使用者的分区所有权计数都将在正好1的增量范围内。)

如上图,假设有两个消费者C0和C1,两个主题t0和t1,每个主题有3个分区,从而得到分区t0p0、t0p1、t0p2、t1p0、t1p1和t1p2。

分配结果为:

  • C0: [t0p0, t0p2, t1p1]
  • C1: [t0p1, t1p0, t1p2]

如上图,当消费者实例之间的订阅不同时,分配过程仍然以循环方式考虑每个用户实例,但如果实例未订阅主题,则跳过该实例。与订阅相同的情况不同,这可能导致分配不平衡。例如,我们有三个消费者C0、C1、C2和三个主题t0、t1、t2,分别有1、2和3个分区。因此,分区为t0p0、t1p0、t1p1、t2p0、t2p1、t2p2。C0认购t0;C1认购t0、t1;C2被订阅到t0、t1、t2。

分配结果为:

C0: [t0p0]

C1: [t1p0]

C2: [t1p1, t2p0, t2p1, t2p2]

由于引入了静态成员身份,我们可以利用group.instance.id使分配行为更具粘性。例如,我们有三个消费者,分配了member.id C0、C1、C2、两个主题t0和t1,每个主题有3个分区,从而产生了分区t0p0、t0p1、t0p2、t1p0、t1p1和t1p2。我们选择根据ephemeral member.id执行排序顺序。如下图:

分配结果为:

C0: [t0p0, t1p0]

C1: [t0p1, t1p1]

C2: [t0p2, t1p2] 组协调员将尝试向使用者分配新的

在一次重新均衡后,组协调员将尝试向使用者分配新的memberid,例如C0->C5 C1->C3,C2->C4。 任务可以完全转移到, 如下图:

C4(是 C2):[t0p1,t1p1](在was[t0p2,t1p2]之前)

C3(是C1):[t0p0,t1p0](之前是[t0p1,t1p1])

C5(是C0):[t0p2,t1p2](之前是[t0p0,t1p0])

这个问题可以通过引入静态成员来缓解。 消费者将拥有单独的实例 ID I1、I2、I3。 只要

1. 跨代成员数量保持不变 2. 静态成员的身份跨代保持不变 3. 任何成员的订阅模式都不会改变

分配结果一直会是:

I0: [t0p0, t1p0]

I1: [t0p1, t1p1]

I2: [t0p2, t1p2]

StickyAssignor

粘性分配器有两个目的。首先,它保证分配尽可能平衡,它有两个目的:

  • 分配给消费者的topic partition个数最多相差1个;或者
  • 主题分区比其他消费者少 2 的每个消费者无法将这些主题分区中的任何一个转移到它。

其次,当发生重新分配时,它尽可能多地保留现有分配。当主题分区从一个消费者移动到另一个消费者时,这有助于节省一些开销处理。

重新开始它可以通过将分区尽可能均匀地分布在消费者身上来工作。尽管这听起来与循环分配器的工作方式相似,但下面的第二个示例表明事实并非如此。在重新分配期间,它将以这样一种方式执行重新分配,即在新分配中

  1. 主题分区仍然尽可能均匀地分布
  2. 主题分区尽可能地保留在其先前分配的消费者中。

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

例 1.假设有 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被删除并且重新分配即将发生。

循环分配器将产生:

  • C0: [t0p0, t1p0, t2p0, t3p0]
  • C2: [t0p1, t1p1, t2p1, t3p1]

而粘性分配器会导致:

  • C0 [t0p0, t1p1, t3p0, t2p0]
  • C2 [t1p0, t2p1, t0p1, t3p1]

保留所有以前的分配(与循环分配器不同)

示例 2.有 3 个消费者C0、C1、C2和 3 个主题t0、t1、t2,分别具有 1、2 和 3 个分区。因此,分区为t0p0、t1p0、t1p1、t2p0、 t2p1、t2p2。C0已订阅t0;C1已订阅 t0, t1; 并C2订阅了t0, t1, t2。循环分配器将提出以下分配:

  • C0 [t0p0]
  • C1 [t1p0]
  • C2 [t1p1, t2p0, t2p1, t2p2]

这不像粘性分配器建议的分配那样平衡:

  • C0 [t0p0]
  • C1 [t1p0, t1p1]
  • C2 [t2p0, t2p1, t2p2]

现在如果消费者C0被移除,这两个分配器将产生以下分配。

循环(保留 3 个分区分配):

  • C1 [t0p0, t1p1]
  • C2 [t1p0, t2p0, t2p1, t2p2]

粘性(保留 5 个分区分配):

  • C1 [t1p0, t1p1, t0p0]
  • C2 [t2p0, t2p1, t2p2]

0 人点赞