Java Spring批处理:KafkaItemReader仅在消费者作业在生产者作业之前启动并且指定了正确的分区时才工作

Java Spring批处理:KafkaItemReader仅在消费者作业在生产者作业之前启动并且指定了正确的分区时才工作,java,apache-kafka,spring-batch,consumer,Java,Apache Kafka,Spring Batch,Consumer,我有一个简单的Spring批处理作业,它读取具有3个分区的Kafka主题。我有以下意见/问题: 如果在将消息发布到主题后启动使用者作业,则使用者作业将无限期地等待消息。消费者仅在先启动消息,然后生成主题消息时才会使用消息。在现实世界中,我不能等待消息发布后再开始消费者工作。我怎么处理这个 我的主题有4个分区,但只有当我向读者提供分区0、1和2时,使用者才能工作。如果我也提供了分区3,那么消费者waitis infinitley和somtimes也会抛出以下异常: Exception is...

我有一个简单的Spring批处理作业,它读取具有3个分区的Kafka主题。我有以下意见/问题:

  • 如果在将消息发布到主题后启动使用者作业,则使用者作业将无限期地等待消息。消费者仅在先启动消息,然后生成主题消息时才会使用消息。在现实世界中,我不能等待消息发布后再开始消费者工作。我怎么处理这个

  • 我的主题有4个分区,但只有当我向读者提供分区0、1和2时,使用者才能工作。如果我也提供了分区3,那么消费者waitis infinitley和somtimes也会抛出以下异常:

    Exception is......................... : 
    org.apache.kafka.common.errors.TimeoutException: Timeout of 60000ms 
    expired before successfully committing the current consumed offsets
    org.apache.kafka.common.errors.TimeoutException: Timeout of 60000ms 
    expired before successfully committing the current consumed offsets
    
  • 消费者作业配置:

    @Configuration
    @EnableBatchProcessing
    public class BatchConfiguration {
    
        @Autowired
        private JobBuilderFactory jobBuilderFactory;
    
        @Autowired
        private StepBuilderFactory stepBuilderFactory;
    
        @Bean
        public Job job() {
            return jobBuilderFactory.get("job").incrementer(new RunIdIncrementer())
                    .start(testFileWritingStep()).build();
        }
    
        @Bean
        public Step testFileWritingStep() {
            return stepBuilderFactory.get("testFileWritingStep").<String, String>chunk(10)
                    .reader(testKafkaItemReader()).writer(testFileWriter()).build();
        }
    
        @Bean
        public KafkaItemReader<String, String> testKafkaItemReader() {
            Properties props = new Properties();
            //not providing the actual broker hosts and ports on stackoverfow for security reasons..
            props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,
                    "somebroker:someport,somebroker:someport,somebroker:someport,somebroker:someport");
            props.put(ConsumerConfig.GROUP_ID_CONFIG, "mygroup");
            props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SSL");
            props.put(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG, "src/main/resources/conf/trust.jks");
            props.put(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, "pass");
            props.put(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG, "src/main/resources/conf/loc.jks");
            props.put(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG, "pass");
            props.put(SslConfigs.SSL_KEY_PASSWORD_CONFIG, "pass");
    
                
            props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
                    "org.apache.kafka.common.serialization.StringDeserializer");
            props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
                    "org.apache.kafka.common.serialization.StringDeserializer");
    
            return new KafkaItemReaderBuilder<String, String>().partitions(0,1,2).consumerProperties(props)
                    .name("myreader").saveState(true).topic("mytopic").build();
        }
    
        @Bean
        public FlatFileItemWriter<String> testFileWriter() {
            FlatFileItemWriter<String> writer = new FlatFileItemWriter<>();
            writer.setResource(new FileSystemResource(
                    "I:/CK/data/output.dat"));
            writer.setAppendAllowed(false);
            writer.setShouldDeleteIfExists(true);
            DelimitedLineAggregator<String> lineAggregator = new DelimitedLineAggregator<>();
            lineAggregator.setDelimiter(",");
            writer.setLineAggregator(lineAggregator);
            return writer;
        }
    }
    
    @配置
    @启用批处理
    公共类批处理配置{
    @自动连线
    私人JobBuilderFactory JobBuilderFactory;
    @自动连线
    私人StepBuilderFactory StepBuilderFactory;
    @豆子
    公职{
    返回jobBuilderFactory.get(“job”).incrementer(新的RunIdIncrementer())
    .start(testFileWritingStep()).build();
    }
    @豆子
    公共步骤testFileWritingStep(){
    返回stepBuilderFactory.get(“testFileWritingStep”).chunk(10)
    .reader(testKafkaItemReader()).writer(testFileWriter()).build();
    }
    @豆子
    公共KafkaItemReader testKafkaItemReader(){
    Properties props=新属性();
    //出于安全原因,没有在stackoverfow上提供实际的代理主机和端口。。
    props.put(ProducerConfig.BOOTSTRAP\u SERVERS\u CONFIG,
    “somebroker:someport,somebroker:someport,somebroker:someport,somebroker:someport”);
    props.put(ConsumerConfig.GROUP_ID_CONFIG,“mygroup”);
    props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG,“SSL”);
    put(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG,“src/main/resources/conf/trust.jks”);
    props.put(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG,“pass”);
    put(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG,“src/main/resources/conf/loc.jks”);
    props.put(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG,“pass”);
    props.put(SslConfigs.SSL_KEY_PASSWORD_CONFIG,“pass”);
    props.put(ConsumerConfig.KEY\u反序列化程序\u类\u配置,
    “org.apache.kafka.common.serialization.StringDeserializer”);
    props.put(ConsumerConfig.VALUE\u反序列化程序\u类\u配置,
    “org.apache.kafka.common.serialization.StringDeserializer”);
    返回新的KafkaItemReaderBuilder().分区(0,1,2).consumerProperties(道具)
    .name(“myreader”).saveState(true).topic(“mytopic”).build();
    }
    @豆子
    公共FlatFileItemWriter testFileWriter(){
    FlatFileItemWriter writer=新的FlatFileItemWriter();
    writer.setResource(新文件系统资源(
    “I:/CK/data/output.dat”);
    writer.setAppendAllowed(false);
    writer.setShouldDeleteIfExists(true);
    DelimitedLineAggregator lineAggregator=新的DelimitedLineAggregator();
    lineAggregator.setDelimiter(“,”);
    writer.setLineAggregator(lineAggregator);
    返回作者;
    }
    }
    
    1。读卡器不应无限等待,您可以设置一个值,然后读卡器将返回
    null
    并结束该步骤。2.你确定你的卡夫卡经纪人在这个案子中还活着吗?@MahmoudBenHassine谢谢你的评论。因为你是对的。我的读卡器超时时间很高。也就是说,仍然无法理解为什么只有在消息发布之前启动消息时,读者才会使用消息。我如何确保读者在主题开始之前阅读该主题上已有的消息?对于2)我有一个4代理设置。我的主题有4个分区和4个副本。即使一个经纪人真的倒下了,我也会假设读者会继续和其他经纪人合作。确保经纪商永远不会倒闭会适得其反吗?