消费时offset被重置导致重复消费
1.业务背景:
kafka 使用的事2.11_0.10.0.1
在做及时通讯IM的时候,客户端A发完消息后会,使用kafka 通知下游服务(kafka 消费者consumer)进行给B端用户发送消息。
2.现象:
1.在某一时间
在某一时间是kafka consumer poll处理时间9.3 s ,poll这里逻辑用了线程池,只有最后提交offests的时候会有个synchronized,但是一般都是0.1ms的。
public void execute() {
try {
while (true) {
ConsumerRecords<byte[], byte[]> records = consumer.poll(200);
StopWatch stopWatch = PerfUtlils.getWatcher();
PerfCount.countMetric(MicrometerStat.STAT_KAFKA_CONSUMER, "kafka.consumer.poll.record.count");
//1.先找出吧不同的topic 分区
for (final TopicPartition partition : records.partitions()) {
List<ConsumerRecord<byte[], byte[]>> partitionRecords = records.records(partition);
//2.对于同一个分区的不同record用独立线程处理
partitionRecords.forEach(record -> {
ConsumerWorker<T> worker = new ConsumerWorker<>(record, handler, offsets, partition);
worker.setFutureTask(executors.submit(worker));
log.info("consumer worker consume 1 message");
});
}
//3.提交offsets
commitAsyncOffsets();
PerfCount.durationTimeMetric(MicrometerStat.STAT_KAFKA_CONSUMER, "kafka.consumer.poll.process", stopWatch);
}
} catch (WakeupException e) {
log.info("kafka poll get WakeupException");
} finally {
commitSyncOffsets();
consumer.close();
}
}
2.这时候业务error 日志是
org.apache.kafka.clients.consumer.RetriableCommitFailedException: Offset commit failed with a retriable exception. You should retry committing the latest consumed offsets.
3.kafka broker 日志:
3.原因:
博主设置的消费者 session.timeout.ms=8000 8s
其中session.timeout.ms 的含义有两个(kafka 0.10.1.0之前):
- 是consumer group 检测组内成员发送奔溃的时间,回个某个group 成员突然崩溃(比如kill -9 或者宕机),group coordinator 有可能需要session.timeout.ms 时间感应到。
- 是consumer 消费处理逻辑的最大时间,倘或consumer 两次poll的时间间隔超过该参数所设的阈值,那么group coordinator 入会认为此consumer跟不上组内其他成员的消费进度并将其”踢出”组中,会进行rebalane
上面文字来自《Apache kafka 实战》
很明显博主的情况属于第二种,这个被”踢出”组中会无法提交位移,之就会造成这些消息会被其他程序消费,但此时刚好这个consumer会再次提交这个offests所有会出现上面的bug。
4.解决办法:
1.将session.timeout.ms 设置大些。
2.