程序猿阵线联盟-汇总各类技术干货程序员大数据

[Spring Cloud Task]4 Spring Batc

2018-05-19  本文已影响0人  为为王

概述

本文是Spring Cloud Task系列的第四篇文章,如果你尚未使用过Spring Cloud Task,请 移步spring cloud task1 简介与示例

本文主要讲述的是Spring的另一个核心子项目 Spring Batch,一个轻量级的综合的批处理框架。框架主要为规范、简化企业级具有健壮性要求的重要日常任务。

Spring Batch为大批量数据处理提供很多可重用的核心组件,包括日志、追踪、事务管理、任务处理分析、任务重启、跳读以及资源管理器。另外它还提供了更为先进的技术服务与特性,如通过最优和分区技术来支持超大规模数据的高性能批处理。总之,无论是简单的,还是复杂的大数据量的处理任务,都可以利用该框架为信息处理提供可扩展的支持。

Spring Batch有以下特性:

详情

在企业级应用中许多关键任务都需要批处理操作,需求大致可以分为如下几类:

Spring Batch继承了Spring框架的设计理念,强调基于POJO的开发方式并且促进创建可维护、可测试的代码。在功能设计上它利用调度框架(如Quartz)工作,并非是一个调度框架。

Spring Batch提供了很多用于支持大批量数据处理的功能,例如失败后的重试、跳过记录、从最后一次失败的位置重新开始工作、定期批量的提交给事务型数据库、可重用的组件(如解析器、映射器、读取器、处理器、写入器和校验器)以及工作流定义。

使用场景

下面是几个典型的批处理程序的使用场景:

Spring Batch 能够自动完成上述基础批处理迭代,并将类似的事务抽象成一个集合视角来处理,故而其典型应用场景就是无人值守的批处理。

Spring Batch是一个完全开源的框架,它提供了稳定的企业级批处理任务的解决方案,尤其适用于以下业务场景。

技术目标

架构设计

Spring Batch在设计时充分考虑的不同类型的用户需求,重视框架的可扩展性。其设计上的分层架构如下图所示。

Spring Batch 分层架构

Spring Batch的分层架构将系统分为应用层,核心层和基础组组件层。

应用层包含所有批处理任务以及开发者使用Spring Batch编写的其它代码。

核心层提供运行与管理批处理任务的能力。主要有 JobLauncher,Job以及Step接口的实现类组成。

应用层和核心层都依赖于公共基础层。基础层由公共的输入reader、输出writer以及服务service。

通用批处理程序参考指南

在设计批处理应用时,我们应慎重思考以下几点。

批处理策略

为了更好的设计和实现批处理系统,基础批处理应用的的构建块和模式应该提供图表式的框架以及编程接口给设计和研发人员。在设计批处理任务时,首重抽象分解阶段,业务处理逻辑应该被分解为一连串的步骤,每一个步骤都是一个行为模块。具体的步骤设计可参考下面的标准行为模块。

然而受复杂业务逻辑的影响,很多应用无法简单的由上述标准行为模块组成。此时或许可以尝试将多个标准组件组合,以完成业务需求。除了上述标准模块外,框架还提供了如下模块。

根据不同的数据源,批处理应用可被分为以下三类:

  1. 数据库驱动型应用:数据依赖于由数据库存储的纪录行或值。
  2. 文件驱动型应用:纪录或值存储在文件中
  3. 消息驱动型应用:数据纪录由消息队列维护

批处理策略的选择

上述的批处理策略是批处理系统的基础。在选用具体的批处理策略时要充分考虑很多因素。首先要估算数据量的大小,其次是批处理系统要面临的并发,再者还需要考虑系统的可用性要求(业务方希望系统7*24小时可用)。

下面是几种典型的批处理模式(通常结合调度任务使用):

针对不同的模式,数据的提交和锁定的策略非常重要,且在设计完成整体架构之后,批处理模式很难能独立更改。锁策略可以选用数据库自带的锁,也可以自己自定义继承框架中的锁服务。锁服务可以根据数据库锁状态来判断是否给予数据库操作的权限。根据锁服务的状态,也可以避免自己继承实现的重试逻辑的无意义执行。

离线普通批处理

在数据不被线上客户修改访问,没有并发处理的需求,也没有其它批处理任务一同对这些数据进行更改时,当前任务处理完成后就可以简单的对结果进行提交。

