我对poll()的预期行为有些困惑。在我的应用中,如果processLogic()有效,那么我应该手动提交偏移量,以便在调用下一个poll()时,我确实会收到新消息。
processLogic()引发错误时发生问题。我设置使用者以寻求在处理期间失败的偏移量。在下一个poll()上,它再次收到相同的消息。(按照我命令消费者将偏移量手动重置到该位置的正确行为)想象一下它工作正常并且还调用了doCommitSync()。
意外的行为发生在以下poll()中。它应该接收新消息,但仍会检索最后一条消息,从而导致再次调用processLogic()函数和doCommitSync()。在doCommitSync()期间,它还会引发以下错误:
无法完成提交,因为该组已经重新平衡并已将分区分配给另一个成员。这意味着后续调用poll()之间的时间比配置的max.poll.interval.ms更长,这通常意味着轮询循环在消息处理上花费了太多时间。您可以通过增加会话超时或通过使用max.poll.records减小poll()中返回的批处理的最大大小来解决此问题。
我的消费者配置:
enable.auto.commit=false
isolation.level=read_committed
auto.offset.reset=latest
public void runConsumer() {
Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
try {
consumer.subscribe(topics);
while (!closed.get()) {
processedStatus.set(false);
final ConsumerRecords<String, String> consumedRecords = consumer.poll(numRecords);
if (!consumedRecords.isEmpty()) {
StreamSupport.stream(consumedRecords.spliterator(), false)
.map(ConsumerRecord::value)
.forEach(record -> {
try {
processLogic(); //do some logic which can fail
processedStatus.set(true);
} catch (Exception e) {
logger.error("Error applying action: " + record.getUuid(), e);
}
if (processedStatus.get()) {
doCommitSync();
} else {
consumer.seek(new TopicPartition(recordTopic, recordPartition), recordOffset);
}
});
}
}
} catch (WakeupException e) {
logger.error("Kafka Consumer wakeup exception");
} finally {
alertConsumer.close();
shutdownLatch.countDown();
}