Java 在生成事件B后手动确认Kafka事件A
我有一个案例,我必须使用事件a并进行一些处理,然后生成事件B。因此,我的问题是,如果处理崩溃,应用程序无法生成B,而它已经使用了a。我的方法是在成功发布B之后进行确认,我是正确的还是应该为这种情况实施另一种解决方案Java 在生成事件B后手动确认Kafka事件A,java,spring,spring-boot,apache-kafka,spring-kafka,Java,Spring,Spring Boot,Apache Kafka,Spring Kafka,我有一个案例,我必须使用事件a并进行一些处理,然后生成事件B。因此,我的问题是,如果处理崩溃,应用程序无法生成B,而它已经使用了a。我的方法是在成功发布B之后进行确认,我是正确的还是应该为这种情况实施另一种解决方案 @KafkaListener( id = TOPIC_ID, topics = TOPIC_ID, groupId = GROUP_ID, containerFactory = LISTENER_CONTAINER_FA
@KafkaListener(
id = TOPIC_ID,
topics = TOPIC_ID,
groupId = GROUP_ID,
containerFactory = LISTENER_CONTAINER_FACTORY
)
public void listen(List<Message<A>> messages, Acknowledgment acknowledgment) {
try {
final AEvent aEvent = messages.stream()
.filter(message -> null != message.getPayload())
.map(Message::getPayload)
.findFirst()
.get();
processDao.doSomeProcessing() // returns a Mono<Example> by calling an externe API
.subscribe(
response -> {
ProducerRecord<String, BEvent> BEventRecord = new ProducerRecord<>(TOPIC_ID, null, BEvent);
ListenableFuture<SendResult<String, BEvent>> future = kafkaProducerTemplate.send(buildBEvent());
future.addCallback(new ListenableFutureCallback<SendResult<String, BEvent>>() {
@Override
public void onSuccess(SendResult<String, BEvent> BEventSendResult) {
//TODO: do when event published successfully
}
@Override
public void onFailure(Throwable exception) {
exception.printStackTrace();
throw new ExampleException();
}
});
},
error -> {
error.printStackTrace();
throw new ExampleException();
}
);
acknowledgment.acknowledge(); // ??
} catch (ExampleException) {
exception.printStackTrace();
}
}
@KafkaListener(
id=主题_id,
topics=TOPIC\u ID,
groupId=组\u ID,
containerFactory=侦听器\u容器\u工厂
)
公共无效侦听(列出消息、确认){
试一试{
final AEvent AEvent=messages.stream()
.filter(message->null!=message.getPayload())
.map(消息::getPayload)
.findFirst()
.get();
processDao.doSomeProcessing()//通过调用外部API返回Mono
.订阅(
答复->{
ProducerRecord BEventRecord=新的ProducerRecord(主题ID,null,BEvent);
ListenableFuture=kafkaProducerTemplate.send(buildBEvent());
future.addCallback(新ListenableFutureCallback(){
@凌驾
成功时公共无效(SendResult BEventSendResult){
//TODO:成功发布事件时执行的操作
}
@凌驾
失败时公共无效(可丢弃的例外){
异常。printStackTrace();
抛出新的ExampleException();
}
});
},
错误->{
错误。printStackTrace();
抛出新的ExampleException();
}
);
确认。确认();/??
}捕获(例如异常){
异常。printStackTrace();
}
}
使用异步代码(如reactor)时,您无法管理卡夫卡的“确认”
Kafka不管理每个主题/分区的离散ACK,只管理分区的最后提交偏移量
如果您异步处理两条记录,您将有一个关于首先提交哪个偏移量的竞争
您需要在侦听器容器线程上执行发送,以保持正确的顺序。在这种情况下,如何使用侦听线程?你能不能给我一个提示,我应该如何重构代码以获得正确的顺序?谢谢,我现在反应不太好,但我认为您需要在
Mono
上调用block()
,而不是subscribe()
,并使用结果发送消息。然后,您可以在将来完成时调用acknowledge,或者抛出异常并配置seektocurInterrorHandler
,以便重新传递记录。但是,您确实不需要使用手动确认,AckMode.BATCH
(默认值)将在侦听器正常退出时导致容器提交偏移量;您将需要更复杂的功能—保留您的订阅者,并使用某种闩锁来保持侦听器线程,直到所有处理完成。e、 g.new CountDownLatch(messages.size())
并在每次完成时对闩锁进行倒计时,以便在完成所有操作后释放侦听器线程。如果我理解清楚,请使用错误处理程序seektocurinterrorHandler
(类似),我的应用程序将再次侦听同一消息,直到流程正常完成,因此无需实现手动aknowledge,对吗?正确-但请记住,使用批处理侦听器;SeekToCurrentBatchErrorHandler
无法知道批处理中的哪个记录失败,因此无法恢复,记录将无限期地重新传递。对于暂时性错误,这是可以的,但通常,对于批处理侦听器,错误处理/恢复必须在侦听器本身中完成。您仍然可以使用seektocurrentbackerrorhandler
,但是如果同一条记录一再失败,您需要侦听器中的一些逻辑来放弃。