在 Spring Batch 中以最后处理的记录作为 jobParameter 启动一个新的作业实例?

Posted

技术标签:

【中文标题】在 Spring Batch 中以最后处理的记录作为 jobParameter 启动一个新的作业实例?【英文标题】:Starting a new job instance with last processed record as jobParameter in Spring Batch? 【发布时间】:2021-06-15 20:00:28 【问题描述】:

我们正在处理 Spring Batch 作业。该作业每天将运行约 6 个小时,并将从 REST 服务中获取与每条记录相对应的一些值。从 REST 服务检索到值后,它会针对相应的记录进行更新。例如

--------------------
   Student
--------------------
Id | Name | Marks
--------------------
1  | John | Null
2  | Sam  | Null
3  | Lilly| Null

遍历每条记录(ASC 订单)并根据Id 从 REST 服务获取标记。使用检索到的标记更新列标记。 REST 服务不支持批量操作,一次只能处理一条记录。

建议的解决方案:

    使用RepositoryItemReader 以ASC 顺序使用固定页面大小从db 读取数据。由于默认情况下没有 ID 范围,因此作业将永远继续运行(每天约 6 小时后停止)。 调用 REST 服务以根据每条记录获取标记 Id 并使用标记更新学生对象。 (CustomItemProcessor) 使用RepositoryItemWriter更新学生对象。

需要解决的问题:

有2个问题:

1.需要知道最后处理的记录才能从那里恢复(我们希望 每天创建一个新的工作实例)。 为了每天运行作业,我们可以对作业进行基准测试并估计 每天将处理的记录数。基于此,我们可以定义 Id 静态表中的范围,以便作业从表中读取范围和 处理范围内的记录。这个解决方案不是很优雅。 另一种方法是将最后获取的(未读取)存储在跟踪中 表并将其用作第二天的下限。我不确定我该怎么做 优雅地实现这一目标。

2.提高工作绩效 在单线程顺序模式下,性能不是很好。这只是 能够处理 1 条记录/2 秒(0.5 条记录/秒)。我用了一个 ThreadPoolTask​​Executor 的线程池大小约为 10,并且能够 达到 4 条记录/秒的性能(这对我们来说非常理想)。

【问题讨论】:

为什么不把最后处理的写入数据库,然后选择它作为参数传递呢? 是的,我也是这么想的,但是我应该什么时候写最后处理的记录呢? @后工作?是否可以从作业执行上下文中获取此信息?正如我提到的,因为它是多线程的,最后处理的记录不一定是读取记录中的最大 id。 【参考方案1】:

由于我们也在使用 ThreadPoolTask​​Executor,所以要知道最后处理的记录并不简单。

排序与多线程不兼容。如果你并行,“First”和“Last”是未定义的。您需要找到一种与串行或并行执行无关的方式来标记记录。我强烈建议在引入多线程之前先找到问题的正确解决方案:正确性比性能更重要。

我们希望每天运行一个新的 Job 实例。

这意味着当前日期是识别工作参数的良好候选者。

【讨论】:

我明白了。这是否意味着在这种情况下无法使用任何类型的并行性?我知道一旦您拆分块可能无法做到这一点,但是在您阅读页面时可以做到吗?我们正在考虑使用 RepositoryItemReader 并读取具有特定页面大小的输入。如果我们可以在阅读时从页面中获取最大 id,我们可以将其存储在自定义表中。 Does it mean there is no way to use any sort of parallelism in this case?:您没有分享任何正确的单线程解决方案,以便能够告诉您是否有办法并行化它。我在您的描述中所期望的是:“这是一个适用于我的问题的解决方案,但速度很慢,我想提高它的性能。怎么做?” .这就是我在回答中提到的正确性。 我建议先描述手头的问题,不要参考 Spring Batch。您的第 3 步是否修改了输入记录?有专栏可以追踪吗?一个记录完整流程的具体示例会有所帮助。 我添加了更多细节。我希望我现在能够解释我的问题。 感谢您的更新。对于问题 1:Need to know the last processed record to resume from there (we would like to create a new job instance everyday):这是为什么呢?在您的输入中,我看不到任何东西每天都在变化。您需要设计每个作业实例来处理固定数据集(通过识别作业参数来表示)。从您的描述中不清楚并更新了代表作业实例的内容。对于问题 2,多线程步骤或分区步骤都是不错的选择,只要首先正确解决问题 1。

以上是关于在 Spring Batch 中以最后处理的记录作为 jobParameter 启动一个新的作业实例?的主要内容,如果未能解决你的问题,请参考以下文章

Spring Batch:ItemProcessor 不处理所有记录

Spring Batch 处理记录,但不将它们插入数据库

Spring Batch - 循环读取器、处理器和写入器 N 次

在 Spring Batch 中动态设置 gridSize(线程数)

Spring Batch SkipPolicy在处理异常时陷入无限循环

Spring batch 入门基础