近期遇到一起业务方要求我们运维同学帮助处理分布式事务的事情,分布式事务处理需要非常谨慎,整理了一下相关点。

XA事务注意点

        残留XA事务是提交还是回滚,必须要由业务决定,保留证据,免留后患。

        在单个实例的运维视角,无法决定某个XA事务是应该提交还是应该回滚,不管选择哪种处置方式可能会导致全局数据出错。

        举个例子:A给B转账1000无,A在实例1上,B在实例2上,开启了一个分布式事务,A减1000元,B加1000元,由于是在两个不同实例上的事务,实例之间没有直接关联,靠业务层的分布式事务管理器来保证一致性,现在A实例上残留的这个XA事务,那个这个事务该提交还是回滚呢?

        必须和B实例上的同个XA事务处理结果保持一致。即B提交,则A必须提交,B回滚则A必须回滚,否则就会存在转出帐户扣了钱,但收款帐户的未收到,或收款的收到了钱,转出的未扣。

        当运维上去处理时,在单个实例视角,无法正确判断出事务是应该提交还是回滚的。所以告诉业务方由他们自己处理最为妥当,如果业务一定要运维处理,必须由业务方明确指出是需要对某个事务做提交或回滚,且一定要告知业务方这么处理数据可能破坏全局数据一致性。

回滚或提交办法:

        执行xa recover 查看未提交XA事务,选择对应的进行rollback或commit。

        如果仅 gtrid_length 有值一般可能直接以Xa rollback/commit xid方式回滚或提交,xid就是xa recover中data。

        如果gtrid_length和bqual_length 都有值,回滚或提交比较麻烦,需要以 xa rollback/commit gtrid, bqual,formatid 方式提交或回滚,gtrid和 bqual被拼接在 data字段中,需要按他们长度切分,以下未提交xa事务里第一个为例,gtrid_length 为34则data中前34个字符为gtrid, bqual_length 为22则bqual为data中后22个字符,对其回滚或提交方式如下:

xa rollback '10.10.10.10.tm163721155374124700','10.10.10.10.tm881366',1096044365;
xa commit '10.10.10.10.tm163721155374124700','10.10.10.10.tm881366',1096044365;
 
MySQL [(none)]> xa recover;
+------------+--------------+--------------+----------------------------------------------------------+
| formatID   | gtrid_length | bqual_length | data                                                     |
+------------+--------------+--------------+----------------------------------------------------------+
| 1096044365 |           34 |           22 | 10.10.10.10.tm16372115537412470010.10.10.10.tm881366 |
| 1096044365 |           34 |           22 | 10.10.10.10.tm16372115536792469510.10.10.10.tm881357 |
| 1096044365 |           34 |           22 | 10.10.10.10.tm16372115536372469310.10.10.10.tm881350 |
| 1096044365 |           34 |           22 | 10.10.10.10.tm16372115535172468110.10.10.10.tm881326 |
| 1096044365 |           34 |           22 | 10.10.10.10.tm16372115534862467610.10.10.10.tm881319 |


如果data中有其它特殊字符,也可以转成16进制整数方式处理,执行语句如下:

XA recover convert xid;

MySQL [(none)]> xa recover convert xid;
+------------+--------------+--------------+--------------------------------------------------------------------------------------------------------------------+
| formatID   | gtrid_length | bqual_length | data                                                                                                               |
+------------+--------------+--------------+--------------------------------------------------------------------------------------------------------------------+
| 1096044365 |           34 |           22 | 0x31302E3137372E3139372E34312E746D31363337323131353532383532323436303531302E3137372E3139372E34312E746D383831323038 |
| 1096044365 |           34 |           22 | 0x31302E3137372E3139372E34312E746D31363337323131353532383538323436303631302E3137372E3139372E34312E746D383831323037 |
| 1096044365 |           34 |           22 | 0x31302E3137372E3139372E34312E746D31363337323131353532383836323436313131302E3137372E3139372E34312E746D383831323230 |
| 1096044365 |           34 |           22 | 0x31302E3137372E3139372E34312E746D31363337323131353532383432323436303331302E3137372E3139372E34312E746D383831323139 |

因为是16进制数,回滚或提交的字符数*2,grtrid是34则是68个16进制数字,bqual是22则是44个:

xa rollback 0x31302E3137372E3139372E34312E746D313633373231313535323835323234363035, 0x31302E3137372E3139372E34312E746D383831323038,1096044365;
 xa commit, 0x31302E3137372E3139372E34312E746D313633373231313535323835323234363035, 0x31302E3137372E3139372E34312E746D383831323038,1096044365;

        注意,上面的提交或回滚都可能报xid不存在,这不一定是xid写错了,可能是这个xid的事务还在进行中,当有连接正在进行某个XA事务时,其它连接不能处理,所以处理XA事务一定要谨慎。当一个XA事务进行到XA prepare之后,必须要等执行到XA prepare的这个连接断开,其它连接才可以接着处理这个事务。