在 spring 批处理作业上重新定义数据库 "transactional" 边界
Redefine database "transactional" boundary on a spring batch job
有没有办法在 spring 批处理作业上重新定义数据库“事务”边界?
上下文:
我们有一个简单的支付处理作业,它读取 x 条支付记录,处理并将数据库中的记录标记为已处理。目前,编写器执行 REST API 调用(对支付网关),处理 API 响应并将记录标记为已处理。我们正在采用面向块的方法,因此在整个块完成之前不会将更新刷新到数据库。因为,基本上整个 read/write 都在一个事务中,我们开始看到过度的数据库锁定和争用。例如,如果 API 需要很长时间才能响应(例如 30 秒),则整个应用程序开始受到影响。
我们显然可以将 API 调用的超时时间减少到一个较小的值。但这仍然不能解决表可能被锁定的时间超过预期持续时间的问题。理想情况下,我们希望数据库事务的生命周期尽可能短。我们的想法是,如果可以在数据库事务之外完成工作的“实质”,我们就可以解决这个问题。因此,如果 API 调用发生在数据库事务之外。我们可以承受多花几秒钟来接受响应,而不是 cause/add 长锁定持续时间。
这是正确的方法吗?如果不是,以 spring 批处理方式完成这项“简单”工作的推荐方法是什么?是否有其他批处理工具更适合该任务? (如果 spring-batch 不是正确的选择)。
愿意在需要时提供更多背景信息。
我无法准确回答您的所有问题,但我会尝试提供一些指导。
Since, basically the whole read/write is within a transaction, we are starting to see excessive database locks and contentions. For example, if the API takes a long time to respond (say 30 seconds), the whole application starts to suffer.
从一开始,批处理或以“批次”形式处理数据这一术语就是基于将一批记录视为一个单元的想法:要么处理所有记录(无论术语“处理”是什么意思)或 none 的记录被处理。这种“全有或全无”语义正是 Spring Batch 在其面向块的处理模型中实现的。实现这样的(强大的)属性 需要权衡取舍。在您的情况下,您需要在一致性和响应性之间做出权衡。
We can obviously reduce the timeout for the API call to be a smaller value.. but that still doesn't solve the issue of the tables potentially getting locked for longer than desirable duration.
块大小是对交易行为影响最大的参数。您可以做的是尝试减少单个事务中要处理的记录数并查看结果。没有最佳值,这是一个经验过程。这也将取决于您在处理块期间调用的 API 的响应能力。
Our thought is that if the "meat" of what the job does can be done outside of the database transaction, we could get around this issue. So, if the API call happens outside of a database transaction.. we can afford it to take a few more seconds to accept the response and not cause/add to the long lock duration.
避免在实时系统上进行此类更新的一种常用技术是卸载针对另一个数据存储的处理,然后在单个事务中复制更新。这个想法是用给定的批处理 ID 标记记录,并将这些记录复制到不同的数据存储(或者甚至是同一数据存储中的临时 table),批处理可以在不影响实时数据存储的情况下使用该数据存储。一旦处理完成(可以并行完成以提高性能),记录可以在单个事务中标记为在实时系统中已处理(这通常非常快并且可以基于批次 ID 来识别哪些记录更新)。
有没有办法在 spring 批处理作业上重新定义数据库“事务”边界?
上下文:
我们有一个简单的支付处理作业,它读取 x 条支付记录,处理并将数据库中的记录标记为已处理。目前,编写器执行 REST API 调用(对支付网关),处理 API 响应并将记录标记为已处理。我们正在采用面向块的方法,因此在整个块完成之前不会将更新刷新到数据库。因为,基本上整个 read/write 都在一个事务中,我们开始看到过度的数据库锁定和争用。例如,如果 API 需要很长时间才能响应(例如 30 秒),则整个应用程序开始受到影响。
我们显然可以将 API 调用的超时时间减少到一个较小的值。但这仍然不能解决表可能被锁定的时间超过预期持续时间的问题。理想情况下,我们希望数据库事务的生命周期尽可能短。我们的想法是,如果可以在数据库事务之外完成工作的“实质”,我们就可以解决这个问题。因此,如果 API 调用发生在数据库事务之外。我们可以承受多花几秒钟来接受响应,而不是 cause/add 长锁定持续时间。
这是正确的方法吗?如果不是,以 spring 批处理方式完成这项“简单”工作的推荐方法是什么?是否有其他批处理工具更适合该任务? (如果 spring-batch 不是正确的选择)。
愿意在需要时提供更多背景信息。
我无法准确回答您的所有问题,但我会尝试提供一些指导。
Since, basically the whole read/write is within a transaction, we are starting to see excessive database locks and contentions. For example, if the API takes a long time to respond (say 30 seconds), the whole application starts to suffer.
从一开始,批处理或以“批次”形式处理数据这一术语就是基于将一批记录视为一个单元的想法:要么处理所有记录(无论术语“处理”是什么意思)或 none 的记录被处理。这种“全有或全无”语义正是 Spring Batch 在其面向块的处理模型中实现的。实现这样的(强大的)属性 需要权衡取舍。在您的情况下,您需要在一致性和响应性之间做出权衡。
We can obviously reduce the timeout for the API call to be a smaller value.. but that still doesn't solve the issue of the tables potentially getting locked for longer than desirable duration.
块大小是对交易行为影响最大的参数。您可以做的是尝试减少单个事务中要处理的记录数并查看结果。没有最佳值,这是一个经验过程。这也将取决于您在处理块期间调用的 API 的响应能力。
Our thought is that if the "meat" of what the job does can be done outside of the database transaction, we could get around this issue. So, if the API call happens outside of a database transaction.. we can afford it to take a few more seconds to accept the response and not cause/add to the long lock duration.
避免在实时系统上进行此类更新的一种常用技术是卸载针对另一个数据存储的处理,然后在单个事务中复制更新。这个想法是用给定的批处理 ID 标记记录,并将这些记录复制到不同的数据存储(或者甚至是同一数据存储中的临时 table),批处理可以在不影响实时数据存储的情况下使用该数据存储。一旦处理完成(可以并行完成以提高性能),记录可以在单个事务中标记为在实时系统中已处理(这通常非常快并且可以基于批次 ID 来识别哪些记录更新)。