Kafka【再平衡】

👉 Kafka 再平衡 💎

csdn

1  何为 Kafka 再平衡


再平衡就是一个协议,它规定了如何让消费组下的所有消费者来分配 Topic 中的每一个分区。例如:一个 Topic 有 100 个分区,一个消费者组内有有 20 个消费者,在协调者的控制下让消费者组内的每一个消费者分配到 5 个分区,这个分区分配的过程就是再平衡。

触发再平衡的条件:

  • 消费者组内成员发生变更,这个变更包含消费者的增加与减少。这里的减少有很大可能是被动的,就是某个消费者出现崩溃掉线了
  • 主题分区发生改变,kafka 目前只支持分区增加,当出现分区数增加的时候就会触发再平衡
  • 订阅的主题发生变化,当消费者使用正则表达式订阅主题时,而恰好增加的主题就是订阅的主题,就会触发再平衡机制

为什么说 kafka 再平衡为人诟病呢?因为再平衡的过程中,消费者无法从 kafka 消费消息,这对 kafka 的 TPS 影响极大,而如果 Kafka 集群内节点较多,那么再平衡可能耗时极多。数分钟到数小时都有可能,而这段时间,Kafka 是处于不可用状态。所以在实际环境中,应该尽量避免。

2   再平衡过程如何通知到其他消费者


答案就是:依靠消费者端的心跳线程(Heartbeat Thread)

Kafka 消费者需要定期地发送心跳请求(Heartbeat Request) 到 Broker 端的协调者,以证明消费者还活着。在 Kafka 0.10.0.1版本之前,发送心跳请求是在消费者主线程中完成的。这样就有很多问题,最大的问题在于,消息处理逻辑也是在这个线程中完后的。因此,一旦消息处理消耗很长的时间,心跳请求将无法及时发送到协调者那里,使协调者误以为该消费者死掉。自 0.10.0.1 版本之后,Kafka 就提供了一个专门的线程去发送心跳,避免了这个问题。

再平衡就是通过这个心跳线程去通知其他消费者触发再平衡机制。当协调者开启新一轮的再平衡之后,它会将 "REBALANCE_IN_PROGREESS"封装到心跳线程的响应信息中,返回给消费者实例,当消费者收到响应信息中含有 “REBALANCE_IN_PROGREESS” 信息,就立马知道再平衡开始了,这就是再平衡的通知机制。

3   消费者组状态机


再平衡一旦开启,Broker 端的协调者组件就要开始忙了,主要涉及到控制消费者组的状态流转。当前 Kafka 设计了一套消费者组状态机(State Machine),来帮助协调者完成整个再平衡过程。严格来说,这套状态机属于非常底层的设计,Kafka 官网并没有提及过。目前,Kafka 为消费者组定义了 5 中状态,他们分别是:Empty、Dead、PreparingRebalance、CompletingReblance、Stable。那么这 5 中状态的含义是什么?看下面一张表。
消费者组 5 种状态
状态 含义
Empty组内没有任何成员,但消费者可能存在已提交的位移数据,而且这些位移尚未过期
Dead同样是在组内没有成员,但组内元数据信息已经在协调者端被移除。协调者组件保存着当前向它注册过的所有组信息,所谓的元数据信息类似于这个注册信息
PreparingRebalance消费者组开启再平衡,此时所有成员都要重新加入消费者组
CompletingRebalance消费者组小所有成员已经加入,各个成员已在等待分配方案。该状态在老一点版本中称为AwaitingSync,它和CompletingReblance是等价的。
Stable消费者组的稳定状态。该状态表名再平衡已经完成,组内各成员能够正常消费数据了。

看下图,展示了状态机各个状态流转

在这里插入图片描述

一个消费者组最开始是 Empty 状态,当再平衡开启后,它会被至于 PreparingRebalance 状态等待成员加入,之后变更为 CompletingReblance 状态等待分配方案,最后流转为 Stable,完成再平衡过程。

4   消费者端再平衡流程


再平衡的完整流程需要消费者端与协调者组件共同参与才能完成。先从消费者角度审视一下再平衡流程。

