Spring Batch:作业存储库

时间:2015-12-17 14:21:46

标签: spring spring-batch

我使用Master / Slave范例阅读了很多关于如何启用单个作业的并行处理和分块的内容。考虑一个已经实现的Spring Batch解决方案,该解决方案旨在在独立服务器上运行。通过最少的重构,我希望能够实现水平扩展,并在生产操作中更具弹性。速度和效率不是目标。

http://www.mkyong.com/spring-batch/spring-batch-hello-world-example/

在以下示例中,使用了一个Job Repository,它连接到一个初始化Job Repository的数据库模式。作业启动请求被送到一个消息队列,一个服务器,一个Java进程正在通过Spring JMS监听。遇到这种情况时,它会执行一个新的Java进程,即Spring Batch作业。如果作业尚未根据作业存储库启动,则它将开始。如果工作失败了,它将会找到工作停止的地方。如果作业正在进行中,它将被忽略。

单点故障是作业启动的单一服务器和单一监听过程。我想通过水平扩展相同的服务器实例来增加弹性,所有这些服务器实例都在竞争谁可以在它首次出现在队列中时首先获取作业启动消息。该服务器实例现在将尝试运行该作业。

我认为JobRepository的所有实例都将共享相同的模式,因此他们都可以查询状态当前处于什么状态并决定他们将要做什么。我不确定这个架构或JobRepository实现是否意图被多个实例使用。

这种方法是否有可能导致数据库陷入僵局?对于我的应用程序,Spring Batch的分区功能不适用于其他限制。

2 个答案:

答案 0 :(得分:1)

我决定构建一个原型来测试Spring Batch Job Repository架构和SimpleJobRepository是否可以以负载均衡的方式使用,并且多个Spring Batch Java进程同时运行。我担心数据库中可能发生死锁情况,所有正在运行的作业进程都会被卡住。

我的测试

我开始使用mkyong Spring Batch HelloWorld示例并对其进行了一些更改,可以将其打包到可以从命令行执行的Jar中。我还删除了database.config文件中定义的初始化数据库步骤,并手动建立了具有正确模式元素的本地MySQL服务器。我将time的Job参数添加为millis的当前时间,以便每个作业实例都是唯一的。

接下来,我编写了一个单独的Java主类,它使用Apache Commons Exec框架创建了50个子进程,它们之间没有等待。这些进程中的每一个在其Processor对象中都有一个Thread.sleep 1秒钟,因此许多进程将同时启动,并且所有进程都同时尝试访问数据库。

结果

连续多次运行此测试后,我发现所有50个Spring批处理过程一致成功并正确更新了相同的数据库模式。我没有看到任何迹象表明如果在连接到同一数据库的多个服务器上运行多个Spring Batch作业进程,它们将在架构上相互干扰,我也没有看到任何迹象表明此时可能发生死锁。

所以听起来好像没有使用高级主/从和分区分区方法的Spring Batch作业的负载平衡是一个有效的用例。

如果有人想对我的测试发表评论或建议改进方法,我将不胜感激。

答案 1 :(得分:0)

这是摘录自 Spring Batch docs关于Spring Batch如何处理其存储库的数据库更新:

  

Spring Batch在处理数据库更新时采用乐观锁定策略。这意味着每次“触摸”(更新)记录时,版本列中的值将增加1。当存储库返回以保存该值时,如果版本号已更改,则会抛出OptimisticLockingFailureException,指示并发访问时出错。 此检查是必要的,因为即使不同的批处理作业可能在不同的计算机上运行,​​它们也都使用相同的数据库表。