Spring Batch中管理长时间运行作业:解决连接问题


在 Spring Batch 中处理长时间运行的作业可能很棘手,尤其是在管理数据库连接和事务时。在我们关于 Developer's Coffee 的最新文章中,我们深入探讨了 Spring Batch 作业由于连接限制而超时的现实问题。

了解我们如何通过调整 HikariCP 设置和调整负载平衡器超时来解决该问题,以确保批处理顺利可靠。请继续阅读,详细了解我们的解决方案以及如何将它们应用到您的项目中。

Spring Batch 是一个用于处理大量数据的强大框架。然而,在处理长时间运行的作业时,尤其是在数据库连接和事务管理方面,它可能会带来挑战。在这篇文章中,我们将探讨在长时间运行的批处理作业中遇到的实际问题以及我们如何解决它。

问题
我们有一个 Spring Batch 作业,其中包括多个步骤,其中一个步骤需要花费相当多的时间来执行。该作业使用 HikariCP 进行连接池,最大生命周期设置为 30 分钟。使用的数据库是 YugabyteDB。

这是我们的作业配置的片段:

return new StepBuilder("step1", jobRepository)
        .<UUID, UUID>chunk(employeeTmpProcessorPageSize, transactionManager)
        .reader(employeeTmpReader)
        .writer(employeeTmpWriter)
        .faultTolerant()
        .skipLimit(step1SkipLimit)
        .skip(RuntimeException.class)
        .allowStartIfComplete(true)
        .listener(new SPItemProcessorListener())
        .taskExecutor(taskExecutor)
        .build();

在执行过程中,如果step1花费的时间超过30分钟,我们会遇到以下异常:

org.springframework.dao.DataAccessResourceFailureException: PreparedStatementCallback; SQL [UPDATE ...]; An I/O error occurred while sending to the backend.; nested exception is com.yugabyte.util.PSQLException: An I/O error occurred while sending to the backend.
...
Caused by: java.sql.SQLException: Connection is closed
    at com.zaxxer.hikari.pool.ProxyConnection$ClosedConnection.lambda$getClosedConnection$0(ProxyConnection.java:502)

根本原因分析 (RCA)
1.连接超时:HikariCP 连接池关闭空闲时间超过 30 分钟的连接。这会导致超出此持续时间的长时间运行步骤出现问题。

2.数据库负载均衡器超时:负载均衡器的空闲超时设置为较低值(例如,30 分钟),导致长时间运行的事务的连接丢失。

3.事务上下文:Spring Batch 的事务上下文维护连接以更新作业元数据。当连接关闭时,会导致更新此元数据失败。
解决方案

为了解决这个问题,我们实施了以下更改:
1.增加 HikariCP max-lifetime:此设置增加到更高的值,以确保连接在长时间运行的步骤期间保持打开状态。然而,这只是一个临时措施。
spring.datasource.hikari.max-lifetime=5400000 # 90 minutes

2.调整负载均衡器超时:我们将 Azure 负载均衡器上的空闲超时设置增加到 60 分钟,以与我们预期的作业执行时间保持一致。

3.定期连接验证:我们添加了连接验证查询,以在长时间运行的步骤期间定期检查和刷新连接。

spring.datasource.hikari.validation-timeout=30000 # 30 seconds
spring.datasource.hikari.idle-timeout=60000 # 60 seconds

结果
实施这些更改后,长时间运行的批处理作业成功执行,没有连接超时问题。作业存储库能够维护和更新作业执行上下文,确保数据一致性和作业成功完成。

结论
在 Spring Batch 中处理长时间运行的作业需要仔细考虑数据库连接设置和事务管理。通过延长连接寿命并使负载均衡器设置与作业要求保持一致,我们可以确保稳健可靠的批处理。