在消费者端,再平衡分为两个步骤:分别是加入组合等待领导消费者(Leader Consumer) 分配方案。这两个步骤分别对应两类特定的请求:JoinGroup 请求和 SyncGroup 请求。

当组内成员加入组时,消费者会向协调者发送 JoinGroup 请求,在该请求中,每个成员都要将自己订阅的主题上报,这样协调者就能收集到所有成员的订阅信息。一旦收集了全部成员的 JoinGroup 请求后,协调者会从这些成员中选择一个担任这个消费者组的领导者。

通常情况下,第一个发送 JoinGroup 请求的成员自动成为领导者。领导者消费者的任务是收集所有成员的订阅信息,然后根据这些信息,指定具体的分区消费分配方案。

选出领导者之后,协调者会把消费者的订阅信息封装在 JoinGroup 请求的响应中,然后发送给领导者,由领导者统一做出分区消费分配方案后,在进行下一步,发送 SyncGroup 请求。

在这一步中,领导者向协调者发送 SyncGroup 请求,将刚刚做出的分配方案发给协调者。值得注意的是,其他成员也会向协调者发送 SyncGroup 请求,只不过请求体中并没有实际的内容。这一步主要目的是让协调者接收分配方案,然后统一以 SyncGroup 响应的方式发给所有成员,这样组内的成员都知道自己该消费哪些分区的数据了

接下来,用一张图说明一下 JoinGroup 请求的处理过程


在这里插入图片描述


就像前面说的,JoinGroup 请求的主要作用是将组成员的订阅信息发送给领导者消费者,待领导者制定好分配方案后,再平衡流程进入到 SyncGroup 请求阶段

接下来,用一张图说明一下 SyncGroup 请求的处理过程


在这里插入图片描述


SyncGroup 请求的主要目的就是让协调者把领导者的分配方案下发给各个组内成员。当所有成员都成功接收到分配方案后,消费者组进入 Stable 状态,即开始正常的消费工作。

5   Broker端再平衡场景剖析


要剖析协调者端处理再平衡的全流程,我们就需要分几个场景来讨论。这几个场景分别是新成员加入组、组成员主动离组、组成员崩溃离组、组成员提交位移。接下来,我们一个一个来讨论。

5.1   场景一:新成员入组


当新成员入组是指组处于 Stable 状态后,有新成员加入。如果对全新启动一个消费者组,Kafka 是有一些自己的小优化的,流程会有些许的不同。我们这里要论的是,组稳定之后有新成员加入的情形。

当协调者收到新的 JoinkGroup 请求后,它会通过心跳响应的方式通知组内现有的所有成员,强制它们开启新一轮的再平衡。具体的过程和之前的客户端再平衡流程是一样的。现在,用一张时序图说明协调者一端是如何处理新成员入组的。

在这里插入图片描述

5.2   场景二:组成员主动离组


何为主动离组?就是指消费者实例所在线程或进程调用 close() 方法主动通知协调者它要退出。这个场景就涉及到第三类请求:LeaveGroup 请求。协调者收到 LeaveGroup 请求后,依然会以心跳响应的方式通知其他成员,直接用一张图说明。

在这里插入图片描述

5.3   场景三:组成员崩溃离组


崩溃离组是指消费者实例出现严重故障,突然宕机导致的离组。它 和主动离组是有区别的,因为后者是主动发起的离组,协调者能马上感知病例吗处理。但是崩溃离组是被动的,协调者通常需要等待一段时间才能感知到,这段时间一般是由消费者端参数 session.timeout.ms 控制的。也就是说,Kafka 一般不会超过 session.timeout.ms 就能感知到这个崩溃。当然,后面处理崩溃离组的流程与之前是一样的,来看下面一张图

在这里插入图片描述

5.4   场景四:再平衡是协调者对组内成员移交位移处理


正常情况下,每个组成员都会定期汇报位移给协调者。当再平衡开启时,协调者会给予成员一端缓冲时间,要求每个成员必须在这段时间内快速上报自己的位移信息,然后再开启正常的 JoinGroup/SyncGroup
请求发送。还是看一张图

