春季批KafkaConsumer对多线程访问不安全

时间:2020-04-16 10:15:14

标签: spring multithreading apache-kafka spring-batch

我是批量批量生产的新手。我有需要读取kafka流并过滤数据并保存在数据库中的要求。为此,我使用了带有KafkaItemReader的spring批处理。当我在spring作业中运行启动多个作业时,它会给出 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;
    }

并且有一个控制器End Point可以启动新作业。这是我必须使用的开始新工作的方法

    @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();
    }

我已经看到KafkaItemReader不是线程safe。我想知道这种方式是正确的还是在多线程spring batch环境中有没有办法读取kafka流。 谢谢与问候

2 个答案:

答案 0 :(得分:1)

KafkaItemReader被证明是非线程安全的,这是其Javadoc的摘录:

Since KafkaConsumer is not thread-safe, this reader is not thread-safe.

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

答案 1 :(得分:1)

从春季documentation开始,它使用KafkaConsumer;根据其详细的documentation,它本身不是线程安全的。

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