spring-batch day1 概念篇

spring-batch day1 概念篇

本篇文章转载自topEngineerray大佬的博客

1.spring-batch是什么?

  spring-batch是一个轻量级的,完全面向Spring的批处理框架,可以应用于企业级大量的数据处理系统。spring-batch以POJO和大家熟知的Spring框架为基础,使开发者更容易的访问和利用企业级服务。spring-batch可以提供大量的,可重复的数据处理功能,包括日志记录/跟踪,事务管理,作业处理统计工作重新启动、跳过,和资源管理等重要功能,但是spring-batch本身不提供定时任务功能,需要与其他定时任务框架配合使用。

2.spring-batch架构介绍:

一个典型的批处理应用程序大致如下:

  • 从数据库,文件或队列中读取大量记录。
  • 以某种方式处理数据。
  • 以修改之后的形式写回数据。

    图1-1:
    在这里插入图片描述

  在spring batch中一个job可以定义很多的步骤step,在每一个step里面可以定义其专属的ItemReader用于读取数据,ItemProcesseor用于处理数据,ItemWriter用于写数据,而每一个定义的job则都在JobRepository里面,我们可以通过JobLauncher来启动某一个job。

3.spring-batch核心概念介绍:

什么是Job:

  Job是一个封装整个批处理过程的一个概念。Job在spring batch的体系当中只是一个最顶层的一个抽象概念,体现在代码当中则它只是一个最上层的接口

  在Job这个接口当中定义了五个方法,它的实现类主要有两种类型的job,一个是simplejob,另一个是flowjob。在spring batch当中,job是最顶层的抽象,除job之外我们还有JobInstance以及JobExecution这两个更加底层的抽象。

  一个job是我们运行的基本单位,它内部由step组成。job本质上可以看成step的一个容器。一个job可以按照指定的逻辑顺序组合step,并提供了我们给所有step设置相同属性的方法,例如一些事件监听,跳过策略。

源码:

 
/**
 * Batch domain object representing a job. Job is an explicit abstraction
 * representing the configuration of a job specified by a developer. It should
 * be noted that restart policy is applied to the job as a whole and not to a
 * step.
 */
public interface Job {
 
	String getName();
 
 
	boolean isRestartable();
 
 
	void execute(JobExecution execution);
 
 
	JobParametersIncrementer getJobParametersIncrementer();
 
 
	JobParametersValidator getJobParametersValidator();
 
}

  JobInstance:JobInstance是Job的更加底层的一个抽象他的方法很简单,一个是返回Job的id,另一个是返回Job的名字。JobInstance指的是job运行当中,作业执行过程当中的概念。Instance本就是实例的意思。比如说现在有一个批处理的job,它的功能是在一天结束时执行行一次。我们假定这个批处理job的名字为’EndOfDay’。在这个情况下,那么每天就会有一个逻辑意义上的JobInstance, 而我们必须记录job的每次运行的情况。

源码:

public interface JobInstance {
	/**
	 * Get unique id for this JobInstance.
	 * @return instance id
	 */
	public long getInstanceId();
	/**
	 * Get job name.
	 * @return value of 'id' attribute from <job>
	 */
	public String getJobName();	
}

  spring batch中提供的用来标识一个jobinstance的东西是:JobParameters。 JobParameters对象包含一组用于启动批处理作业的参数,它可以在运行期间用于识别或甚至用作参考数据。我们假设的运行时间,就可以作为一个JobParameters。

图1-2 JobInstance和JobParameter的关系:
在这里插入图片描述


