为何出现了trx_mysql_thread_id为0 的事务
今天巡检时突然发现有很多锁等待超时的情况,原以为是一个简单的小事,一查,结果令人深思。
1. 问题现象
发现日志中出现了大量的 error 1205 (hy000): lock wait timeout exceeded; try restarting transaction 错误
2. 排查过程
发现此类情况后,挑了其中一个sql脚本手动运行了一下,发现同样报此错误
mysql> update tbname set column_name = 2 where col_id= '25945fa285904ea59cd92a73a3850ceb' and ayear = 2018 and amonth = 5; error 1205 (hy000): lock wait timeout exceeded; try restarting transaction
出现此情况,第一反应是查看是否有未提交的事务或有其他的sql运行时也需要对该条记录进行写操作。
# 查看正在运行的sql select * from information_schema.processlist where info is not null;
结果集中并无对该表的任何操作,因此,很大可能是有未提交的事务了。
# 查看事务
select *from information_schema.innodb_trx;
结果中确实存在大量事务,此时原本以为已经查到问题,直接将对应为提交的事务杀掉即可(已与相关人员确认可以杀)
于是把脚本准备好,准备大开杀戒
# 杀sql会话
select concat('kill ',trx_mysql_thread_id,";")t_sql from information_schema.innodb_trx;
但是仔细一看,trx_mysql_thread_id全部都是0
经确认,trx_mysql_thread_id=0 的事务全部为xa事务。
3. 处理过程
因为trx_mysql_thread_id=0 的事务无法通过kill trx_mysql_thread_id 的方式处理,所以,需要回滚这些xa事务。
查看xa事务信息
mysql> xa recover;
+------------+--------------+--------------+-------------------------------+
| formatid | gtrid_length | bqual_length | data |
+------------+--------------+--------------+-------------------------------+
| 1096044365 | 20 | 9 | tm156393736565426841tm1333009 |
| 1096044365 | 20 | 9 | tm156393708714926372tm1332251 |
| 1096044365 | 20 | 9 | tm156393726166726646tm1332693 |
...
+------------+--------------+--------------+-------------------------------+
43 rows in set (0.00 sec)
拼接生成xa事务回滚脚本
# xa事务回滚命令的格式: xa rollback 'left(data,gtrid_length)','substr(data,gtrid_length+1,bqual_length)', formatid;
# 以上查出来的信息拼接结果为(以下举其中一个为例)
xa rollback 'tm156393736565426841','tm1333009',1096044365;
执行回滚脚本
mysql> xa rollback 'tm156393736565426841','tm1333009', 1096044365;
query ok, 0 rows affected (0.00 sec)
检查是否还存在未提交的xa事务
发现已经无正在执行事务
xa信息
测试能否正常更新记录
# 发现也已正常
再检查各日志,此类锁等待问题也未出现。
4. xa事务(分布式事务)浅析
mysql> xa start 'xatest'; query ok, 0 rows affected (0.00 sec) mysql> insert into mytable (i) values(10); query ok, 1 row affected (0.04 sec) mysql> xa end 'xatest'; query ok, 0 rows affected (0.00 sec) mysql> xa prepare 'xatest'; query ok, 0 rows affected (0.00 sec) mysql> xa commit 'xatest'; query ok, 0 rows affected (0.00 sec)
阶段二为提交阶段(commit)。当transaction manager确认所有参与者都ready后,向所有参与者发送commit命令。
因为xa 事务是基于两阶段提交协议的,所以需要有一个事务协调者(transaction manager)来保证所有的事务参与者都完成了准备工作(第一阶段)。如果事务协调者(transaction manager)收到所有参与者都准备好的消息,就会通知所有的事务都可以提交了(第二阶段)。mysql 在这个xa事务中扮演的是参与者的角色,而不是事务协调者(transaction manager)。
xa事务的性能问题
xa的性能很低。一个数据库的事务和多个数据库间的xa事务性能对比可发现,性能差10倍左右。因此要尽量避免xa事务,例如可以将数据写入本地,用高性能的消息系统分发数据。或使用数据库复制等技术。只有在这些都无法实现,且性能不是瓶颈时才应该使用xa。并发高的情况下不建议使用,可以借助redis或其他方法来改造。
关于xa事务的问题及优化的方案有什么建议可以留言沟通。
耿小厨已开通个人微信公众号,想进一步沟通或想了解其他文章的同学可以关注我