OneProxy :: 利用中间件记录事务堆栈,极速分析定位数据库死锁产生原因!

死锁(Dead Lock)是数据库里很难排查的问题,从数据库后端的错误日志中并不能得到非常有用的信息。由于死锁往往产生于比较复杂的事务之间,两个不同的事务以不同的顺序来操作表或记录引起的,死锁的产生和解决都需要从应用端入手,故而一般情况下需要了解应用才能分析并解决死锁问题。先来看一下死锁的例子,在第一个会话中,我们执行了如下的SQL语句:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from my_hash where id = 1 for update;
+----+------+-------+
| id | col2 | col3  |
+----+------+-------+
|  1 |  100 | Row 1 |
+----+------+-------+
1 row in set (0.03 sec)

mysql> select * from t_binlog where id = 1 for update;
+----+-------+
| id | col2  |
+----+-------+
|  1 | 30000 |
+----+-------+
1 row in set (4.63 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

在第二个会话中执行了如下的SQL语句:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t_binlog where id = 1 for update;
+----+-------+
| id | col2  |
+----+-------+
|  1 | 30000 |
+----+-------+
1 row in set (0.06 sec)

mysql> select * from my_hash where id = 1 for update;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

在明确地知道两个事务内容的情况下,可以很容易判断出来死锁产生的原因是,更新两个表的顺序不同,但在真实的应用中,往往只能知道“ERROR 1213”这个错误号以及报错的SQL语句,并不知道整个事务的内容,将会加大死锁分析的难度。而OneProxy中间件具备的事务分析功能,可以知道报错的SQL语句的事务结构,如下所示:

... TrxStack (192.168.1.119:42514) : 3908251694,3656660562
... SQLError (192.168.1.119:42514) : select * from my_hash where id = ? for update

在OneProxy开启“LOG_SQLERROR”功能后,如果是事务,将会打印出事务的SQL结构(参考TrxStack行),用逗号分开不同SQL语句的Hash值,以便于分析SQL产生的原因(可以根据SQL的Hash值查找完整的SQL语句),就可以一清二楚地定位死锁产生的原因。