我是批量批量生产的新手。我有需要读取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流。 谢谢与问候
答案 0 :(得分:1)
KafkaItemReader
被证明是非线程安全的,这是其Javadoc的摘录:
Since KafkaConsumer is not thread-safe, this reader is not thread-safe.
因此在多线程环境中使用它是不正确的,并且不符合文档说明。您可以做的是每个分区使用一个读取器。
答案 1 :(得分:1)
从春季documentation开始,它使用KafkaConsumer;根据其详细的documentation,它本身不是线程安全的。
请查看您是否可以使用该文档中提到的任何方法(即每个线程解耦或单个使用方)。在您的示例中,您可能需要为taskexecutor使用单独的处理程序(如果您遵循去耦方法)。