kafka- 再均衡原理

导语
从 Apache Kafka 2.3.0 开始, Kafka Connect 和 consumers 使用的内部再均衡协议有几个重大的调整。在下面的文章里,我们会先从这个协议的基础开始,它是 Apache Kafka 消费机制的核心。然后讨论它的局限性和当前的改进。
首先,让我们回顾下 Kafka 的基础知识 &再均衡协议。

Kafka & 再均衡协议
1.1 Kafka
Apache Kafka 是一个基于分布式发布/订阅模式的流式平台。首先,称为生产者的进程将消息发送到主题,主题由 broker 集群管理和存储。然后,消费者进程订阅这些主题获取和处理发布的消息。一个主题是分布在多个 broker 中,因此每个 broker 管理每个主题的消息子集-这些消息子集称为分区。分区的数量在创建主题的时候定义的,并且可以随着时间的推移而增加(但要小心该操作)。重要的是要理解 『分区实际上是 Kafka 的生产者和消费者的并行单元』。
对于生产者,分区允许并行的写消息。如果一个消息发布使用一个 key 值, 然后 默认的生产者将要对 key 做 hash,确定目的分区。这个确保了有相同 key 的消息将要被发送到相同的分区。另外,一个消费者将要保证按照分布在分区的顺序消费。
对于消费者, 主题的分区数限制了消费者组内的最大活跃消费者数。消费者组是 Kafka 提供的一种机制,用于将多个消费者客户端分组到一个逻辑组中,以对分区的消费者进行负载均衡。Kafka 保证主题分区仅分配给组内的一个消费者。例如, 下图描绘了一个名为 A 的消费者组,其中包含三个消费者。消费者订阅了主题 A, 分区分配为:P0 到 C1, P1 到 C2, P2 到 C3,P3 到 C1。

Apache Kafka — 消费组
如果一个消费者在受控关闭或崩溃后离开组,则其所有分区将在其它消费者之间自动重新分配。同样, 如果消费者(重新)加入现有组,则所有分区也将在组成员之间再均衡。通过使用所谓的 Kafka 再均衡协议,消费者客户端能够在组内动态进行合作。下面我们将深入介绍这个协议,并理解它的工作原理。
1.2 再均衡协议
首先, 我们看下 Apache Kafka 官方文档对术语 再均衡(Rebalance/Rebalancing)的定义。
Rebalance/Rebalancing: 一系列分布式进程所遵循的过程, 这些进程使用 Kafka 客户端或 Kafka 协调器来形成一个公共组并在该组的成员之间分配一组资源 (source : Incremental Cooperative Rebalancing: Support and Policies). 上面的定义实际上没有提到消费者或分区的概念。相反,它使用成员和资源的概念。主要原因是因为再均衡协议不仅限于管理消费者, 还可以用来协调任何一组进程。
以下便是再均衡协议的一些用法:
Confluent Schema Registry 依赖再均衡来选举领导节点;
Kafka Connect 使用它在 Worker 之间分配任务和连接器;
Kafka Streams 使用它将任务和分区分配给应用程序流实例。

Apache Kafka Rebalance Protocol and components
如上图所示,再均衡机制主要围绕 2 个协议构建的:组成员协议(Group Membership Protocol) 和 消费者嵌入式协议(Consumer Embedded Protocol)
组成员协议(Group Membership Protocol),顾名思义,这个协议负责一个组内成员的协调。参与组的客户端将使用充当协调器的 Kafka broker 执行一系列请求/ 响应。
消费者嵌入协议(Consumer Embedded Protocol)在客户端执行,并允许通过嵌入第一个协议(组成员协议)来扩展第一个协议。例如,消费者使用协议会将主题分区分配给成员。
上面术语的介绍比较抽象,下面我们将通过 Group 和 Client 之间的交互,来描述再均衡的基本原理。涉及到 JoinGroup, SyncGroup, Hearbeat, LeaveGroup 几个场景。
加入组(JoinGroup)
当消费者启动时,它会发送第一个 FindCoordinator 请求以获取负责其组的 Kafka broker 协调器。然后,它通过发送 JoinGroup 请求来启动重新均衡协议。

