在 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 条记录/秒)。我用了一个 ThreadPoolTaskExecutor 的线程池大小约为 10,并且能够 达到 4 条记录/秒的性能(这对我们来说非常理想)。
【问题讨论】:
为什么不把最后处理的写入数据库,然后选择它作为参数传递呢? 是的,我也是这么想的,但是我应该什么时候写最后处理的记录呢? @后工作?是否可以从作业执行上下文中获取此信息?正如我提到的,因为它是多线程的,最后处理的记录不一定是读取记录中的最大 id。 【参考方案1】:由于我们也在使用 ThreadPoolTaskExecutor,所以要知道最后处理的记录并不简单。
排序与多线程不兼容。如果你并行,“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 - 循环读取器、处理器和写入器 N 次
在 Spring Batch 中动态设置 gridSize(线程数)