JobExecution:JobExecution指的是单次尝试运行一个我们定义好的Job的代码层面的概念。job的一次执行可能以失败也可能成功。只有当执行成功完成时,给定的与执行相对应的JobInstance才也被视为完成。 源码:
public interface JobExecution {
	/**
	 * Get unique id for this JobExecution.
	 * @return execution id
	 */
	public long getExecutionId();
	/**
	 * Get job name.
	 * @return value of 'id' attribute from <job>
	 */
	public String getJobName(); 
	/**
	 * Get batch status of this execution.
	 * @return batch status value.
	 */
	public BatchStatus getBatchStatus();
	/**
	 * Get time execution entered STARTED status. 
	 * @return date (time)
	 */
	public Date getStartTime();
	/**
	 * Get time execution entered end status: COMPLETED, STOPPED, FAILED 
	 * @return date (time)
	 */
	public Date getEndTime();
	/**
	 * Get execution exit status.
	 * @return exit status.
	 */
	public String getExitStatus();
	/**
	 * Get time execution was created.
	 * @return date (time)
	 */
	public Date getCreateTime();
	/**
	 * Get time execution was last updated updated.
	 * @return date (time)
	 */
	public Date getLastUpdatedTime();
	/**
	 * Get job parameters for this execution.
	 * @return job parameters  
	 */
	public Properties getJobParameters();	
}

JobExecution当中提供了一个方法getBatchStatus用于获取一个job某一次特地执行的一个状态。BatchStatus是一个代表job状态的枚举类,其定义如下:

public enum BatchStatus {STARTING, STARTED,STOPPING, STOPPED, FAILED, COMPLETED, ABANDONED }

什么是step:

  每一个Step对象都封装了批处理作业的一个独立的阶段。 事实上,每一个Job本质上都是由一个或多个步骤组成。 每一个step包含定义和控制实际批处理所需的所有信息。 任何特定的内容都由编写Job的开发人员自行决定。 一个step可以非常简单也可以非常复杂。 例如,一个step的功能是将文件中的数据加载到数据库中,那么基于现在spring batch的支持则几乎不需要写代码。 更复杂的step可能具有复杂的业务逻辑,这些逻辑作为处理的一部分。 与Job一样,Step具有与JobExecution类似的StepExecution
图1-3:
在这里插入图片描述

  StepExecution:StepExecution表示一次执行Step, 每次运行一个Step时都会创建一个新的StepExecution,类似于JobExecution。 但是,某个步骤可能由于其之前的步骤失败而无法执行。 且仅当Step实际启动时才会创建StepExecution。一次step执行的实例由StepExecution类的对象表示。 每个StepExecution都包含对其相应步骤的引用以及JobExecution和事务相关的数据,例如提交和回滚计数以及开始和结束时间。 此外,每个步骤执行都包含一个ExecutionContext,其中包含开发人员需要在批处理运行中保留的任何数据,例如重新启动所需的统计信息或状态信息。

   ExecutionContext即每一个StepExecution 的执行环境。它包含一系列的键值对。我们可以用如下代码获取ExecutionContext

  JobRepository是一个用于将上述job,step等概念进行持久化的一个类。 它同时给Job和Step以及下文会提到的JobLauncher实现提供CRUD操作。 首次启动Job时,将从repository中获取JobExecution,并且在执行批处理的过程中,StepExecution和JobExecution将被存储到repository当中。@EnableBatchProcessing注解可以为JobRepository提供自动配置。

  JobLauncher:JobLauncher这个接口的功能非常简单,它是用于启动指定了JobParameters的Job,jobparameter和job一起才能组成一次job的执行

什么是ItemReader

  ItemReader是一个读数据的抽象,它的功能是为每一个Step提供数据输入。 当ItemReader以及读完所有数据时,它会返回null来告诉后续操作数据已经读完。Spring Batch为ItemReader提供了非常多的有用的实现类,比如JdbcPagingItemReader,JdbcCursorItemReader等等。ItemReader支持的读入的数据源也是非常丰富的,包括各种类型的数据库,文件,数据流,等等。几乎涵盖了我们的所有场景。

什么是ItemWriter

  既然ItemReader是读数据的一个抽象,那么ItemWriter自然就是一个写数据的抽象,它是为每一个step提供数据写出的功能。写的单位是可以配置的,我们可以一次写一条数据,也可以一次写一个chunk的数据,关于chunk下文会有专门的介绍。ItemWriter对于读入的数据是不能做任何操作的。

什么是ItemProcessor

  ItemProcessor对项目的业务逻辑处理的一个抽象, 当ItemReader读取到一条记录之后,ItemWriter还未写入这条记录之前,I我们可以借助temProcessor提供一个处理业务逻辑的功能,并对数据进行相应操作。如果我们在ItemProcessor发现一条数据不应该被写入,可以通过返回null来表示。ItemProcessor和ItemReader以及ItemWriter可以非常好的结合在一起工作,他们之间的数据传输也非常方便。我们直接使用即可。

