Spring boot 消费者情绪低落时卡夫卡信息丢失

Spring boot 消费者情绪低落时卡夫卡信息丢失,spring-boot,apache-kafka,kafka-consumer-api,spring-cloud-stream,Spring Boot,Apache Kafka,Kafka Consumer Api,Spring Cloud Stream,您好,我正在使用spring cloud stream编写一个卡夫卡消费制作人。在消费者内部,我将数据保存到数据库中,如果数据库关闭,我将手动退出应用程序。重新启动应用程序后,如果数据库仍然关闭,则应用程序将再次停止。现在,如果我在第三次重启应用程序时,中间间隔(两个故障)接收到的消息丢失,卡夫卡消费者获取最新消息,也跳过我退出代码的消息。 入站和出站通道绑定器接口 public interface EventChannel { String inputEvent = "inputChanne

您好,我正在使用spring cloud stream编写一个卡夫卡消费制作人。在消费者内部,我将数据保存到数据库中,如果数据库关闭,我将手动退出应用程序。重新启动应用程序后,如果数据库仍然关闭,则应用程序将再次停止。现在,如果我在第三次重启应用程序时,中间间隔(两个故障)接收到的消息丢失,卡夫卡消费者获取最新消息,也跳过我退出代码的消息。 入站和出站通道绑定器接口

public interface EventChannel {

String inputEvent = "inputChannel";
String outputEvent = "outputChannel";

@Input(inputChannel)
SubscribableChannel consumeEvent();

@Output(outputEvent)
SubscribableChannel produceEvent();
}
服务等级-

1) 生产性服务业

@Service
@EnableBinding(EventChannel.class)

public class EventProducerService{

private final EventChannel eventChannel;

@Autowired  
public EventConsumerService(EventChannel eventChannel){
this.eventChannel = eventChannel;
}

public void postEvent(EventDTO event) {
    MessageChannel messageChannel = eventChannel.produceEvent();
    messageChannel.send(MessageBuilder
            .withPayload(event)
            .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON)
            .setHeader("partitionKey",event.getId().toString())
            .build());     
    }
}
@Component
@EnableBinding(EventChannel.class)
public class EventConsumerService{ 

private final ApplicationContext applicationContext;
private final EventChannel eventChannel;

@Autowired  
public EventConsumerService(ApplicationContext applicationContext,EventChannel eventChannel){
this.applicationContext = applicationContext;
this.eventChannel = eventChannel;
}

@StreamListener(EventChannel.inputEvent)
public void saveUpdateCassandra(EventDTO event){
  Event newEvent = new Event(event);
  try{
     eventRepository.save(newEvent)
    } catch(Exceptione e){
     e.printStackTrace();
     SpringApplication.exit(applicationContext,()-> 0); 
  }
}
2) 消费者服务

@Service
@EnableBinding(EventChannel.class)

public class EventProducerService{

private final EventChannel eventChannel;

@Autowired  
public EventConsumerService(EventChannel eventChannel){
this.eventChannel = eventChannel;
}

public void postEvent(EventDTO event) {
    MessageChannel messageChannel = eventChannel.produceEvent();
    messageChannel.send(MessageBuilder
            .withPayload(event)
            .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON)
            .setHeader("partitionKey",event.getId().toString())
            .build());     
    }
}
@Component
@EnableBinding(EventChannel.class)
public class EventConsumerService{ 

private final ApplicationContext applicationContext;
private final EventChannel eventChannel;

@Autowired  
public EventConsumerService(ApplicationContext applicationContext,EventChannel eventChannel){
this.applicationContext = applicationContext;
this.eventChannel = eventChannel;
}

@StreamListener(EventChannel.inputEvent)
public void saveUpdateCassandra(EventDTO event){
  Event newEvent = new Event(event);
  try{
     eventRepository.save(newEvent)
    } catch(Exceptione e){
     e.printStackTrace();
     SpringApplication.exit(applicationContext,()-> 0); 
  }
}
应用程序属性文件

#Spring Cloud Streams Configuration
##Broker
spring.cloud.stream.kafka.binder.brokers=localhost:9092
##EventIngestion 
spring.cloud.stream.bindings.outputChannel.destination=Event
spring.cloud.stream.bindings.outputChannel.producer.partitionKeyExpression=headers.partitionKey
spring.cloud.stream.bindings.inputChannel.destination=Event
spring.cloud.stream.bindings.inputChannel.group=event-consumer-1
spring.cloud.stream.kafka.bindings.inputChannel.consumer.startOffset=earliest

这两个应用程序都是独立运行的,因此如果我的数据库出现故障,消费者停止,在连续失败时消息会丢失

首先,我不确定您对
SpringApplication.exit(applicationContext,()->0)的期望是什么,但您实际上是在破坏整个应用程序及其可能运行的所有内容。
其次,您的消息丢失是由于卡夫卡·宾德完全不知道发生了异常,并且必须将消息放回主题。事实上,从活页夹的角度来看,由于您的代码,每条消息总是被成功处理。所以


请从StreamListener方法中删除
try/catch
,并让异常传播,从而让binder知道有错误。

首先,我不确定您对
SpringApplication.exit(applicationContext,()->0)的期望是什么,但您实际上是在破坏整个应用程序及其可能运行的所有内容。
其次,您的消息丢失是由于卡夫卡·宾德完全不知道发生了异常,并且必须将消息放回主题。事实上,从活页夹的角度来看,由于您的代码,每条消息总是被成功处理。所以


请从StreamListener方法中删除
try/catch
,并让异常传播,从而让binder知道有错误。

由于在侦听器正常退出之前不会提交偏移量,因此终止JVM将导致重新启动时重新交付。除非enable.auto.commit为true,否则当然,即使我删除了SpringApplication.exit消息,也会启用.auto commitlost@GaryRussell我知道收到信息后会立即发送偏移量,但在我的情况下,多条信息会丢失。我说过,根据您的代码(我们可以从您的帖子中看到),信息不会丢失,它们被成功地处理了——这就是框架所看到的;我假设
exit()
调用了
System.exit(n)
。它没有;因此监听器正常退出,记录偏移量被提交。由于偏移量在监听器正常退出之前不会被提交,因此终止JVM应该会导致重启时重新交付。除非enable.auto.commit为true,否则当然,即使我删除了SpringApplication.exit消息,也会启用.auto commitlost@GaryRussell我知道收到信息后会立即发送偏移量,但在我的情况下,多条信息会丢失。我说过,根据您的代码(我们可以从您的帖子中看到),信息不会丢失,它们被成功地处理了——这就是框架所看到的;我假设
exit()
调用了
System.exit(n)
。它没有;因此侦听器正常退出,记录偏移量被提交。