1.消费者组重平衡的作用
- 防止数据倾斜:如果某个消费者实例处理数据的速度较慢,可能会导致数据倾斜,影响整个消费者组的性能。通过重平衡,可以将分区重新分配给其他处理速度更快的消费者实例,从而避免数据倾斜。
- 提高稳定性:通过重新分配分区,重平衡可以帮助消费者组在面对消费者离组、崩溃等异常情况时,保持系统的稳定性和可靠性。
- 让组内所有的消费者实例就消费哪些主题分区达成一致。
2.触发条件
- 组成员数量发生变化
- 订阅主题数量发生变化
- 订阅主题的分区数发生变化
在实际生产环境中,因条件1而引发的重平衡是最常见的(消费者组中的消费者实例依次启动也属于第1种情况,每次消费者组启动,必定触发重平衡)。
3.通知方式
Kafka消费者需要定期发送心跳请求(Heartbeat Request)到Broker端的协调者。从0.10.1.0版本开始,Kafka引入了专门发送心跳请求的线程(Heartbeat Thread)。**重平衡的通知机制正是通过心跳线程来完成的。**当协调者决定开启新一轮重平衡时,会将“REBALANCE_IN_PROCESS”封装进心跳请求的响应中,发还给消费者实例。
因此heartbeat.interval.ms参数除了设置心跳的时间间隔,也同时决定了重平衡通知的频率。如果想要消费者快速得到通知,那么可以将这个参数设置为非常小的值,这样消费者就可以更快的收到重平衡的响应消息。
4.消费者端重平衡的流程
在消费者端,重平衡分为两个步骤:分别是加入组和等待领导者消费者(Leader Consumer)分配方案。这两个步骤分别对应两类特定的请求:JoinGroup 请求和 SyncGroup 请求。
4.1 Consumer Group 如何确定为它服务的 Coordinator 在哪台 Broker 上?
Coordinator 的选择是根据 Group ID 的 hashcode 值对 50 取模,为什么对 50 取模,因为选择 Coordinator 的依据就是 Kafka 的内置 Topic(_consumer_offsets),该主题默认 50 个分区。
这样下来,不同的 Group ID 会被哈希到不同的分区上,从而不同的 Broker 充当不同 Group 的 Coordinator。也就是说一个 Consumer Group 对应一个 Coordinattor。例如:Group ID 的 hashcode 值为 1,1%50=1,那么 _consumer_offsets 主题的 1 号分区在哪个 Broker 上,就选择这个节点的 Coordinator 作为这个消费者组的协调器。消费者组下的所有的消费者提交 offset 的时候就往这个分区去提交 offset。
4.2 JoinGroup请求
当消费者组内有成员加入组时,它会向协调者发送 JoinGroup 请求。每个成员都要将自己订阅的主题上报,这样协调者就能收集到所有成员的订阅信息。收集了全部成员的 JoinGroup 请求后,协调者会从这些成员中选择一个担任这个消费者组的领导者。
通常情况下,第一个发送 JoinGroup 请求的成员自动成为领导者。
领导者消费者:通过协调者发出JoinGroup响应,收到所有成员的订阅信息,然后根据这些信息,制定具体的分区消费分配方案。
选出领导者之后,协调者会把消费者组的每个成员订阅信息封装进 JoinGroup 请求的响应体中,然后发给领导者,由领导者统一做出分配方案后,进入到下一步:发送 SyncGroup 请求。
注意:每个消费者组对应一个协调者。
如图:
4.3 SyncGroup请求
在这一步中,领导者向协调者发送 SyncGroup 请求,将分配方案发给协调者。值得注意的是,其他成员也会向协调者发送 SyncGroup 请求,只不过请求体中并没有实际的内容。这一步的主要目的是让协调者接收分配方案,然后统一以 SyncGroup 响应的方式分发给所有成员,这样组内所有成员就都知道自己该消费哪些分区了。
SyncGroup 请求的主要目的,就是让协调者把领导者制定的分配方案下发给各个组内成员。当所有成员都成功接收到分配方案后,消费者组进入到 Stable 状态,即开始正常的消费工作。
如图: