Spring批处理-读取大型平面文件-选择水平缩放?
在过去的一两个小时里,我开始研究Spring批次。需要你的投入 问题:读取一个或多个包含2000万数据的csv文件,执行次要处理,将其存储在db中,并在最短时间内将输出写入另一个平面文件 最重要的:我需要做出选择,这些选择将在未来水平扩展 问题: 使用远程分块或分区来水平扩展 因为数据在平面文件中,所以远程分块和分区都是错误的选择 哪种多进程解决方案能够从一个大文件中读取数据,跨多个服务器进行处理,并更新数据库,但最终写入/输出到单个文件 multiresourcepartitioner是否跨服务器工作 您知道在哪里完成/演示过类似的内容吗 您的想法是:1)在开始作业之前将大文件拆分为小文件2)使用项目读取器一次读取一个文件……。假设“次要处理”不是处理过程中的瓶颈,扩展此类作业的最佳选择是通过分区。这项工作有两个步骤。第一种方法是将大文件拆分为较小的文件。为此,我建议使用Spring批处理-读取大型平面文件-选择水平缩放?,spring,spring-batch,Spring,Spring Batch,在过去的一两个小时里,我开始研究Spring批次。需要你的投入 问题:读取一个或多个包含2000万数据的csv文件,执行次要处理,将其存储在db中,并在最短时间内将输出写入另一个平面文件 最重要的:我需要做出选择,这些选择将在未来水平扩展 问题: 使用远程分块或分区来水平扩展 因为数据在平面文件中,所以远程分块和分区都是错误的选择 哪种多进程解决方案能够从一个大文件中读取数据,跨多个服务器进行处理,并更新数据库,但最终写入/输出到单个文件 multiresourcepartitioner是否跨服
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
。然后将通过从机(在线程上本地运行或远程侦听某些消息传递中间件)执行这些操作
在这种方法中需要注意的一点是,从原始文件处理记录的顺序将不会得到维护
您可以在这里看到一个完整的远程分区示例:在这里可以找到一段对话/演示视频:使用
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;
}
@Bean
公共分区器分区器(){
MultiResourcePartitioner partitioner=新的MultiResourcePartitioner();
ClassLoader cl=this.getClass().getClassLoader();
ResourcePatternResolver解析器=新路径匹配ResourcePatternResolver(cl);
Resource[]resources=resolver.getResources(“文件:“+filePath+”/“+”*.csv”);
partitioner.setResources(资源);
分区器。分区(10);
返回分区器;
}
@豆子
公共任务执行器任务执行器(){
ThreadPoolTaskExecutor taskExecutor=新的ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(4);
taskExecutor.AfterPropertieSet();
返回任务执行器;
}
@豆子
@限定词(“主步骤”)
公共步骤masterStep(){
return stepBuilderFactory.get(“masterStep”)
.partitioner(processDataStep())
.partitioner(“processDataStep”,partitioner())
.taskExecutor(taskExecutor())
.listener(侦听器)
.build();
}
@豆子
@限定符(“processData”)
公共步骤processData(){
返回stepBuilderFactory.get(“processData”)
.chunk(5000)
.读卡器(读卡器)
.processor(处理器())
.作者(作者)
.build();
}
@Bean(name=“reader”)
@步进镜
公共FlatFileItemReader读取器(@Value(“#{stepExecutionContext['fileName']}”)字符串文件名){
FlatFileItemReader=新的FlatFileItemReader();
setResource(新的UrlResource(文件名));
reader.setLineMapper(新的DefaultLineMapper(){
{
setLineTokenizer(新的DelimitedLineTokenizer(){
{
设置名称(文件头);
}
});
setFieldSetMapper(新的BeanRapperFieldSetMapper(){
{
setTargetType(pojo.class);
}
});
}
});
返回读取器;
}
“MultiResourcePartitioner为每个文件生成步骤执行”,这会在处理多个文件时占用太多内存。我们怎样才能避免这种情况呢。什么叫“多文件”?2.请围绕这个问题提出一个新问题,比如200.000个文件。我已经打开了一个问题,但还没有回答:我希望是这样。@MichaelMinella我已经将一个大文件按1MB分成了几个部分。如何将有关步骤计数的信息传递到下一步