Spring Batch 介绍
Spring Batch 介绍
企业域中的许多应用程序需要批量处理才能执行 关键任务环境中的业务运营。这些业务运营包括:
-
以最高效的方式自动、复杂地处理大量信息 无需用户交互即可处理。这些作通常包括基于时间的事件 (例如月末计算、通知或通信)。
-
定期应用在非常大的环境中重复处理的复杂业务规则 数据集(例如,保险福利确定或费率调整)。
-
整合从内部和外部系统接收的信息,这些 通常需要以事务方式格式化、验证和处理为 记录系统。批处理用于处理每 企业日。
Spring Batch 是一个轻量级、全面的批处理框架,旨在实现 开发对企业日常运营至关重要的强大批处理应用程序 系统。Spring Batch 建立在 Spring Framework 的特性之上,人们 已经达到预期(生产力、基于 POJO 的开发方法以及一般易用性 使用),同时使开发人员可以轻松访问和利用更高级的企业 必要时提供服务。Spring Batch 不是一个调度框架。有很多好的 企业调度器(如 Quartz、Tivoli、Control-M 等)在 商业和开源空间。它旨在与 调度程序,而不是替换调度程序。
Spring Batch 提供了处理大量内容所必需的可重用函数 记录,包括日志记录/跟踪、事务管理、作业处理统计、 作业重启、跳过和资源管理。它还提供了更先进的技术 支持极高容量和高性能批处理作业的服务和功能 通过优化和分区技术。Spring Batch 可以在简单的 用例(例如将文件读入数据库或运行存储过程) 作为复杂的大容量用例(例如在数据库之间移动大量数据、 转换它,依此类推)。大批量批处理作业可以利用 高度可扩展的方式来处理大量信息。
背景
虽然开源软件项目和相关社区更加关注 关注基于 Web 和基于微服务的架构框架,已经出现了 明显缺乏对可重用架构框架的关注,以适应基于 Java 的批处理 处理需求,尽管仍然需要在企业 IT 中处理此类处理 环境。由于缺乏标准的、可重用的批处理架构,导致 在客户企业 IT 中开发的许多一次性内部解决方案激增 功能。
SpringSource(现为 Pivotal)和埃森哲合作改变了这一点。埃森哲的 在实现批处理架构方面具有实践的行业和技术经验, SpringSource 深厚的技术经验,以及 Spring 经过验证的编程模型 共同建立了自然而强大的合作伙伴关系,创造了高质量、与市场相关的合作伙伴关系 旨在填补企业 Java 中重要空白的软件。两家公司都与 许多客户通过开发基于 Spring 的批处理来解决类似的问题 架构解决方案。这提供了一些有用的额外细节和现实生活 有助于确保解决方案可以应用于实际问题的约束 由客户提出。
埃森哲将以前专有的批处理架构框架贡献给Spring Batch 项目,以及提交者资源以推动支持、增强、和现有的功能集。埃森哲的贡献基于数十年的使用过去几代构建批处理架构的经验平台:COBOL/大型机、C++/Unix,以及现在的 Java/任何地方。
埃森哲和 SpringSource 之间的合作旨在促进软件处理方法、框架和工具的标准化,可以企业用户在创建批处理应用程序时始终如一地利用。 公司 以及希望为其提供标准、经过验证的解决方案的政府机构企业 IT 环境可以从 Spring Batch 中受益。
使用场景
典型的批处理程序通常:
-
从数据库、文件或队列中读取大量记录。
-
以某种方式处理数据。
-
以修改后的形式写回数据。
Spring Batch 自动执行此基本批量迭代,提供处理类似的交易作为一组,通常在没有任何用户的离线环境中 互动。 批处理作业是大多数 IT 项目的一部分,而 Spring Batch 是唯一一个开放的提供强大的企业级解决方案的源码框架。
业务场景
-
定期提交批处理
-
并发批处理:作业的并行处理
-
分阶段的企业消息驱动处理
-
大规模并行批处理
-
故障后手动或计划重启
-
依赖步骤的顺序处理(具有对工作流驱动批处理的扩展)
-
部分处理:跳过记录(例如,回滚时)
-
整批交易,适用于批次大小较小或现有存储的案例过程/脚本
技术目标
-
批量开发人员使用 Spring 编程模型:专注于业务逻辑,并让框架负责基础设施。
-
明确分离基础架构、批处理执行环境和批处理应用程序之间的关注点。
-
提供通用的核心执行服务作为所有项目都可以实现的接口。
-
提供核心执行接口的简单和默认实现,这些接口可以是 “开箱即用”。
-
通过利用 spring 框架轻松配置、自定义和扩展服务在所有层中。
-
所有现有的核心服务都应易于替换或扩展,而不会影响基础设施层。
-
提供一个简单的部署模型,其架构 JAR 与应用程序完全分开,使用 Maven 构建。
Spring Batch 架构
Spring Batch 在设计时考虑了可扩展性和多样化的最终用户群体。 这 下图显示了支持可扩展性和易用性的分层架构供最终用户开发人员使用。

