今天巡检时突然发现有很多锁等待超时的情况,原以为是一个简单的小事,一查,结果令人深思。
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事务的问题及优化的方案有什么建议可以留言沟通。
耿小厨已开通个人微信公众号,想进一步沟通或想了解其他文章的同学可以关注我