跳转至

Kafka的"分蛋糕"艺术:分区是如何被巧妙分配的

分配算法的三大目标

这个分配算法的核心,就是要同时达成三个目标:

公平性 (Fairness): 保证每个 Broker 的工作量(承载的副本数量)大致相当,谁也别太闲,谁也别太累。

安全性 (Safety): 确保一个分区的多个副本(比如原始文件和复印件)必须存放在不同的 Broker上。否则一个 Broker 挂了,这个分区的所有数据就全没了。

容灾性 (Resilience - 高级): 如果配置了机架信息,就要确保一个分区的多个副本尽可能存放在不同的机架上,防止整个机架断电导致分区不可用。

为了同时实现这三个目标,Kafka 采用了一种非常聪明的、分两步走的"轮流坐庄"算法。

第一步:分配"负责人"(Assigning Leaders)

首先,Kafka 要为每一个分区(Partition)指定一个"负责人"(Leader)。它采用的是一种简单高效的轮询(Round-Robin)方式。

我们用一个简化的新例子:3个 Broker(B0, B1, B2),3个分区(P0, P1, P2)。

Kafka 会先随机选一个 Broker 作为起点,比如是 Broker 1。

然后就像发牌一样,开始轮流分配"首领"职责:

分区0 的首领给 Broker 1

分区1 的首领给 Broker 2

分区2 的首领给 Broker 0 (因为到头了,从0开始)

这一步完成后,每个分区的"负责人"就被均匀地散布在了不同的 Broker 上,初步实现了负载均衡。

第二步:分配"备份人"(Assigning Followers)

"负责人"定好了,接下来就要为每个分区安排"备份人"(Follower)了。这里的算法同样巧妙,它是在上一步的基础上,进行偏移轮询。

我们来看这个新例子,复制系数为2(即1个首领+1个跟随者):

分区0的分配过程

我们知道它的首领在 Broker 1 上。

它的第1个(也是唯一一个)跟随者,就分配给 Broker 1 的下一个 Broker,也就是 Broker 2。

结果:分区0的2个副本分别位于 Broker 1(L), 2(F),完美地分散开了。

分区1的分配过程

我们知道它的首领在 Broker 2 上。

它的跟随者,就分配给 Broker 2 的下一个 Broker,也就是 Broker 0。

结果:分区1的2个副本分别位于 Broker 2(L), 0(F),同样完美分散。

分区2的分配过程

我们知道它的首领在 Broker 0 上。

它的跟随者,就分配给 Broker 0 的下一个 Broker,也就是 Broker 1。

结果:分区2的2个副本分别位于 Broker 0(L), 1(F)。

Kafka 会对所有分区都执行这个过程,最终确保每个分区的2个副本都位于不同的 Broker 上。

高级玩法:机架感知分配策略 (Rack Awareness)

如果您的服务器部署在不同的机架上,为了防止整个机架掉电导致数据丢失,Kafka 会把机架信息考虑进来,执行更智能的分配策略。

步骤1:创建机架交错的Broker列表

分配算法的第一步,不再是使用简单的数字顺序列表(如 0, 1, 2),而是会创建一个交错的 Broker 列表。

目的: 打乱 Broker 的物理顺序,创建一个新的分配顺序,使得列表中相邻的 Broker 尽可能来自不同的机架。

方法: 轮流从每个机架中取出一个 Broker,放入新列表,直到所有 Broker 都被放入。

举例: 假设我们有4个 Broker,分布在2个机架上:

机架 A: Broker 0, Broker 1

机架 B: Broker 2, Broker 3

Kafka 会这样生成交错列表:

  1. 从机架A取 0,从机架B取 2。列表变为 [0, 2]
  2. 再从机架A取 1,从机架B取 3。列表变为 [0, 2, 1, 3]

最终生成的机架感知分配顺序就是:0 -> 2 -> 1 -> 3。

步骤2:使用交错列表分配副本

接下来,Kafka 会使用这个新的交错列表 [0, 2, 1, 3] 来执行之前我们讨论过的"轮询"和"偏移轮询"算法。

举例: 创建一个有1个分区(P0)、复制系数为3的Topic。

  1. 分配P0的首领(Leader): 假设随机起点是列表的第一个元素,即 Broker 0 (位于机架A)
  2. 分配P0的第一个跟随者(Follower): 从 Broker 0 在交错列表中的位置开始,向后找一个位置。下一个是 Broker 2 (位于机架B)
  3. 分配P0的第二个跟随者(Follower): 再向后找一个位置。下一个是 Broker 1 (位于机架A)

步骤3:结果分析

最终分布: P0 的三个副本被分配到了 Broker 0 (机架A)、Broker 2 (机架B) 和 Broker 1 (机架A)。

容灾能力: 通过这个策略,Kafka 尽最大努力将副本分散到了不同的机架上。现在,即使整个机架A(包含Broker 0和1)完全掉线,分区 P0 的数据在机架B的 Broker 2 上还有一个副本幸存,服务依然可用,从而实现了机架级别的容灾。

总结

Kafka 的这套分区分配算法,看似复杂,但其背后的逻辑非常清晰:通过一个巧妙的、分两步走的轮询策略,简单高效地实现了负载均衡、数据安全和机架容灾这三大目标,是其能够成为稳定、可靠的分布式系统的核心基石之一。