spring batch KafkaConsumer对于多线程访问不安全

spring batch KafkaConsumer对于多线程访问不安全,spring,multithreading,apache-kafka,spring-batch,Spring,Multithreading,Apache Kafka,Spring Batch,我是新的孢子批。我有要求,需要读取卡夫卡流和过滤数据,并保存在数据库中。为此,我使用了带有KafkaItemReader的spring批处理。当我在spring job中运行start multiple jobs时,它会给出java.util.ConcurrentModificationException:KafkaConsumer对于多线程访问来说是不安全的错误。在这段时间内,它只运行最后一个作业 这是spring批处理配置 @Autowired TaskExecutor ta

我是新的孢子批。我有要求,需要读取卡夫卡流和过滤数据,并保存在数据库中。为此,我使用了带有KafkaItemReader的spring批处理。当我在spring job中运行start multiple jobs时,它会给出java.util.ConcurrentModificationException:KafkaConsumer对于多线程访问来说是不安全的错误。在这段时间内,它只运行最后一个作业

这是spring批处理配置

    @Autowired
    TaskExecutor taskExecutor;

    @Autowired
    JobRepository jobRepository;

    @Bean
    KafkaItemReader<Long, Event> kafkaItemReader() {
        Properties props = new Properties();
        props.put(JsonSerializer.ADD_TYPE_INFO_HEADERS, false);
        props.putAll(this.properties.buildConsumerProperties());
        return new KafkaItemReaderBuilder<Long, Event>()
                .partitions(0)
                .consumerProperties(props)
                .name("event-reader")
                .saveState(true)
                .topic(topicName)
                .build();
    }

    @Bean
    public TaskExecutor taskExecutor(){
        SimpleAsyncTaskExecutor asyncTaskExecutor=new SimpleAsyncTaskExecutor("spring_batch");
        asyncTaskExecutor.setConcurrencyLimit(5);
        return asyncTaskExecutor;
    }

    @Bean(name = "JobLauncher")
    public JobLauncher simpleJobLauncher() throws Exception {
        SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
        jobLauncher.setJobRepository(jobRepository);
        jobLauncher.setTaskExecutor(taskExecutor);
        jobLauncher.afterPropertiesSet();
        return jobLauncher;
    }
@Autowired
任务执行者任务执行者;
@自动连线
作业库作业库;
@豆子
卡夫卡泰姆阅读器卡夫卡泰姆阅读器(){
Properties props=新属性();
props.put(JsonSerializer.ADD_TYPE_INFO_头,false);
props.putAll(this.properties.buildConsumerProperties());
返回新的KafkaItemReaderBuilder()
.分区(0)
.消费者财产(道具)
.name(“事件读取器”)
.saveState(true)
.主题(主题名称)
.build();
}
@豆子
公共任务执行器任务执行器(){
SimpleAsyncTaskExecutor asyncTaskExecutor=新的SimpleAsyncTaskExecutor(“spring_批处理”);
asyncTaskExecutor.setConcurrencyLimit(5);
返回异步任务执行器;
}
@Bean(name=“JobLauncher”)
public JobLauncher simpleJobLauncher()引发异常{
SimpleJobLauncher jobLauncher=新的SimpleJobLauncher();
jobLauncher.setJobRepository(jobRepository);
jobLauncher.setTaskExecutor(taskExecutor);
jobLauncher.AfterPropertieSet();
返回作业启动器;
}
还有一个控制器端点,它开始新的作业。这就是我开始新工作的方式

    @Autowired
    @Qualifier("JobLauncher")
    private JobLauncher jobLauncher;


    Map<String, JobParameter> items = new HashMap<>();
    items.put("userId", new JobParameter("UserInputId"));
    JobParameters paramaters = new JobParameters(items);
    try {
        jobLauncher.run(job, paramaters);
    } catch (Exception e) {
        e.printStackTrace();
    }
@Autowired
@限定符(“JobLauncher”)
私有JobLauncher JobLauncher;
Map items=newhashmap();
items.put(“userId”,新作业参数(“UserInputId”);
JobParameters paramaters=新的JobParameters(项目);
试一试{
jobLauncher.run(作业,参数);
}捕获(例外e){
e、 printStackTrace();
}
我已经看到卡夫卡泰姆阅读器不是线程。我想知道这种方法是否正确,或者有没有任何方法可以在多线程spring批处理环境中读取kafka流。
感谢和问候

KafkaItemReader被证明是非线程安全的,以下是其:

因此,在多线程环境中使用它是不正确的,并且不符合文档要求。您可以做的是在每个分区使用一个读卡器。

根据spring,它使用KafkaConsumer;根据其详细说明,其本身不是线程安全的


请查看您是否可以使用该文档中提到的任何方法(即解耦或每个线程一个使用者)。在您的示例中,您可能需要为taskexecutor使用单独的处理程序(如果您遵循解耦方法)

谢谢你的快速回复。你是写这本书的人,我知道。我是新的春天批和卡夫卡以及。卡夫卡阅读器分区是否有我更喜欢的文档。在这种情况下,请接受答案:(请注意,接受答案不同于投票)。我没有一个例子,但是你可以为每个分区创建一个读卡器(也就是多个读卡器,分配给不同分区的每个线程一个读卡器)。谢谢你的快速回复。对于decouple task manager,是否有我更喜欢的文档。在joblauncher中,不要像当前那样设置taskexecutor。这将使紧密耦合。相反,调用一些处理程序,这些处理程序将依次调用任务执行器。Handler是独立的类&该类可以调用任务执行器。
Since KafkaConsumer is not thread-safe, this reader is not thread-safe.