我在过去一两个小时内开始研究Spring Batch。并要求你输入。
问题:读取包含2000万个数据的多个csv文件,执行次要处理,将其存储在db中,并在最短时间内将输出写入另一个平面文件。
最重要的:我需要做出将来会横向扩展的选择。
问题:
使用远程分块或分区水平缩放?
由于数据是平面文件,因此远程分块和分区都是错误的选择吗?
哪个多进程解决方案可以从大文件中读取,跨多个服务器传播处理并更新Db但最终写入/输出到单个文件?
multiresourcepartitioner是否跨服务器工作?
你知道任何类似的东西已经完成/演示的任何好的教程吗?
您对如何进行此操作的想法,例如1)在开始作业之前将大文件拆分为较小的文件2)使用项目阅读器一次读取一个文件...........
答案 0 :(得分:5)
假设"次要处理"在处理过程中不是瓶颈,扩展此类工作的最佳选择是通过分区。这项工作将有两个步骤。第一个将大文件拆分为较小的文件。为此,我建议使用SystemCommandTasklet
向操作系统发送文件以拆分文件(这通常比通过JVM传输整个文件更高效)。这样做的例子如下:
<bean id="fileSplittingTasklet" class="org.springframework.batch.core.step.tasklet.SystemCommandTasklet" scope="step">
<property name="command" value="split -a 5 -l 10000 #{jobParameters['inputFile']} #{jobParameters['stagingDirectory']}"/>
<property name="timeout" value="60000"/>
<property name="workingDirectory" value="/tmp/input_temp"/>
</bean>
第二步是分区步骤。如果文件位于未共享的位置,则您使用本地分区。但是,如果生成的文件位于某处的网络共享上,则可以使用远程分区。在任何一种情况下,您都可以使用MultiResourcePartitioner
为每个文件生成StepExecution
。然后,这些将通过从服务器执行(在线程上本地运行或远程监听某些消息传递中间件)。
这种方法需要注意的一点是,不会保留从原始文件处理记录的顺序。
您可以在此处查看完整的远程分区示例:https://github.com/mminella/Spring-Batch-Talk-2.0,可在此处找到谈话/演示的视频:https://www.youtube.com/watch?v=CYTj5YT7CZU
答案 1 :(得分:0)
使用MultiResourcePartitioner
来阅读这对我有用的大文件
@Bean
public Partitioner partitioner() {
MultiResourcePartitioner partitioner = new MultiResourcePartitioner();
ClassLoader cl = this.getClass().getClassLoader();
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(cl);
Resource[] resources = resolver.getResources("file:" + filePath + "/"+"*.csv");
partitioner.setResources(resources);
partitioner.partition(10);
return partitioner;
}
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(4);
taskExecutor.afterPropertiesSet();
return taskExecutor;
}
@Bean
@Qualifier("masterStep")
public Step masterStep() {
return stepBuilderFactory.get("masterStep")
.partitioner(processDataStep())
.partitioner("processDataStep",partitioner())
.taskExecutor(taskExecutor())
.listener(listener)
.build();
}
@Bean
@Qualifier("processData")
public Step processData() {
return stepBuilderFactory.get("processData")
.<pojo, pojo> chunk(5000)
.reader(reader)
.processor(processor())
.writer(writer)
.build();
}
@Bean(name="reader")
@StepScope
public FlatFileItemReader<pojo> reader(@Value("#{stepExecutionContext['fileName']}") String filename) {
FlatFileItemReader<pojo> reader = new FlatFileItemReader<>();
reader.setResource(new UrlResource(filename));
reader.setLineMapper(new DefaultLineMapper<pojo>() {
{
setLineTokenizer(new DelimitedLineTokenizer() {
{
setNames(FILE HEADER);
}
});
setFieldSetMapper(new BeanWrapperFieldSetMapper<pojo>() {
{
setTargetType(pojo.class);
}
});
}
});
return reader;
}