什么是 kafka 重平衡?
重平衡也叫 Rebalance,本质上是一种协议,规定了一个消费组下的所有消费者如何达成一致,来分配订阅 Topic 的每个分区,比如某个消费组下有10个消费者实例,它订阅了一个具有50个分区的 Topic,正常情况下,Kafka 平均会为每个消费者分配5个分区,这个分配的过程就叫 Rebalance。
为什么 kafka 会发生重平衡?
消费组发生 Rebalance 有三种情况:
- 消费者成员数发生变更
有消费者实例加入消费组或者离开消费组,或者有消费者实例崩溃被"踢出"消费组,从而发生 Rebalance。
- 订阅主题数量发生变更
消费组一开始只是订阅 Topic A 和 Topic B,某次上线消费组订阅 Topic C,消费组发生 Rebalance。
- 订阅主题的分区数发生变更
当 Topic 分区数增加时,就会触发订阅该主题的所有消费组发生 Rebalance。
kafka 重平衡有什么影响?
Rebalance 过程中,消费者组的消费者都会停止消费(Stop-The-World),直到 Rebalance 完成,这会导致,
- 消费暂停
整个消费者组在重平衡期间无法处理消息,很容易影响业务正常运行。
- 重复消费
消费者在重平衡前未完成提交的偏移量导致消息被重复处理,一旦业务没有做好幂等处理,容易产生脏数据。
如何避免 kafka 发生重平衡?
-
要避免 Rebalance,还是要从 Rebalance 产生的原因入手,消费者组成员数量发生变化、订阅主题数量发生变化、订阅主题的分区数发生变化都会使得消费组发生 Rebalance。
-
其中订阅主题数量发生变化、订阅主题的分区数发生变化不可避免。消费者组成员数量增加主要是配置了相同的group.id 程序会添加到这个消费者组中,发生 Rebalance,这个不是我们需要考虑的。
-
消费者组成员减少才是我们需要重点研究的,那什么情况会出现消费者成员减少?
消费者心跳超时导致
消费者因为未能及时发送心跳,导致消费者被"踢出"消费组而引发 Rebalance。
消费者心跳与 session.timeout.ms、heartbeat.interval.ms 两个参数有关。
-
session.timeout.ms:消费者与 broker 会话超时时间。
-
heartbeat.interval.ms:消费者发送心跳到协调器的时间间隔。
一般来说 session.timeout.ms >= 3 * heartbeat.interval.ms。这么设置源自 Kafka 官方推荐和实际运维经验。
消费者消费时间过长导致
如果在最大间隔时间内未将消息处理完毕,触发消费组 Rebalance。消费者消息处理速度与 max.poll.interval.ms、max.poll.records 两个参数有关。
-
max.poll.interval.ms:消费者两次 poll 最大间隔时间。
-
max.poll.records:消费者单次 poll 最大消息数。
两个参数简单设置:max.poll.interval.ms >= 单个消息处理时间 * max.poll.records。
笔者就遇到过一个业务场景,消费者消费消息需要将消息处理之后写入到 MySQL,某天 MySQL 发生慢查导致消费者程序消费时长突增,消费组发生 Rebalance。总之,一定要给业务处理逻辑留下充足的时间来避免 Rebalance。
经验之谈,一旦发生 Rebalance 不要着急,分析整个消费者链路,逐个依赖排查,遇到问题,解决问题。