Spring批处理-读取大型平面文件-选择水平缩放?

Spring批处理-读取大型平面文件-选择水平缩放?,spring,spring-batch,Spring,Spring Batch,在过去的一两个小时里,我开始研究Spring批次。需要你的投入 问题:读取一个或多个包含2000万数据的csv文件,执行次要处理,将其存储在db中,并在最短时间内将输出写入另一个平面文件 最重要的:我需要做出选择,这些选择将在未来水平扩展 问题: 使用远程分块或分区来水平扩展 因为数据在平面文件中,所以远程分块和分区都是错误的选择 哪种多进程解决方案能够从一个大文件中读取数据,跨多个服务器进行处理,并更新数据库,但最终写入/输出到单个文件 multiresourcepartitioner是否跨服

在过去的一两个小时里,我开始研究Spring批次。需要你的投入

问题:读取一个或多个包含2000万数据的csv文件,执行次要处理,将其存储在db中,并在最短时间内将输出写入另一个平面文件

最重要的:我需要做出选择,这些选择将在未来水平扩展

问题:

使用远程分块或分区来水平扩展

因为数据在平面文件中,所以远程分块和分区都是错误的选择

哪种多进程解决方案能够从一个大文件中读取数据,跨多个服务器进行处理,并更新数据库,但最终写入/输出到单个文件

multiresourcepartitioner是否跨服务器工作

您知道在哪里完成/演示过类似的内容吗

您的想法是:1)在开始作业之前将大文件拆分为小文件2)使用项目读取器一次读取一个文件……。

假设“次要处理”不是处理过程中的瓶颈,扩展此类作业的最佳选择是通过分区。这项工作有两个步骤。第一种方法是将大文件拆分为较小的文件。为此,我建议使用
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分成了几个部分。如何将有关步骤计数的信息传递到下一步