重平衡是 Consumer Group 中的所有 Consumer 实例,就消费分区划分达成共识的过程。在重平衡的过程中,所有的消费者实例共同参与,在协调者组件的帮助下,完成订阅主题分区的分配。在重平衡过程中,所有的 consumer 实例都不能进行消费。
我们举个简单的例子来说明一下 Consumer Group 发生 Rebalance 的过程。假设目前某个 Consumer Group 下有两个 Consumer,比如 A 和 B,当第三个成员 C 加入时,Kafka 会触发 Rebalance,并根据默认的分配策略重新为 A、B 和 C 分配分区,如下图所示:
重平衡的缺点:
- 对 Consumer 端 TPS 影响很大。在重平衡过程中,所有的消费者实例均不能消费任何消息。
- 耗时时间长。
- 效率低。当前 Kafka 设计机制中,在重平衡的过程中,Group 中下的所有消费者实例都会参与进来,对所有分区进行重新分配,而不是针对发生变化的部分进行调整,未遵循局部性原理。
重平衡的触发条件:
- Topic 的分区数发生变化
- Consumer Group 中的实例数量发生变化
Topic 的分区数发生变化通常都是运维人员的主动操作,我们主要关注的是消费者组成员数量发生变化而引发的重平衡。
消费者组成员数量变化的情况:
- 消费者组成员数量增加。当我们启动一个 Consumer 程序时,就会向 group.id 配置对应的 Group添加一个新的消费者实例,并重新分区。通常来说,增加消费者实例的操作多是计划内的,可能是出于增加 TPS 或提高伸缩性的需求,它不属于“非必要的重平衡”。
- 消费者组成员数量减少。除计划内的停掉某些 Consumer 实例外,在某些情况下 Consumer 实例会被协调器错误的认为已经挂掉从而被踢出 Group,这种方式引发的重平衡操作需要重点关注并竟可能规避。
非必要重平衡的情况:
- 未能及时发送心跳,导致 Consumer 被踢出 Group 而引发重平衡。该情况的出现与 'session.timeout.ms' 和 'heartbeat.interval.ms' 配置有关。
- Consumer 消费时间过长引发重平衡。该情况的出现于 'max.poll.interval.ms' 配置有关。
- 频繁的 Full GC 导致 Consumer 长时间停顿,从而引发重平衡。
相关配置项
session.timeout.ms
设置消费者实例离线判定时间间隔。'session.timeout.ms' 默认值为 10 秒,即如果协调器(Coordinator)在10 秒内没有收到目标消费者实例的心跳,它就会认为该消费者实例已经挂掉。该配置不建议设置过大,以便于更快发现消费者实例的异常状态。
设置 session.timeout.ms = 6s
heartbeat.interval.ms
消费者实例心跳消息的发送间隔,要保证消费者实例在被判定为离线前,能够发送至少 3 轮心跳请求。但注意心跳请求不可太过频繁,避免过多消耗带宽资源。
设置 heartbeat.interval.ms = 2s
max.poll.interval.ms
消费者实例两次拉取消息(poll)操作的最大间隔,若超出该时间,则认为该消费者实例离线。结合 'max.poll.records' 与 消息处理逻辑的情况判断是否需要调大 'max.poll.interval.ms' 配置。
max.poll.records
消费者实例单次 poll 调用返回的最大消息数,默认值为500,如果处理逻辑很轻量,可以适当提高该值。注意一个批次('max.poll.records'条)的数据需要在 'session.timeout.ms' 时间内处理完成,否则会引起非必要的重平衡操作。