从主题读取消息后,我正尝试提交消息。我已经按照以下链接(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://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)之后完成执行该方法时,将提交该消息。有人可以告诉我该怎么做吗?
答案 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);