这种分层架构突出了三个主要的高级组件:应用程序、核心和基础设施。该应用程序包含所有批处理作业和编写的自定义代码由开发人员使用 Spring Batch。Batch Core 包含核心运行时类启动和控制批处理作业所必需的。它包括实现JobLauncher
,Job
和Step
. 应用程序和核心都建立在一个共同的 基础设施。 此基础架构包含常见的读取器和写入器以及服务(例如RetryTemplate
),它们都由应用程序开发人员(读取器和写入器,例如ItemReader
和ItemWriter
)和核心框架本身(重试,这是它自己的库)。
一般批次原则和指南
应考虑以下关键原则、指南和一般注意事项 构建批处理解决方案时。
-
请记住,批处理架构通常会影响在线架构和副 反之亦然。使用通用架构在设计时同时考虑架构和环境 尽可能阻止。
-
尽可能简化,避免在单个中构建复杂的逻辑结构 批量应用。
-
保持数据的处理和存储在物理上接近(换句话说,保持 您的数据)。
-
尽量减少系统资源的使用,尤其是 I/O。在内存中执行尽可能多的作。
-
审查应用程序 I/O(分析 SQL 语句)以确保避免不必要的物理 I/O被避免。特别是需要寻找以下四个常见缺陷:
-
读取每笔交易的数据,当数据可以读取一次并缓存或保留时在工作存储中。
-
重新读取先前在同一 交易。
-
导致不必要的表或索引扫描。
-
未在 SQL 语句的 WHERE 子句中指定键值。
-
-
不要在批量运行中执行两次作。例如,如果您需要数据汇总报告目的,您应该(如果可能)在数据初始处理时递增存储的总计,因此您的报告应用程序不必重新处理相同的 数据。
-
在批处理应用程序开始时分配足够的内存,以避免耗时的在此过程中重新分配。
-
在数据完整性方面始终假设最坏的情况。插入足够的支票和 记录验证以保持数据完整性。
-
尽可能实施校验和以进行内部验证。例如,平面文件 应该有一个尾部记录,说明文件中的记录总数和 关键字段。
-
在类似生产的环境中尽早计划和执行压力测试 具有真实的数据量。
-
在大批量系统中,备份可能具有挑战性,尤其是在系统正在运行的情况下 与 24-7 在线并发。数据库备份通常得到很好的处理 的,但文件备份应该被视为同样重要。 如果系统依赖于平面文件,则不仅应制定文件备份过程 并记录在案,但也要定期测试。
批处理策略
帮助设计和实现批处理系统、基本批处理应用程序构建块和 模式应以样本的形式提供给设计人员和程序员 结构图和代码 shell。开始设计批处理作业时,业务逻辑 应分解为一系列步骤,这些步骤可以使用以下步骤实现 标准构建块:
-
转换应用:对于由 外部系统,必须创建转换应用程序才能转换交易 以处理所需的标准格式提供的记录。此类批次 应用程序可以部分或全部由翻译实用程序模块组成(参见基本 批处理服务)。
-
验证应用:验证应用程序确保所有输入/输出 记录正确且一致。验证通常基于文件头和 预告片、校验和和验证算法,以及记录级别交叉检查。
-
提取应用:从数据库或数据库中读取一组记录的应用程序 输入文件,根据预定义的规则选择记录,并将记录写入 输出文件。
-
提取/更新应用程序:从数据库读取记录的应用程序或 输入文件,并对数据库或由找到的数据驱动的输出文件进行更改 在每个输入记录中。
-
处理和更新应用程序:执行处理的应用程序来自提取或验证应用程序的输入事务。处理通常涉及读取数据库以获取处理所需的数据,可能更新数据库并创建用于输出处理的记录。
-
输出/格式化应用程序:读取输入文件、重组数据的应用程序根据标准格式从该记录中获取,并生成用于打印的输出文件或传输到另一个程序或系统。
此外,应为无法使用前面提到的构建块构建的业务逻辑提供基本的应用程序 shell。
除了主要构建块之外,每个应用程序还可以使用一个或多个标准实用程序步骤,例如:
-
排序:读取输入文件并生成输出文件的程序,其中记录已根据记录中的排序键字段重新排序。排序通常是由标准系统实用程序执行。
-
拆分:读取单个输入文件并将每条记录写入其中一条的程序基于字段值的多个输出文件。拆分可以通过以下方式进行定制或执行参数驱动的标准系统实用程序。
-
合并:从多个输入文件中读取记录并生成一个输出的程序文件包含来自输入文件的组合数据。合并可以通过以下方式进行定制或执行参数驱动的标准系统实用程序。
批处理应用程序还可以按其输入源进行分类:
-
数据库驱动的应用程序由从数据库检索到的行或值驱动。
-
文件驱动的应用程序由从文件中检索到的记录或值驱动。
-
消息驱动的应用程序由从消息队列检索到的消息驱动。
任何批处理系统的基础都是处理策略。影响策略的选择包括:估计的批处理系统数量、与在线系统或其他批处理系统的并发性、可用的批次窗口。(请注意,随着更多企业希望 24x7 全天候运行,清晰的批次窗口正在消失)。
批处理的典型处理选项是(按实现的升序排列 复杂性):
-
在脱机模式下的批处理窗口期间进行正常处理。
-
并发批处理或在线处理。
-
同时并行处理许多不同的批处理或作业。
-
分区(同时处理同一作业的多个实例)。
-
上述选项的组合。
商业调度程序可能支持其中一些或全部选项。
以下部分将更详细地讨论这些处理选项。这很重要 请注意,根据经验,批处理采用的提交和锁定策略 进程取决于执行的处理类型以及在线锁定 战略也应该使用相同的原则。因此,批处理架构不能 在设计整体架构时只是事后才想到的。
锁定策略可以是仅使用普通数据库锁或实现 体系结构中的其他自定义锁定服务。锁定服务将跟踪 数据库锁定(例如,通过将必要的信息存储在专用的 db-table)并授予或拒绝向请求数据库的应用程序授予或拒绝权限 操作。此体系结构也可以实现重试逻辑,以避免中止 批处理作业,以防发生锁定情况。
1. 批处理窗口中的正常处理对于在单独的 在线用户或其他批次不需要更新数据的批处理窗口 进程,并发不是问题,可以在 批量运行。
在大多数情况下,更稳健的方法更合适。请记住,该批次 随着时间的推移,系统有增长的趋势,无论是在复杂性还是数据方面 他们处理的体积。如果没有锁定策略,并且系统仍然依赖于 单个提交点,修改批处理程序可能会很痛苦。因此,即使使用 最简单的批处理系统,考虑重新启动-恢复的提交逻辑需求 选项以及有关后面描述的更复杂情况的信息 本节。
2. 并发批处理或在线处理 批处理应用程序处理可以 在线用户同时更新时,不应锁定任何数据(无论是在 数据库或文件中),在线用户可能需要多个 秒。此外,更新应在每隔几次结束时提交到数据库 交易。这最大限度地减少了其他进程不可用的数据部分 以及数据不可用的经过时间。
最小化物理锁定的另一个选项是具有逻辑行级锁定 使用乐观锁定模式或悲观锁定模式实现。
-
乐观锁定假定记录争用的可能性较低。它通常意味着 在 batch 和 在线处理。当应用程序获取一行进行处理时,它还会获取 时间戳。当应用程序随后尝试更新已处理的行时,更新会使用 原始时间戳。如果时间戳匹配,则数据和 timestamp 更新。如果时间戳不匹配,则表示另一个 应用程序在获取和更新尝试之间更新了同一行。因此 无法执行更新。
-
悲观锁定是假设存在很高可能性的任何锁定策略 记录争用,因此需要在 检索时间。一种悲观逻辑锁定使用专用的锁列 数据库表。当应用程序检索要更新的行时,它会在 锁列。使用该标志后,其他应用程序尝试检索 同一行在逻辑上失败。当设置标志的应用程序更新行时,它还 清除该标志,使其他应用程序能够检索该行。请注意 在初始获取和设置之间也必须保持数据的完整性 ,例如通过使用 db 锁(例如
SELECT FOR UPDATE
).另请注意, 这种方法与物理锁定具有相同的缺点,只是它在某种程度上 更易于管理,构建超时机制,如果用户 在记录锁定时去吃午饭。
这些模式不一定适合批处理,但可以使用它们 用于并发批处理和在线处理(例如,在数据库没有的情况下 支持行级锁定)。一般来说,乐观锁定更适合 在线应用,而悲观锁定更适合批量应用。 每当使用逻辑锁定时,必须对所有应用程序使用相同的方案 访问受逻辑锁保护的数据实体。
请注意,这两种解决方案都只解决锁定单个记录的问题。通常,我们可能需要锁定一组逻辑相关的记录。使用物理锁,您必须非常仔细地管理这些,以避免潜在的死锁。使用逻辑锁,它通常最好构建一个理解逻辑记录的逻辑锁管理器您想要保护的组,并且可以确保锁是连贯的并且非死锁。这个逻辑锁管理器通常使用自己的表来锁定管理、争用报告、超时机制和其他问题。
3. 并行处理并行处理允许多个批处理运行或作业在并行以最大限度地减少总已用的批处理时间。这不是问题,因为只要作业不共享相同的文件、数据库表或索引空间。如果这样做,该服务应使用分区数据来实现。另一种选择是构建一个架构模块,用于使用控制表来维护相互依赖关系。一个控件表应包含每个共享资源的一行,以及它是否被应用程序使用。批处理架构或并行作业中的应用程序将然后从该表中检索信息以确定它是否可以访问它需要的资源。
如果数据访问不是问题,可以通过使用额外的线程并行处理。在大型机环境中,并行传统上一直使用作业类,以确保所有进程。无论如何,解决方案必须足够稳健,以确保时间片所有正在运行的进程。
并行处理中的其他关键问题包括负载平衡和一般系统资源(如文件、数据库缓冲池等)的可用性。另请注意控制表本身很容易成为关键资源。
4. 分区使用分区允许多个版本的大型批处理应用程序并发运行。这样做的目的是减少所需的时间处理长批处理作业。可以成功分区的进程是那些可以拆分输入文件和/或对主数据库表进行分区,以允许应用程序针对不同的数据集运行。
此外,分区的进程必须设计为仅处理其分配的数据集。分区架构必须与数据库紧密相关设计和数据库分区策略。请注意,数据库分区并不必然意味着数据库的物理分区,尽管在大多数情况下这是 明智。 下图说明了分区方法:

