CommitFailedException异常处理和预防
CommitFailedException: Consumer 客户端在提交位移时出现了错误或异常,而且还是那种不可恢复的严重异常。
当然
1.常见场景 max.poll.interval.ms超时
当消息处理的总时间超过预设的max.poll.interval.ms 参数就会发生CommitFailedException异常
比如
Properties props = new Properties();
…
props.put("max.poll.interval.ms", 5000);
consumer.subscribe(Arrays.asList("test-topic"));
while (true) {
ConsumerRecords<String, String> records =
consumer.poll(Duration.ofSeconds(1));
// 使用 Thread.sleep 模拟真实的消息处理逻辑
Thread.sleep(6000L);
consumer.commitSync();
}
1.1解决方案
1. 缩短单条消息处理的时间。 加快你的业务效率,之前下游系统消费一条消息的时间是 100 毫秒,优化之后成功地下降到 50 毫秒,那么此时 Consumer 端的 TPS 就提升了一倍。
2.增加 Consumer 端允许下游系统消费一批消息的最大时长。 增加max.poll.interval.ms 值,默认是5分钟,如果业务逻辑没法简化的时候,增加最大轮询间隔时间也是不错的选择,这里不使用session.timeout.ms会话超时时间是因为这个代表的含义会有其他的不良影响,不便去调整这个参数
3. 减少下游系统一次性消费的消息总数。 max.poll.records,让下游的消费端减低一次性的消费数量,比如默认500条,让他减少消费一次性的数量换成200条
4. 下游系统使用多线程来加速消费。 最难最高级的方法,让下游系统手动创建多个消费线程处理 poll 方法返回的一批消息。之前你使用 Kafka Consumer 消费数据更多是单线程的,所以当消费速度无法匹及Kafka Consumer 消息返回的速度时,它就会抛出 CommitFailedException 异常。如果是多线程,你就可以灵活地控制线程数量,随时调整消费承载能力,再配以目前多核的硬件条件,该方法可谓是防止 CommitFailedException 最高档的解决之道。事实上,很多主流的大数据流处理框架使用的都是这个方法,比如 Apache Flink 在集成Kafka 时,就是创建了多个 KafkaConsumerThread 线程,自行处理多线程间的数据消费。
2.特殊场景 StandaloneConsumer独立消费者和消费者组同时使用
如果你的应用中同时出现了设置相同 group.id 值的消费者组程序和独立消费者程序,那么当独立消费者程序手动提交位移时,Kafka 就会立即抛出CommitFailedException 异常因为 Kafka 无法识别这个具有相同 group.id 的消费者实例,于是就向它返回一个错误,表明它不是消费者组内合法的成员。
并且以上四种的解决方案都是无效的,当如果出现独立消费者可以往这个角度思考。
如有错误欢迎指正