在这里插入图片描述

6   再平衡所涉及的参数


在消费者启动时,某些参数会影响再平衡机制的发生,不当会导致频繁再平衡,严重影响消费速度,下面说说几个参数的一些要点

session.timeout.ms

该参数是 Coordinator 检测消费者失败的时间,即在这段时间内客户端是否跟 Coordinator 保持心跳,如果该参数设置较小,可以更早发现消费者崩溃的信息,从而更快的开启再平衡,避免消费滞后,但是这也会频繁的再平衡,需要根据实际业务来衡量。

max.poll.interval.ms

消费者处理消息逻辑的最大时间,对于某些业务来说,处理消息可能需要很长时间,比如需要 1 分钟,那么该参数就需要设置成大于 1 分钟的值,否则就会被 Coordinator 剔除消息组然后再平衡。

heartbeat.interval.ms

该参数跟 session.timeout.ms 紧密相关,前面也说过,只要在 session.timeout.ms 时间内与 Coordinator 保持心跳,就不会被 Coordinator 剔除,那么心跳间隔时间就是 session.timeout.ms ,因此,该参数值必须小于 session.timeout.ms ,以保持 session.timeout.ms 时间内有心跳。

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个Kafka分区平衡脚本的示例,它使用Kafka自带的工具来完成分区平衡: ```bash #!/bin/bash # Kafka broker列表 BROKERS=broker1:9092,broker2:9092,broker3:9092 # 要平衡的主题 TOPIC=my_topic # 分区数 PARTITIONS=10 # 每个broker的最大分区数 MAX_PARTITIONS_PER_BROKER=3 # 获取每个broker当前的分区数量 PARTITIONS_PER_BROKER=$(kafka-topics --zookeeper zk_host:2181 --describe --topic $TOPIC | grep -e 'Partition:' | awk '{print $2}' | tr ',' '\n' | awk -F ':' '{print $2}' | sort | uniq -c | awk '{print $1}') # 计算每个broker应该有的分区数 TARGET_PARTITIONS_PER_BROKER=$((($PARTITIONS+$MAX_PARTITIONS_PER_BROKER-1)/$MAX_PARTITIONS_PER_BROKER)) # 计算需要移动的分区数 PARTITIONS_TO_MOVE=$(($TARGET_PARTITIONS_PER_BROKER*$MAX_PARTITIONS_PER_BROKER-$PARTITIONS)) # 如果需要移动的分区数大于0,则进行分区平衡 if [ $PARTITIONS_TO_MOVE -gt 0 ]; then # 获取当前分区最少的broker SOURCE_BROKER=$(kafka-topics --zookeeper zk_host:2181 --describe --topic $TOPIC | grep -e 'Partition:' | awk '{print $2}' | tr ',' '\n' | awk -F ':' '{print $1,$2}' | sort -k 2 | awk '{print $1}' | head -n 1) # 获取当前分区最多的broker DEST_BROKER=$(kafka-topics --zookeeper zk_host:2181 --describe --topic $TOPIC | grep -e 'Partition:' | awk '{print $2}' | tr ',' '\n' | awk -F ':' '{print $1,$2}' | sort -k 2 | awk '{print $1}' | tail -n 1) # 计算需要移动的分区数 PARTITIONS_TO_MOVE=$(($PARTITIONS_TO_MOVE<$PARTITIONS_PER_BROKER[$SOURCE_BROKER]? $PARTITIONS_TO_MOVE:$PARTITIONS_PER_BROKER[$SOURCE_BROKER])) # 移动分区 kafka-reassign-partitions --zookeeper zk_host:2181 --reassignment-json-file <(echo "{\"version\":1,\"partitions\":[{\"topic\":\"$TOPIC\",\"partition\":$PARTITION_TO_MOVE,\"replicas\":[$DEST_BROKER]}]}") --execute fi ``` 请注意,这只是一个示例脚本,您需要根据您的特定情况进行修改。例如,您可能需要更改BROKERS,TOPIC,PARTITIONS和MAX_PARTITIONS_PER_BROKER变量的值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值