Seata锁等待超时问题排查

科技资讯 投稿 7300 0 评论

Seata锁等待超时问题排查

伪代码如下:

@GlobalTransactional(rollbackFor = Exception.class,timeoutMills = 30000,lockRetryInternal=3000,lockRetryTimes=10
@Override
public Boolean cancel(Long id, Long userId, Long companyId {
    // 保存业务数据
    ...
    // 启动工作流
    wkflAppServiceProvider.startProcess(....;
    ...
}

 异常如下:

org.springframework.dao.QueryTimeoutException: JDBC commit; Global lock wait timeout; nested exception is io.seata.rm.datasource.exec.LockWaitTimeoutException: Global lock wait timeout
                                                                                             
Caused by: io.seata.rm.datasource.exec.LockWaitTimeoutException: Global lock wait timeout
        at io.seata.rm.datasource.exec.LockRetryController.sleep(LockRetryController.java:63
        at io.seata.rm.datasource.ConnectionProxy$LockRetryPolicy.doRetryOnLockConflict(ConnectionProxy.java:346
        at io.seata.rm.datasource.ConnectionProxy$LockRetryPolicy.execute(ConnectionProxy.java:335
        at io.seata.rm.datasource.ConnectionProxy.commit(ConnectionProxy.java:187
        at org.springframework.jdbc.datasource.DataSourceTransactionManager.doCommit(DataSourceTransactionManager.java:333
        ... 57 more
Caused by: io.seata.rm.datasource.exec.LockConflictException: get global lock fail, xid:10.222.248.60:8091:2900686326154883760, lockKeys:wkfl_app_auth:12326192,12326193;act_ge_bytearray:6515890,6515891;act_re_procdef:rediscountClickSubmitCancel_UserTask_0yze6zf_5:1:6515892;act_re_deployment:6515889
        at io.seata.rm.datasource.ConnectionProxy.recognizeLockKeyConflictException(ConnectionProxy.java:159
        at io.seata.rm.datasource.ConnectionProxy.processGlobalTransactionCommit(ConnectionProxy.java:252
        at io.seata.rm.datasource.ConnectionProxy.doCommit(ConnectionProxy.java:230
        at io.seata.rm.datasource.ConnectionProxy.lambda$commit$0(ConnectionProxy.java:188
        at io.seata.rm.datasource.ConnectionProxy$LockRetryPolicy.doRetryOnLockConflict(ConnectionProxy.java:343
        ... 60 more

看到“LockWaitTimeoutException: Global lock wait timeout” 我以为是有资源竞争,导致加锁等待超时。但这个疑虑很快被打消了,因为这是必现的一个问题,每次执行到这个方法都报错,甚至在下班后系统没有人使用的情况下,我一点,还是报这个错,这个时候可以确定就我一个人在用,而且查了数据库没有被锁定的数据和事务,所以应该不是资源竞争导致的获取锁等待超时。

数据源被代理,本地事务提交走的是io.seata.rm.datasource.ConnectionProxy#commit(

由于我们这里client.rm.lock.retryPolicyBranchRollbackOnConflict配置的是false,所以这里失败后会重试,如果是true,则不重试

看到这里,我们找到了“Global lock wait timeout”的出处了,原来是因为doCommit(执行过程中抛异常了,再重试次数用完后就会抛出LockWaitTimeoutException。因此,LockWaitTimeoutException只是表象,并不是最根本的原因,根本原因是doCommit(报错了。

接着doCommit(看,我们知道,分支事务提交要先注册,注册成功后才能提交。而注册就是要获取全局锁。

通过观察DEBUG日志,发现保存业务数据部分的分支注册都是成功的

结合代码,发现真正的报错发生在调用远程服务启动工作流那里

工作流那个服务里面,分支注册返回的信息是:Global lock acquire failed xid = ...。

于是,翻开Seata Server的源码,看看为什么返回的消息是这样的

直接快进到io.seata.server.transaction.at.ATCore#branchSess

编程笔记 » Seata锁等待超时问题排查

赞同 (33) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