运行弹簧批处理作业的多个实例时出现死锁
Posted
技术标签:
【中文标题】运行弹簧批处理作业的多个实例时出现死锁【英文标题】:Deadlock while running multiple instances of a spring batch job 【发布时间】:2021-06-09 04:17:18 【问题描述】:我有一个 spring 批处理作业,它在基于块的步骤中从数据库读取并在进行一些处理后写入文件。 我的要求是同时运行几乎 16 个作业实例,只是使用不同的作业参数。
但我在这样做的过程中遇到了几个问题。
1.
无法为事务打开 JDBC 连接。嵌套异常是 java.sql.SQLTransientConnectionException: Hikaripool -1 - Connection is not available。
异常:无法增加标识。嵌套异常是 com.microsoft.SQLserver.jdbc.SQLServerException: Transaction (process ID 124) was deadlocked on lock resources with other process,并已被选为死锁牺牲品。重新运行事务。
我已经尝试了链接Github link 中提供的解决方案,方法是设置IsolationLevel
并更改元数据表,如下所示。
像这样设置 IsolationLevelForCreate
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setIsolationLevelForCreate("ISOLATION_REPEATABLE_READ");
让 DBA 像这样为每个 SEQ 表添加索引(JET 是我将 repo 表放入的架构):
ALTER TABLE [JET].[BATCH_JOB_EXECUTION_SEQ]
ADD CONSTRAINT [BATCH_JOB_EXECUTION_SEQ_PK] PRIMARY KEY CLUSTERED ([ID] ASC)
GO
ALTER TABLE [JET].[BATCH_JOB_SEQ]
ADD CONSTRAINT [BATCH_JOB_SEQ_PK] PRIMARY KEY CLUSTERED ([ID] ASC)
GO
ALTER TABLE [JET].[BATCH_STEP_EXECUTION_SEQ]
ADD CONSTRAINT [BATCH_STEP_EXECUTION_SEQ_PK] PRIMARY KEY CLUSTERED ([ID] ASC)
GO
但我仍然面临这个问题。
PS:spring batch已经部署到AKS(Azure Kubernetes Services),使用Azure SQLServer作为数据源。
【问题讨论】:
要调查死锁,您检查死锁图,它会告诉您哪些资源导致了死锁,这通常足以解决如何修复它。否则,您只是在猜测并希望中奖。此外,您很可能无法消除所有死锁,在这种情况下需要重试系统。 【参考方案1】:根据https://github.com/spring-projects/spring-batch/issues/1448 中的讨论,该问题似乎是由Spring Framework 中的SqlServerMaxValueIncrementer
未使用SQLServer 的本机序列引起的。以下是 Javadoc 的摘录:
There should be one sequence table per table that needs an auto-generated key.
Example:
create table tab (id int not null primary key, text varchar(100))
create table tab_sequence (id bigint identity)
insert into tab_sequence default values
这可能是由于 SQLServer 直到最近才支持序列。但我想这就是 Spring Batch 将tables to emulate sequences 用于 MS SQL Server 的原因。
我建议您尝试更改the default DDL 以使用序列而不是表格:
CREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ ;
CREATE SEQUENCE BATCH_JOB_EXECUTION_SEQ ;
CREATE SEQUENCE BATCH_JOB_SEQ ;
这是基于 MS SQL Server 的docs 的默认序列定义。这应该可以,但您可以根据需要自定义它们。
您可能还需要提供基于序列的自定义 DataFieldMaxValueIncrementer
(因为 Spring Framework 中的序列使用表)并通过 DataFieldMaxValueIncrementerFactory
将其注册到 Spring Batch 中(请参阅 JobRepositoryFactoryBean#setIncrementerFactory
)。
【讨论】:
以上是关于运行弹簧批处理作业的多个实例时出现死锁的主要内容,如果未能解决你的问题,请参考以下文章
使用 Apache Commons Exec 向命令提供多个输入并提取输出时出现问题