常见问题

是否可以在多线程或多进程中执行作业?

有三种方法可以解决这个问题 - 但我们建议在分析此类需求时谨慎行事(这真的有必要吗?)。

  • 向 step 添加 TaskExecutor。用于配置 Steps 的 `StepBuilder` 提供了可以设置的 "taskExecutor" 属性。只要 step 本身是可重启的(实际上是幂等的),这种方法就有效。并行作业示例展示了它在实践中如何工作 - 这使用了一种“处理指示器”模式,在业务事务内部将输入记录标记为完成。

  • 使用 PartitionStep 将您的 step 执行明确地分配给多个 Step 实例。Spring Batch 对此主要策略 (PartitionHandler) 有一个本地多线程实现,这使得它成为 IO 密集型作业的绝佳选择。请记住,对于以这种方式执行的 step 中的有状态组件,使用 scope="step",以便为每个 step 执行创建单独的实例,并且线程之间没有交叉通信。

  • 使用 spring-batch-integration 模块中实现的远程分块 (Remote Chunking) 方法。这需要一些持久化的中间件(例如 JMS)来实现驱动 step 和远程工作线程之间的可靠通信。基本思想是在驱动进程上使用特殊的 ItemWriter,并在工作进程上(通过 ChunkProcessor)使用监听器模式。

如何使 item reader 线程安全?

您可以同步 read() 方法(例如,通过将其包装在一个执行同步的委托器中)。请记住,您会失去可重启性,因此最佳实践是将 step 标记为不可重启,并且为了安全(和高效),您还可以将读取器上的 saveState=false 设置为 false。

Spring Batch 关于使用灵活策略和默认实现的理念是什么?是否可以为此或彼属性添加公共 getter?

Spring Batch 为框架开发人员(与业务逻辑实现者相对)提供了许多扩展点。我们期望客户端创建自己的更具体的策略,这些策略可以插入进来控制诸如提交间隔 (CompletionPolicy)、处理异常的规则 (ExceptionHandler) 等等。

通常,我们试图劝阻用户不要扩展框架类。Java 语言在将类和接口标记为内部方面没有给我们太多灵活性。通常,您可以预期源代码树顶层包 org.springframework.batch.* 中的任何内容都是公共的,但不一定可以被子类化。不鼓励扩展我们大多数策略的具体实现,而倾向于组合或分支方法。如果您的代码只能使用 Spring Batch 的接口,那将为您提供最大的可移植性。

Spring Batch 与 Quartz 有何不同?它们是否可以在同一个解决方案中共存?

Spring Batch 和 Quartz 有不同的目标。Spring Batch 提供处理大量数据的功能,而 Quartz 提供调度任务的功能。因此,Quartz 可以补充 Spring Batch,但不是互斥的技术。常见的组合是使用 Quartz 作为 Spring Batch 作业的触发器,使用 Cron 表达式和 Spring Core 提供的便利 SchedulerFactoryBean

如何使用 Spring Batch 调度作业?

使用调度工具。有很多可用的工具。例如:Quartz, Control-M, Autosys。Quartz 不具备 Control-M 或 Autosys 的所有功能 - 它应该是一个轻量级的工具。如果您想要更轻量级的工具,可以直接使用操作系统(cron, at 等)。

简单的顺序依赖关系可以使用 Spring Batch 的 job-steps 模型和 Spring Batch 中的非顺序特性来实现。我们认为这很常见。事实上,这使得更容易纠正调度器的一种常见误用 - 配置数百个作业,其中许多不是独立的,而只依赖于另一个作业。

Spring Batch 如何通过并行处理或其他方式优化项目性能和可扩展性?

我们认为这是 JobStep 的作用之一。Step 的特定实现处理拆分业务逻辑并有效地在并行进程或处理器之间共享的问题(参见 PartitionStep)。有许多技术可以在这里发挥作用。其本质就是对分布式代理进行一组并发远程调用,这些代理可以处理一些业务处理。由于业务处理通常已经模块化了 - 例如,输入一个 item,处理它 - Spring Batch 可以通过多种方式策略性地分配。我们有过经验的一种实现是一组处理业务处理的远程 Web 服务。我们将输入的主键范围发送给许多远程调用中的每一个。相同的基本策略适用于任何 Spring Remoting 协议(纯 RMI, HttpInvoker, JMS, Hessian 等),只需修改执行层配置中的几行代码即可。

如何使用消息传递来扩展批处理架构?

现有项目有大量实践证据表明,批处理采用管道方法非常有益,可以提高弹性和高吞吐量。我们经常面临任务关键型应用,其中审计日志至关重要,并要求保证处理,但在负载下的性能有非常严格的限制,或者高吞吐量能带来竞争优势。

Matt Welsh 的工作表明,分阶段事件驱动架构 (Staged Event Driven Architecture, SEDA) 比更僵化的处理架构具有巨大的优势,并且面向消息的中间件(JMS, AQ, MQ, Tibco 等)为我们提供了开箱即用的强大弹性。在下游和上游阶段之间存在反馈的系统中尤其有益,因此可以调整消费者数量以应对需求量。那么这如何融入 Spring Batch 呢?spring-batch-integration 项目在 Spring Integration 中实现了这种模式,可用于扩展处理大量数据项的任何 step 的远程处理能力。特别参见“chunk”包以及其中的 ItemWriterChunkHandler 实现。