诚然最简单的逻辑是最有效的。但是随着时间的发展和产品迭代,要处理的数据关系会愈加复杂,数据量也会变得越来越大。如果没有设计锁服务,此时批处理模型的数据单次提交逻辑就显得相形见绌。

实时并发批处理

实时并发批处理程序需要同时满足多个并发请求,且任务处理可能占用数秒时间,任务结束后还需要在同一事物中提交数据,故而并发批处理不应该锁定任何数据。整体锁定的数据越少,数据对于其它进程不可用的时间越少,整个系统就越健壮。

合理选择乐观锁或悲观锁来实现逻辑行级锁是减少物理锁定的好思路。下面分别对乐观锁和悲观锁进行介绍。

乐观锁: 适用于数据很少发生锁竞争的情况。在使用数据库时具体实现方案为在批处理程序需要用到的数据表的添加一个版本号或者时间戳字段。当应用读取数据一行数据时,同时也会读取到此列。且当应用处理完成要更新数据时,会将这个时间戳或版本作为WHERE子句的条件。如果数据库中该行当前的时间戳字段与WHERE条件一样,这条数据才会被更新。否则的话就意味着这条数据已经被其它应用修改过了,应用此时应该去尝试其它策略。

悲观锁: 适用于数据会发生很多竞争的情况,在检索时需要取得物理或者逻辑锁。使用数据库时可以借助数据库默认的行级锁来实现。当应用需要更新数据时,首先检索该行并将锁标识为已锁定。这时其它应用尝试检索相同数据时会发生逻辑失败。直到应用将数据更新完成,锁标志才会被释放,其它应用才能重新获取数据。使用悲观锁有两点情况需要注意:1.在锁的锁定和释放的时间范围内,应当保证数据的完整性。2. 应当对锁设置超时机制。

上述知识尤其适用于高并发程序。一般情况下,乐观锁适用于实时处理应用,而互斥锁在批处理应用中能够大展拳脚。无论具体使用哪种锁,其根本目的都是为了保证数据的安全。

不过这些锁只能对单条数据定位锁定。当需要对一组数据进行锁定时,你所面临的最大的挑战是死锁的发生。怎么避免呢?有了逻辑锁,或许可以再设计一个逻辑锁管理器,管理器应该是一致的、非死锁的且应该能理解你想保护的数据组。逻辑锁管理器常常有自己的一张自己的表,如此便能提供锁管理、竞争报告、超时机制以及其它用户关注的功能。

并行处理

并行批处理的意思是多个批处理应用或任务并行工作,从而减少整体处理时间。 如果多个应用间没有共享同一个文件、数据库表或者索引空间,多个应用并行处理,各自只关注自己的数据,其间没有数据冲突,也不会发生什么问题。当应用间有共享资源时,一般情况我们会通过自定义数据分片策略来决定每个应用应该去处理哪些数据。在这里引入另一个新思路,数据管理表。数据管理表是一个维护数据相互依赖性的管理模型,它记录者每行可共享资源以及正在被使用与否,如此批处理程序就能知道自己可以访问哪些共享资源。

解决了数据访问方面的问题,可以配合使用多线程来实现对数据的并行处理。大型机环境下CPU资源丰富,能够保证每个处理任务都能分配到足够的cpu时间片,并行作业处理技术也相对成熟。

再者,我们需要考虑并行处理资源的高可用和负载均衡问题。这些可能用到的技术有连接池、缓存等等。最后需要注意,超大的并行处理中数据管理表本身可能会成为资源瓶颈。

关于

示例源码

Spring Cloud Task learning 的 task-demo-with-datasource 子项目

后记

Spring Cloud Task是一个优秀的项目,但是我找遍网络,也难以找出系统的、准确的中文相关文档。本系列文章以保证对Spring Cloud Task相关概念和设计理解的正确性为标准,尽量采用通俗易懂的语言,希望能给各位带来一些便捷。

本文内容主要是对 Spring Cloud Task 1.2.2-RELEASE 官方文档的翻译,不过作者水平有限,有不尽然的地方敬请指出。本项目和文档中所用的内容仅供学习和研究之用,转载或引用时请指明出处。如果你对文档有疑问或问题,请在项目中给我留言或发email到
weiwei02@vip.qq.com 我的github:
https://github.com/weiwei02/ 我相信技术能够改变世界 。

链接

上一篇 下一篇

猜你喜欢

热点阅读