阅读 94

阿里巴巴分布式事务框架seata使用的2个坑

背景:基于dubbo+springboot的微服务系统

版本:seata版本1.4.2 AT模式

其实seata配置很简单,只是官方文档写得不清不楚,让人很疑惑,某些配置也不知道是否有用,本文描述seata使用过程中的 2个基于nacos配置中心和注册中心的优化点,甚至可以说是bug

  1. 当参与到分布式事务的某个表存在联合主键,全局事务回滚会失败。

分支事务回滚时会抛出如下错误:

2021-10-27 23:09:28.779 INFO 8 --- [h_RMROLE_1_9_32] i.seata.rm.datasource.DataSourceManager : branchRollback failed. branchType:[AT], xid:[172.24.2.1:8091:9199310892359148], branchId:[9199310892359152], resourceId:[jdbc:mysql://172.24.3.1:3306/xxxx], applicationData:[null]. reason:[Branch session rollback failed and try again later xid = 172.24.2.1:8091:9199310892359148 branchId = 9199310892359152 Index: 1, Size: 1]

报错信息还很隐晦,Index: 1, Size: 1 其实就是数组越界了,看了下源码这个异常堆栈被吞掉了,
AbstractUndoLogManager.java 第360行,如下:

throw new BranchTransactionException(BranchRollbackFailed_Retriable, String
    .format("Branch session rollback failed and try again later xid = %s branchId = %s %s", xid,
        branchId, e.getMessage()), e);

抛出异常后,外层catch住也没打印堆栈,见DataSourceManager.java 第124行到131行

StackTraceLogger.info(LOGGER, te,    "branchRollback failed. branchType:[{}], xid:[{}], branchId:[{}], resourceId:[{}], applicationData:[{}]. reason:[{}]",    new Object[]{branchType, xid, branchId, resourceId, applicationData, te.getMessage()});if (te.getCode() == TransactionExceptionCode.BranchRollbackFailed_Unretriable) {    return BranchStatus.PhaseTwo_RollbackFailed_Unretryable;
} else {    return BranchStatus.PhaseTwo_RollbackFailed_Retryable;
}

修改源码,针对AbstractUndoLogManager加上打印日志堆栈信息,编译后,用arthas redefine这个类,发现结果是AbstractUndoExecutor.java 309行数组越界了,如下:

java.lang.IndexOutOfBoundsException: Index: 1, Size: 1

at java.util.ArrayList.rangeCheck(ArrayList.java:653)

at java.util.ArrayList.get(ArrayList.java:429)

at io.seata.rm.datasource.undo.AbstractUndoExecutor.queryCurrentRecords(AbstractUndoExecutor.java:309)

at io.seata.rm.datasource.undo.AbstractUndoExecutor.dataValidationAndGoOn(AbstractUndoExecutor.java:242)

at io.seata.rm.datasource.undo.AbstractUndoExecutor.executeOn(AbstractUndoExecutor.java:117)

at io.seata.rm.datasource.undo.AbstractUndoLogManager.undo(AbstractUndoLogManager.java:312)

at io.seata.rm.datasource.DataSourceManager.branchRollback(DataSourceManager.java:122)

at io.seata.rm.Abst

再看源码,原因就很明白了,undo表里面把联合主键串起来变成了1个字段,但是TableMeta里面还是作为2列,所以获取主键第2列值的时候,就抛出数组越界了。

2 当主流程调用同一个微服务两次,即启用了同一个微服务的2次分支事务,并且这2次分支事务涉及到同一行数据的修改,同样回滚的时候,2个分支事务回去竞争同一个行锁,会导致获取锁超时,回滚失败。


文章分类
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