chunk 处理流程

  它的意思就和图示的一样,由于我们一次batch的任务可能会有很多的数据读写操作,因此一条一条的处理并向数据库提交的话效率不会很高,因此spring batch提供了chunk这个概念,我们可以设定一个chunk size,spring batch 将一条一条处理数据,但不提交到数据库,只有当处理的数据数量达到chunk size设定的值得时候,才一起去commit.

流程图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tcOpvjOl-1638410039365)(spring-batch-day1/chunk示意图.png)]

skip策略和失败处理

  一个batch的job的step,可能会处理非常大数量的数据,难免会遇到出错的情况,出错的情况虽出现的概率较小,但是我们不得不考虑这些情况,因为我们做数据迁移最重要的是要保证数据的最终一致性。

  我们需要留意这三个方法,分别是skipLimit(),skip(),noSkip(),

  skipLimit方法的意思是我们可以设定一个我们允许的这个step可以跳过的异常数量,假如我们设定为10,则当这个step运行时,只要出现的异常数目不超过10,整个step都不会fail。注意,若不设定skipLimit,则其默认值是0.

  skip方法我们可以指定我们可以跳过的异常,因为有些异常的出现,我们是可以忽略的。

  noSkip方法的意思则是指出现这个异常我们不想跳过,也就是从skip的所以exception当中排除这个exception,从上面的例子来说,也就是跳过所有除FileNotFoundException的exception。那么对于这个step来说,FileNotFoundException就是一个fatal的exception,抛出这个exception的时候step就会直接fail

一些注意事项:

默认启动时不执行批处理

  在使用java config使用spring batch的job时,如果不做任何配置,项目在启动时就会默认去跑我们定义好的批处理job。那么如何让项目在启动时不自动去跑job呢?

  spring batch的job会在项目启动时自动run,如果我们不想让他在启动时run的话,可以在application.properties中添加如下属性:

读数据时内存不够

  batch job的reader是一次性拿回了数据库里的所有数据,并没有进行分页,当这个数据量太大时,就会导致内存不够用。解决的办法有两个:

  
调整reader读数据逻辑,按分页读取,但实现上会麻烦一些,且运行效率会下降

  增大service内存

批处理操作指南

  • 批处理体系结构通常会影响体系结构
  • 尽可能简化并避免在单批应用程序中构建复杂的逻辑结构
  • 保持数据的处理和存储在物理上靠得很近(换句话说,将数据保存在处理过程中)
  • 最大限度地减少系统资源的使用,尤其是I / O. 在internal memory中执行尽可能多的操作
  • 查看应用程序I / O(分析SQL语句)以确保避免不必要的物理I / O. 特别是,需要寻找以下四个常见缺陷:
    1. 当数据可以被读取一次并缓存或保存在工作存储中时,读取每个事务的数据。
    2. 重新读取先前在同一事务中读取数据的事务的数据。
    3. 导致不必要的表或索引扫描。
    4. 未在SQL语句的WHERE子句中指定键值。
  • 在批处理运行中不要做两次一样的事情。 例如,如果需要数据汇总以用于报告目的,则应该(如果可能)在最初处理数据时递增存储的总计,因此您的报告应用程序不必重新处理相同的数据。
  • 在批处理应用程序开始时分配足够的内存,以避免在此过程中进行耗时的重新分配。
  • 总是假设数据完整性最差。 插入适当的检查和记录验证以维护数据完整性。
  • 尽可能实施校验和以进行内部验证。 例如,对于一个文件里的数据应该有一个数据条数纪录,告诉文件中的记录总数以及关键字段的汇总。
  • 在具有真实数据量的类似生产环境中尽早计划和执行压力测试。
  • 在大批量系统中,数据备份可能具有挑战性,特别是如果系统以24-7在线的情况运行。 数据库备份通常在在线设计中得到很好的处理,但文件备份应该被视为同样重要。 如果系统依赖于文件,则文件备份过程不仅应该到位并记录在案,还应定期进行测试。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值