Consumer — Rebalance Protocol — SyncGroup Request
如上图所示,JoinGroup 请求包含一些消费者客户端配置, 例如 session.timeout.ms 和 max.poll.interval.ms。如果成员没有响应,协调器会使用这些属性将成员踢出组。另外,这个请求同时包含 2 个重要的字段:成员支持的客户端协议列表,以及将用于执行嵌入式客户端协议之一的元数据。在我们的例子中, 客户端协议是为消费者配置的分区分配器列表(既:partition.assignment.strategy) 。元数据包含消费者订阅的主题列表。如果您想了解上述属性的用途, 可参见官方文档 official documentation (https://kafka.apache.org/documentation/#consumerconfigs)。JoinGroup 做为加入组的屏障,意味着只要未收到所有消费者请求(即 group.initial.rebalance.delay.ms ) 或再均衡超时,协调器就不会发送响应。

Consumer — Rebalance Protocol — JoinGroup Response
组内的第一个消费者收到活跃成员列表和选定的分配策略并充当组长, 而其他消费者则收到空响应。组长负责在本地执行分区分配。
同步组(SyncGroup)
接下来,所有成员都会向协调器发送一个 SyncGroup 请求。组长附上计算好的分配任务, 而其它消费者则简单地以空请求响应。

Consumer — Rebalance Protocol — SyncGroup Request
一旦协调器响应了所有 SyncGroup 请求, 每个消费者都会收到他们分配的分区,在配置的侦听器上调用 onPartitionsAssigned 方法, 然后开始获取信息。

Consumer — Rebalance Protocol — SyncGroup Response
心跳(Heartbeat)
最后需要注意的一点是,每个消费者都会定期向 broker 协调器发送一个心跳请求,以保持其会话处于活动状态(参见 : heartbeat.interval.ms).。如果再均衡正在进行中,则协调器使用 Heatbeat 响应向消费者指示他们需要重新加入组。

Consumer — Rebalance Protocol — Heartbeat
到目前为止一切都很顺利,但是在真实的分布式系统中,会发生各种意想不到的故障。例如:硬件损坏, 网络抖动或消费者出现暂时性故障。 对于所有这些情况,都会触发再均衡。

当前再均衡协议问题 &改进
2.1 再均衡协议的一些问题 &静态成员的引入
2.1.1 再均衡一个成员触发 Stop The World 的问题
再均衡协议的第一个问题是『我们不能简单地再均衡一个成员而不停止整个组(stop-the-world effect)』例如,在如下这个再均衡场景中。我们停止一个实例, 消费者将在停止之前向协调器发送一个离组请求。

Consumer — Rebalance Protocol — LeaveGroup
剩余的消费者将被通知必须在下一次心跳时执行再均衡, 并将启动新的 JoinGroup/SyncGroup 请求,往返以重新分配分区。

Consumer — Rebalance Protocol — Rejoin
在整个再均衡过程中,即只要没有重新分配分区,消费者就不再处理任何数据。默认情况下,再均衡超时设定为 5 分钟,这是一个很长的时间段, 在此期间增加的消费者延迟可能会带来另外一个问题。但是,如果消费者在短暂失败后恰好又重启启动,会发生什么?答案是『消费者在重新加入组时,将触发新的再均衡, 导致所有消费者再次停止』。

Consumer — Rebalance Protocol — Restart
2.1.2 组的滚动升级问题
另外一个可能导致消费者重启的原因是组的滚动升级。不幸的是,这种情况对消费群体来说是灾难性的。实际上,对于一组三个消费者, 这样的操作将触发 6 次再均衡, 这可能会对消息处理产生重大影响。
2.1.3 JAVA GC 导致的心跳丢失问题
在 Java 中运行 Kafka 消费者时还会碰到一个常见问题,由于网络中断或长时间 GC 暂停而丢失心跳请求, 或者由于处理时间 过长而没有定期调用方法 KafkaConsumer.poll()。在第一种情况下,协调器在超过 session.timeout.ms 毫秒内没有收到心跳, 会认为消费者已经死亡。在第二种情况下,处理轮询记录所需的时间要小于 max.poll.inteval.ms

Consumer — Rebalance Protocol — Timeout
2.1.4 引入静态成员
为了减少由于瞬时故障导致的消费者再均衡,Apache Kafka 2.3 引入了静态成员的概念和 KIP-345, 静态成员身份背后主要思想是,『每个消费者实例都附加一个 group.instance.id 属性,用来配置唯一标识符』。成员协议相应扩展,以便通过 JoinGroup 请求 id 传播到 broker 协调器。

如果消费者因暂时性故障而重新启动或宕机,broker 协调器不会通知其他消费者需要再均衡, 直到达到 session.timeout.ms 超时. 这样消费者在停止时不会发送 LeaveGroup 请求。

当消费者最终重新加入组时, broker 协调器会将缓存中的分配重新返回给它, 而不用进行再均衡。

使用静态成员时, 建议设置消费者属性 session.timeout.ms 更大些, 这样 broker 协调器就不会频繁地触发再均衡。一方面, 这个设置会减少不必要的再均衡, 从而最大限度地减少停止世界的影响。但是另一方面,这样做的缺点是增加了分区的不可用性,因为 broker 代理可能只能在几分钟后才检测到失败的消费者(取决于 session.timeout.ms 配置). 但是您不得不在分布式系统中对可用性和容错性两者做权衡。
2.2 Kafka 连接限制 &增量合作再均衡
2.2.1 Kafka 连接限制问题
Kafka Connect 使用组成员协议在组成连接集群的工作人员之间平均分配连接器和任务。因此,当节点失败/重新启动、任务扩展/缩减 以及提交/更新配置时,工作人员相互协调以再均衡连接器和任务。然后,在 Kafka2.3 之前,每当发生其中一种情况时, 所有现有连接器的执行都会中断(既 『Stop The World』)。因此,导致很难扩展具有数十个连机器的互惠集群。
2.2.2 增量合作再均衡
从 2.3 版本开始,Apache Kafka 引入了新的嵌入式协议,以提高每个成员的资源可用性,同时最大限度地减少『Stope The World』效应的影响。这些新协议背后的基本思想是逐步和合作地执行再均衡 --- 换句话说就是『执行多个局部再均衡轮次替换全局轮次』。
增量协作再均衡首先通过 KIP-415 为 Kafka Connect 实现(部分在 Kafka 2.3 中实现)。此外,它将可用于从 Kafka 2.4 到 KIP-429 的流和消费者。
增量合作再均衡试图通过两种方式解决这个问题:
1 ) 仅停止已撤销资源的任务/成员
2 ) 立即或延迟处理成员之间资源分配的暂时不均衡(对于滚动重启很有用)。
为此, 增量合作再均衡主体实际上被分为三种具体设计
Design I: 简单的合作再均衡
Design II: 不均衡的延迟解决
Design III: 不均衡的增量解决
为了更好地理解增量合作再均衡的工作原理,将基于如下 Kafka Connect 的上下文说明。
不均衡的延迟解决
首先,让我们从一个简单的连接集群开始,该集群由三个工作人员组成,具有这个初始任务/连接器分配:

