kafka rebalance(再均衡)导致的消息积压分析
起因:
某天,项目组收到大量的kafka消息积压告警。查看了kafka日志后,发现 kafka不断地 rebalance(再均衡)。
Rebalance (再均衡):
分区的所有权从一个消费者转移到另一个消费者,这样的行为被称为Rebalance (再均衡).
在再均衡期间,消费者无法消费消息,造成整个群组一小段时间的不可用。
Rebalance 的触发条件:
-
当 Consumer Group 组成员数量发生变化
(1)新成员加入
(2)组成员主动离开(3)组成员崩溃
- 消费者心跳超时,导致 rebalance。
- 消费者处理时间过长,导致 rebalance。
-
当订阅主题数量发生变化
-
当订阅主题的分区数发生变化
日志:
[2023-12-11 xx:xx:xx] INFO [GroupCoordinator 1]: Member consumer-anonymous. in group anonymous. has failed, removing it from the group (kafka.coordinator.group.GroupCoordinator)
[2023-12-11 xx:xx:xx] INFO [GroupCoordinator 1]: Preparing to rebalance group anonymous. in state PreparingRebalance with old generation 1 (__consumer_offsets-5) (reason: removing member consumer-anonymous. on heartbeat expiration) (kafka.coordinator.group.GroupCoordinator)
[2023-12-11 xx:xx:xx] INFO [GroupCoordinator 1]: Group anonymous. with generation 2 is now empty (__consumer_offsets-5) (kafka.coordinator.group.GroupCoordinator)
[2023-12-11 xx:xx:xx] WARN Attempting to send response via channel for which there is no open connection, connection id :9092 (kafka.network.Processor)
原因:
kafka消费消息后,如果业务逻辑处理时间过长,会导致消费线程与 Coordinator(协调器) 的 heartbeat (心跳) 超时,Coordinator 判断 Consumer 已经宕机,就将 Consumer 从消费组中剔除,并触发了 Rebalance 机制 。
解决:
优先解决生产问题:先调整消费者的参数,避免频繁 Rebalance。
如果想从根本上解决,还需要优化消费逻辑,提高性能,快速消费完,避免超时。
在创建消费者 KafkaConsumer 时,需要指定各个参数。这些参数在Kafka 的 ConsumerConfig 类上都有常量定义。
Properties properties = new Properties();
properties.put("group.id", groupId);
properties.put("session.timeout.ms", time);
properties.put("heartbeat.interval.ms", interval);
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(properties);
可以优化的参数如下:
session.timeout.ms : 心跳超时时间
heartbeat.interval.ms : 心跳时间间隔
max.poll.interval.ms : 每次消费的处理时间
max.poll.records : 每次消费的消息数
-
session.timeout.ms: 心跳超时时间,默认 10s。当心跳超时时间超过 session.timeout.ms ,会认为 Consumer 已退出 ,将 Consumer 从消费组中剔除,触发 Rebalance 机制。可以适当调大 session.timeout.ms,避免频繁 Rebalance 。
-
heartbeat.interval.ms : 这个是心跳时间间隔,默认值是:3s。 该值必须小于 session.timeout.ms,否则会超时。
-
max.poll.interval.ms :如果消费端在该间隔内没有发起 poll 操作,该消费者将被剔除,触发重平衡,将该消费者分配的队列分配给其他消费者。默认为 5 分钟。
-
max.poll.records: 每次消费的时候,获取多少条消息。默认值为 500。
获取的消息条数越多,需要处理的时间越长。所以每次拉取的消息数不能太多,需要保证在 max.poll.interval.ms 设置的时间内能消费完,否则会发生 rebalance。可以适当调小 max.poll.records,避免频繁 Rebalance 。