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

时间:2014-07-29 17:43:03

标签: spring-batch

我在过去一两个小时内开始研究Spring Batch。并要求你输入。

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

最重要的:我需要做出将来会横向扩展的选择。

问题:

使用远程分块或分区水平缩放?

由于数据是平面文件,因此远程分块和分区都是错误的选择吗?

哪个多进程解决方案可以从大文件中读取,跨多个服务器传播处理并更新Db但最终写入/输出到单个文件?

multiresourcepartitioner是否跨服务器工作?

你知道任何类似的东西已经完成/演示的任何好的教程吗?

您对如何进行此操作的想法,例如1)在开始作业之前将大文件拆分为较小的文件2)使用项目阅读器一次读取一个文件...........

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;
        }