1 — Initial assignment
现在,我们假设 W2 在没有任何特殊原因的情况心下失败并因会话超时而离开组。触发再均衡, 剩余的工人 W1 和 W3 重新加入该组。在发送 JoinGroup 请求时,工作人员包括他们之前的任务。使用 Group Membership 协议的现有字段 member_metadata 共享分配。

2 — W2 leaves the group and rebalance is triggered (W1, W3 join)
W1 被选为组长,并通过计算与先前分配的差异来执行任务/连接器分配。在这里,领导者检测到某些任务和连接器在以前的分配中没有出现。

3 — W1 becomes leader and computes assignments
W1 发送新分配的任务/连机器以及撤销。您可以注意到 W1 实际上不会立即尝试解决丢失的分配(或不均衡)。取而代之的是,它将通过安排下一次再均衡来推迟解决方案,以使失败的成员有机会重新出现。调度延迟由新配置 scheduled.rebalance.max.delay.ms 配置(默认为 5 分钟)。
注意:使用增量协作再均衡, 当成员收到新分配时, 它将开始处理任何新分区(或任务/连机器)。此外,如果分配还包含已撤销的分区, 则它会立即停止处理、提交并启动另一个加入组。这会增加再均衡的次数, 但只会停止分配已更改的资源。

4 — W1, W3 receive assignments
W2 在延迟到期之前重新新加入组并触发另一个再均衡。W1 和 W2 也重新加入该组。

5 — B rejoins the group before delay expire and a rebalance is triggered
但是,在计划的再均衡延迟到期之前,W1 不会重新分配丢失的任务/连接器

6 — W1 becomes leader and computes assignments
剩余延迟到期后,将触发最终再均衡,所有工作人员重新加入组。

7 — W1, W2, W3 receive assignments
最后,组长将 A-Task-1 和 Connector-B 重新分配给 W2。在所有再均衡的过程中,W1 和 W3 从未停止过分配的任务。

8 — After delay, all members join

总结
再均衡协议是 Apache Kafka 消费机制的重要组成部分。同时它也用作协调组成员和在他们之间分配资源的通用协议(例如 Kafka Connect)。静态成员和增量协作重新均衡都是重要的功能,通过使该协议更加健壮和可扩展,为 Apache Kafka 提供了巨大的改进。要了解有关重新均衡协议及其工作原理的更多信息,可参考下列链接。

参考
3. https://kafka.apache.org/protocol
4. The Magical Rebalance Protocol of Apache Kafka by Gwen Shapira

关于领创集团
(Advance Intelligence Group)
领创集团成立于 2016 年,致力于通过科技创新的本地化应用,改造和重塑金融和零售行业,以多元化的业务布局打造一个服务于消费者、企业和商户的生态圈。集团旗下包含企业业务和消费者业务两大板块,企业业务包含 ADVANCE.AI 和 Ginee,分别为银行、金融、金融科技、零售和电商行业客户提供基于 AI 技术的数字身份验证、风险管理产品和全渠道电商服务解决方案;消费者业务 Atome Financial 包括亚洲领先的先享后付平台 Atome 和数字金融服务。2021 年 9 月,领创集团宣布完成超 4 亿美元 D 轮融资,融资完成后领创集团估值已超 20 亿美元,成为新加坡最大的独立科技创业公司之一。
版权声明: 本文为 InfoQ 作者【领创集团Advance Intelligence Group】的原创文章。
原文链接:【http://xie.infoq.cn/article/aa04d814b7ae6c18ce0742436】。文章转载请联系作者。
评论