从主题阅读后立即提交消息

时间:2019-05-29 06:57:34

标签: java spring apache-kafka

从主题读取消息后,我正尝试提交消息。我已经按照以下链接(https://www.confluent.io/blog/apache-kafka-spring-boot-application)创建了一个带有春天的Kafka用户。通常情况下,它工作完美,并且消费者获得消息并等待,直到另一个人进入队列。但是问题是,当我处理此消息时,它花费了很多时间(大约10分钟),kafka队列认为该消息没有被使用(提交),并且使用者一次又一次地读取了该消息。我不得不说,当我的处理时间少于5分钟时,效果很好,但持续时间更长,则不会提交消息。

我一直在寻找一些答案,但这对我没有帮助,因为我没有使用相同的源代码(当然也使用不同的结构)。我尝试发送异步方法,并异步提交消息,但失败了。 一些来源是:

Spring Boot Kafka: Commit cannot be completed since the group has already rebalanced

https://www.confluent.io/blog/tutorial-getting-started-with-the-new-apache-kafka-0-9-consumer-client/

https://dzone.com/articles/kafka-clients-at-most-once-at-least-once-exactly-o

Kafka 0.10 Java consumer not reading message from topic

https://github.com/confluentinc/confluent-kafka-dotnet/issues/470

主要班级在这里:


@SpringBootApplication
@EnableAsync
public class SpringBootKafkaApp {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootKafkaApp .class, args);
    }


消费者类(我需要在其中提交消息)

@Service
public class Consumer {

@Autowired
    AppPropert prop;

   Consumer cons;
@KafkaListener(topics = "${app.topic.pro}", groupId = "group_id")
    public void consume(String message) throws IOException {
        /*HERE I MUST CONSUME THE MESSAGE AND COMMIT IT */

        Properties  props=prope.startProp();//just getting my properties from my config-file
        ControllerPRO pro = new ControllerPRO();

        List<Future<String>> async= new ArrayList<Future<String>>();//call this method asynchronous, doesn't help me
        try {

            CompletableFuture<String> ret=pro.processLaunch(message,props);//here I call the process method 
            /*This works fine when the processLaunch method takes less than 5 minutes, 
            if it takes longer the consumer will get the same message from the topic and start again with this operation 
            */

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("End of consumer method ");

    }

    }


从队列中读取消息后,如何提交消息。

我想确保在收到消息时立即提交消息。现在,当我在(System.out.println)之后完成执行该方法时,将提交该消息。有人可以告诉我该怎么做吗?

3 个答案:

答案 0 :(得分:2)

您必须使用属性enable.auto.commit设置为false来修改消费者配置:

properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);

然后,您必须修改Spring Kafka Listener工厂并将ack-mode设置为MANUAL_IMMEDIATE。这是ConcurrentKafkaListenerContainerFactory的示例:

@Bean
public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory() {
    ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory();
    factory.setConsumerFactory(consumerFactory());
    factory.getContainerProperties().setAckOnError(false);
    factory.getContainerProperties().setAckMode(AckMode.MANUAL_IMMEDIATE);
    factory.setErrorHandler(new SeekToCurrentErrorHandler());
    return factory;
}

如文档中所述,MANUAL_IMMEDIATE的意思是:当侦听器调用Acknowledgment.acknowledge()方法时,立即提交偏移量。

您可以找到所有的提交方法here

然后,在您的侦听器代码中,您可以通过添加Acknowledgment对象来手动提交偏移量,例如:

@KafkaListener(topics = "${app.topic.pro}", groupId = "group_id")
public void consume(String message, Acknowledgment acknowledgment) {
   // commit immediately
    acknowledgment.acknowledge();
}

答案 1 :(得分:0)

您可以在消费并提交Kafka偏移量时使用java.util.concurrent.BlockingQueue推送消息。然后使用另一个线程从blockingQueue获取消息并进行处理。这样,您不必等到处理完成。

答案 2 :(得分:0)

properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,false);

设置上述属性后,如果要批量处理,则可以遵循以下img配置。

     factory.getContainerProperties().setAckMode(AckMode.MANUAL);

//您可以设置Manual或MANUAL_IMMEDIATE,因为// KafkaMessageListenerContainer调用 // ConsumerBatchAcknowledgment用于任何手动确认模式

    factory.getContainerProperties().setAckOnError(true);
    //specifying batch error handler because i have enabled to listen records in batch
    factory.setBatchErrorHandler(new SeekToCurrentBatchErrorHandler());
    factory.setBatchListener(true);
    factory.getContainerProperties().setSyncCommits(false);