Java 成功批量插入后更新Kafka提交偏移量

Java 成功批量插入后更新Kafka提交偏移量,java,spring,apache-kafka,spring-kafka,Java,Spring,Apache Kafka,Spring Kafka,我有一个spring kafka消费者,它读取记录并将其交给缓存。计划的任务将定期清除缓存中的记录。我只想在批成功保存到数据库中后更新提交偏移量。我尝试将Acknowledgement对象传递给缓存服务以调用acknowledge方法,如下所示 public class KafkaConsumer { @KafkaListener( topicPattern = "${kafka.topicpattern}", containerFactory = "kafkaListenerConta

我有一个spring kafka消费者,它读取记录并将其交给缓存。计划的任务将定期清除缓存中的记录。我只想在批成功保存到数据库中后更新提交偏移量。我尝试将Acknowledgement对象传递给缓存服务以调用acknowledge方法,如下所示

public class KafkaConsumer {
    @KafkaListener( topicPattern = "${kafka.topicpattern}", containerFactory = "kafkaListenerContainerFactory" )
    public void receive( ConsumerRecord<String, String> record, Acknowledgment acknowledgment ) {
        cacheService.add( record.value(), acknowledgment );
    }
}

public class CacheService {
    // concurrency handling has been left out in favor of readability
    public void add( String record, Acknowledgment acknowledgment ) {
        this.records.add(record);
        this.lastAcknowledgment = acknowledgment;
    }

    public void saveBatch() { //called by scheduled task
        if( records.size() == BATCH_SIZE ) {
            // perform batch insert into database
            this.lastAcknowledgment.acknowledge();
            this.records.clear();
        }
    }
}
并且自动提交为false:

config.put( ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false );
即使调用了acknowledge方法,提交偏移量也不会更新。保存记录后更新提交偏移量的最佳方法是什么

我使用的是spring kafka 2.1.7.RELEASE



编辑:在@GaryRussell发现在下一次轮询期间,外部线程所做的确认由消费者线程执行之后,我重新检查了我的代码,发现上一次确认对象的设置存在错误修复此问题后,提交偏移量将按预期更新。所以这个问题已经解决了。但是,我无法将此问题标记为已回答。

问题在于,使用者线程负责提交偏移量。在轮询时,使用者线程将提交上一批偏移量

由于在您的情况下,
AUTO_COMMIT
为false,且
lastAcknowledgement.acknowledge()
为NotAcknowledge,因此偏移量不提交

只有一种方法可以做到这一点,一旦您获得轮询记录,将任务安排为异步任务,并在异步任务完成后保持使用者线程并提交偏移量,请检查此答案以供参考

注意如果您按住消费者线程超过5分钟,将发生重新平衡

新的Java消费者现在支持后台线程的心跳。有一个新的配置max.poll.interval.ms,它控制用户主动离开组之前轮询调用之间的最长时间(默认为5分钟)。configuration request.timeout.ms的值必须始终大于
max.poll.interval.ms
,因为这是使用者重新平衡时JoinGroup请求可以在服务器上阻止的最长时间,所以我们将其默认值更改为略高于5分钟。最后,
session.timeout.ms
的默认值已调整为10秒,而
max.poll.records
的默认值已更改为500

特别提示摘自《卡夫卡之春》2.1.5


消费者线程将在下一次轮询之前执行对外部线程的确认感谢@Gary Russell提供此信息

调度任务是另一个线程吗?我相信这是最后一次确认应该在使用者线程上调用,您如何定义未提交的偏移量?您的spring kafka版本是什么?是的,计划的任务是不同的线程,因为我不想在消息被持久化时阻止消息的使用。使用命令行工具kafka-consumer-groups.sh,我可以看到当前偏移量没有更新。它的spring kafka 2.1.7.release您需要保留消费者线程在“外部”线程上所做的确认将由消费者线程在下一次轮询()之前执行;请参阅。但我相信在下一次
轮询之前不会发生
Ack
,一旦消费者线程空闲,它将轮询下一个偏移,对吗@GaryRussell和此提交来自
2.1.5
,这是正确的;异步偏移量提交实际发生的时间取决于提交ack时使用者线程的状态。如果它在
轮询()中被“卡住”(并且没有更多的记录可用),则在轮询退出(超时)时以及在下一次轮询之前会发生提交,如果轮询返回更多的记录,则在这些记录全部发送给侦听器之前不会发生提交
processCommits()
poll()之前调用,并提交任何挂起的偏移量(从异步线程提交的所有偏移量都添加到挂起队列)。是的,它是在2.1.5中添加的。我们没有选择-消费者不是线程安全的。要使侦听器拥有完全的控制权,必须在使用者线程上执行确认(然后使用MANUAL_IMMEDIATE,以便立即进行提交)。@GaryRussell-非常感谢您确认外部线程所做的确认仍然由使用者线程执行。在这之后,我检查了我的代码,发现最后一次确认的设置有一个bug。修复此问题后,将更新提交偏移量,如您所述。
config.put( ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false );