架构应足够灵活,以允许动态配置号码 的分区。应考虑自动和用户控制的配置。 自动配置可能基于输入文件大小和 输入记录数。
4.1 分区方法选择分区方法必须在具体情况的基础上完成。以下列表描述了一些可能的分区 方法:
1. 固定甚至打破记录集
这涉及将输入记录集分解为偶数个部分(例如,10,其中每个部分恰好具有整个记录集的 1/10)。然后每个部分被由批处理/提取应用程序的一个实例处理。
为了使用这种方法,需要进行预处理来拆分记录设置。 这 此拆分的结果将是一个下限和上限放置编号,可用于作为批处理/提取应用程序的输入,以将其处理限制为仅其 部分。
预处理可能是一个很大的开销,因为它必须计算和确定边界记录集的每个部分。
2. 按关键列分解
这涉及分解按键列(例如位置代码、以及将每个键中的数据分配给批处理实例。为了实现这一点,列值可以是:
-
由分区表分配给批处理实例(在本部分后面描述)。
-
按部分值分配给批处理实例(例如 0000-0999、1000 - 1999、等)。
在选项 1 下,添加新值意味着手动重新配置批处理/提取以确保将新值添加到特定实例。
在选项 2 下,这可确保通过批处理的实例覆盖所有值 工作。 但是,一个实例处理的值数量取决于列值的分布(0000-0999 中可能有大量位置范围,1000-1999 范围内很少)。在此选项下,数据范围应为设计时考虑到了分区。
在这两个选项下,记录到批处理实例的最佳均匀分布不能 实现。使用的批处理实例数没有动态配置。
3. 按视图细分
这种方法基本上是按键列分解的,但在数据库级别。它涉及 将记录集分解为视图。批处理的每个实例都使用这些视图 在其处理过程中的应用。分解是通过对数据进行分组来完成的。
使用此选项,批处理应用程序的每个实例都必须配置为命中 特定视图(而不是主表)。此外,随着新数据的添加 值时,必须将这组新数据包含在视图中。没有动态 配置功能,因为实例数的更改会导致 观点。
4. 添加加工指标
这涉及向输入表添加一个新列,该列充当 指示器。作为预处理步骤,所有指标都标记为未处理。 在批处理应用程序的记录获取阶段,将根据条件读取记录 该记录被标记为未处理,一旦读取它们(带锁), 它们被标记为正在处理中。完成该记录后,指示器为 更新为完成或错误。可以启动批处理应用程序的许多实例 无需更改,因为附加列可确保记录仅处理一次。
使用此选项,表上的 I/O 会动态增加。在更新的情况下 批量应用程序,这种影响会减少,因为无论如何都必须进行写入。
5. 将表格提取到平面文件
这涉及将表提取到文件中。然后可以将此文件拆分为 多个段,并用作批处理实例的输入。
使用此选项,将表提取到文件中的额外开销和 拆分它可能会抵消多分区的影响。动态配置可以 通过更改文件拆分脚本来实现。
6. 哈希列的使用
该方案涉及向数据库表添加哈希列(键/索引) 用于检索驱动程序记录。此哈希列有一个指示器,用于确定哪个 批处理应用程序的实例处理此特定行。例如,如果有 是要启动的三个批处理实例,则指示器“A”标记一行 由实例 1 处理时,指示器“B”标记要由实例 2 处理的行, 指示器“C”标记要由实例 3 处理的行。
然后,用于检索记录的过程将具有额外的WHERE
第
以选择由特定指示器标记的所有行。此表中的插入将
涉及添加标记字段,该字段将默认为
实例(例如“A”)。
将使用一个简单的批处理应用程序来更新指标,例如 在不同实例之间重新分配负载。当一个足够大的数字 ,则可以运行此批处理(任何时间,批处理窗口除外) 将新行重新分发到其他实例。
批处理应用程序的其他实例只需要运行批处理 如前几款所述,将指标重新分配给 使用新数量的实例。
4.2 数据库和应用程序设计原则
支持针对 使用键列方法的分区数据库表应包括一个中央 用于存储分区参数的分区存储库。这提供了灵活性和 确保可维护性。存储库通常由单个表组成,称为 分区表。
存储在分区表中的信息是静态的,通常应维护 由 DBA 提供。该表应包含 多分区应用程序。该表应包含“程序 ID 代码”列, 分区号(分区的逻辑 ID),此 db 键列的低值 partition 和此分区的 db 键列的高值。
程序启动时,程序id
和分区号应传递给应用程序(特别是来自控制处理任务)。 如果 使用键列方法,这些变量用于读取中的分区表,以确定应用程序要处理的数据范围。此外,分区号必须在整个处理过程中使用:
-
添加到输出文件/数据库更新,以便合并过程正常工作 适当地。
-
将正常处理报告到批处理日志,并将任何错误报告到体系结构错误 处理器。
4.3 最小化死锁
当应用程序并行运行或分区时,数据库资源中的争用和死锁可能会发生。数据库设计团队必须尽可能消除潜在的争用情况,作为数据库设计的一部分。
此外,开发人员必须确保数据库索引表在设计时考虑到死锁预防和性能。
死锁或热点经常出现在管理或架构表中,例如日志表、控制表和锁定表。应考虑这些的影响也考虑在内。现实的压力测试对于识别可能的情况至关重要架构中的瓶颈。
为了尽量减少冲突对数据的影响,架构应提供服务例如,在附加到数据库或遇到 僵局。 这意味着一种内置机制来对某些数据库返回代码做出反应,并且,而不是立即发出错误,而是等待预定的时间,然后重试数据库作。
4.4 参数传递和验证
分区架构对应用程序开发人员来说应该相对透明。该架构应执行与在分区模式下运行应用程序相关的所有任务,包括:
-
在应用程序启动之前检索分区参数。
-
在应用程序启动之前验证分区参数。
-
在启动时将参数传递给应用程序。
验证应包括检查以确保:
-
该应用程序有足够的分区来覆盖整个数据范围。
-
分区之间没有间隙。
如果数据库已分区,那么可能需要进行一些额外的验证来确保单个分区不跨越数据库分区。
此外,体系结构还应考虑分区的合并。关键问题包括:
-
在进入下一个作业步骤之前,必须完成所有分区?
-
如果其中一个分区中止会发生什么?