spring-kafka消费出现异常:Commit cannot be completed since the group has already rebalanced 消费者突然hung住停止消费

博客主要讲述线上Kafka出现的两个异常。一是CommitFailedException,因一次性poll拉取消息处理时间长,超max.poll.interval.ms阈值,通过改拉取消息数量和session.timeout.ms解决;二是消息堆积不消费,消费者挂起,最终加大max.poll.interval.ms解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一天发现线上环境大量报kafka异常:CommitFailedException

org.apache.kafka.clients.consumer.CommitFailedException:
 Commit cannot be completed since the group has already rebalanced and assigned the partitions to another member.
 This means that the time between subsequent calls to poll() was longer than the configured max.poll.interval.ms,
 which typically implies that the poll loop is spending too much time message processing.
 You can address this either by increasing the session timeout or by reducing the maximum size of batches returned in poll() with max.poll.records.

后面分析得知出现该异常是因为一次性poll拉取(默认500)消息后处理时间过长,导致两次拉取时间间隔超过了max.poll.interval.ms阈值(默认五分钟)。解决策略可以加大参数:max.poll.interval.ms或者减少一次性拉取的消息数量。 我这里是改了拉取消息数量和session.timeout.ms得以解决。
spring配置如下:

spring:
  kafka:
   consumer:
     max-poll-records: 200

我也改了spring.kafka.properties.session.timeout.ms

spring:
  kafka:
   properties:
    session:
      timeout:
        ms: 120000

这个可能不需要改,因为0.10.0.0之后的版本已经由max.poll.interval.ms参数来决定。


案例二:
另外最近线上又出现另外的异常:
消息堆积一直不消费,感觉消费者已经死掉一样。重启服务后开始消费,
但是消费一段时间又停止。
开始尝试增加消费者数量和增加pod(节点)数,但是都不能完全解决,异常依然存在。
通过dump出堆栈信息发现消费则全部处在 WAITING 状态,这个状态是挂起状态,并且是无限期等待:

"kafka-coordinator-heartbeat-thread | CID_alikafka_xxx" #125 daemon prio=5 os_prio=0 tid=0x00007f1aa57fa000 nid=0x86 in Object.wait() [0x00007f1a8af80000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:502)
        at org.apache.kafka.clients.consumer.internals.AbstractCoordinator$HeartbeatThread.run(AbstractCoordinator.java:920)
        - locked <0x00000000e798f558> (a org.apache.kafka.clients.consumer.internals.ConsumerCoordinator)

   Locked ownable synchronizers:
        - None

"kafka-coordinator-heartbeat-thread | CID_alikafka_xxx" #124 daemon prio=5 os_prio=0 tid=0x00007f1aa546b800 nid=0x85 in Object.wait() [0x00007f1a8b081000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:502)
        at org.apache.kafka.clients.consumer.internals.AbstractCoordinator$HeartbeatThread.run(AbstractCoordinator.java:920)
        - locked <0x00000000e798f888> (a org.apache.kafka.clients.consumer.internals.ConsumerCoordinator)

   Locked ownable synchronizers:
        - None

后来经过查看官方文档发现一句话:
https://docs.spring.io/spring-kafka/docs/2.6.3-SNAPSHOT/reference/html/
在这里插入图片描述
消费者被挂起了,因为超过了max.poll.interval.ms默认五分钟,其实罪魁祸首还是拿到消息后业务处理太慢了,这块后续优化掉。
后面加大spring.kafka.properties.max.poll.interval.ms到600000(10分钟)解决。

spring-kafka部分参数介绍

spring.kafka.producer.batch-size 150  一次性拉取消息数

spring.kafka.properties.max.poll.interval.ms  两次poll的间隔默认5分钟

spring.kafka.producer.batch-size  一次性提交大小(默认16384字节)针对消息生产者

spring.kafka.listener.concurrency  消费者数量,平均分配kafka的partition,如24个partition,此值为8,则每个消费者负责3个partition。
### 解决 Kafka 消费者提交偏移量失败的问题 当遇到 `CommitFailedException` 错误时,通常是因为消费者组正在进行重新平衡 (rebalance),这期间尝试提交的偏移量会被拒绝。为了处理这种情况,可以采取以下措施: #### 调整配置参数 增加 `max.poll.interval.ms` 和 `session.timeout.ms` 的值可以帮助减少因长时间处理消息而导致的再平衡频率。适当延长这些超时设置能够给消费者更多时间来完成消息处理并成功提交偏移量[^3]。 ```properties props.put("max.poll.interval.ms", "600000"); // 设置为10分钟 props.put("session.timeout.ms", "45000"); // 设置为45秒 ``` #### 实现幂等性和事务支持 启用消费者的幂等性 (`enable.idempotence=true`) 可以防止由于重复提交造成的不一致问题。对于更严格的一致性需求,则应考虑使用 Kafka 提供的事务 API 来确保恰好一次语义的消息传递和偏移量管理[^2]。 ```java Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("group.id", "test-group"); props.put("key.deserializer", StringDeserializer.class.getName()); props.put("value.deserializer", StringDeserializer.class.getName()); // 启用幂等生产者特性 props.put("enable.idempotence", "true"); KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props); consumer.subscribe(Collections.singletonList(topic)); try { while (true) { ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100)); for (ConsumerRecord<String, String> record : records) System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value()); // 手动控制提交逻辑 consumer.commitSync(); } } finally { consumer.close(); } ``` #### 处理异常情况下的重试机制 编写自定义错误处理器,在捕获到 `CommitFailedException` 之后执行特定的操作,比如记录日志或者实施指数退避策略进行有限次数内的自动重试。需要注意的是,如果确实发生了再平衡事件,则应当立即停止进一步的提交操作直到下一轮轮询开始后再恢复正常的提交流程[^1]。 ```java try { consumer.commitSync(); } catch (CommitFailedException e) { logger.error("Offset commit failed due to group rebalance or shutdown.", e); // Implement backoff and retry logic here... } ``` 通过上述方法调整应用的行为模式以及合理配置相关参数,可以在很大程度上缓解甚至消除由消费者组再平衡所引发的提交偏移量失败现象。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值