持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情
背景
项目中如果事务使用不当,会很容易出现死锁现象,但是死锁出现的场景比较复杂,问题的分析和定位比较困难。
简介
死锁:指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。
示例分析
通过一个简单的示例来模拟死锁。
新建表,插入相关数据
CREATE TABLE t (i INT) ENGINE = InnoDB;
INSERT INTO t (i) VALUES(1);
A客户端开启事务
START TRANSACTION;
SELECT * FROM t WHERE i = 1 LOCK IN SHARE MODE;
说明: LOCK IN SHARE MODE开启mysql的共享锁
B客户端开启事务,删除数据
START TRANSACTION;
DELETE FROM t WHERE i = 1;
说明:由于删除操作需要互斥锁 (X),但是互斥锁X和共享锁S是不能相容的。所以删除事务被放到锁请求队列中,客户B阻塞。
回到A客户端,删除同一条数据
DELETE FROM t WHERE i = 1;
说明:A删除成功,B事务产生死锁。信息如下:
原因:因为客户A需要锁X来删除行,而客户B拿着锁X并正在等待客户A释放锁S。所以产生死锁。
死锁分析
常见分析办法
通过查询mysql的INNODB_TRX来分析事务的情况
SELECT * FROM information_schema.INNODB_TRX;
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
INNODB_TRX 表提供了信息关于在InnoDB中执行的当前的每个事务包含是否事务是等待一个锁,以及当事务开始后事务正在执行的SQL语句.
通过mysql的INNODB_TRX能分析出事务的情况,从而定位死锁,但是他只能在产生死锁的时间内去进行分析,过一段时间后,该事务信息将会被清除,后续无法进行分析。也可以通过show engine innodb status \G 来查询mysql的日志信息来进行分析,但是通常日志文件会比较多,对于分析定位带来困难。
今天给大家介绍一款监控死锁的工具:pt-deadlock-logger
pt-deadlock-logger安装
关于pt-deadlock-logger的安装,详情可以参考juejin.cn/post/708908… 文章中安装pt-query-digest章节。
基本命令介绍
- --host:-h,IP地址
- --port:-P,端口
- --socket:-S,套接字文件
- --user:-u,用户名
- --password:-p,密码
- --charset:-A,字符集
- --database:-D,数据库
- --ask-pass:提示手动输入密码
- --daemonize:后台运行
- --dest:指定存储死锁信息的表
- --create-dest-table:自动创建存储死锁信息的表
- --columns:死锁信息存储表的列信息
- --log:指定存储死锁信息的日志文件
- --run-time:运行时间,默认永久
- --interval:运行间隔,默认30s
- --iterations:运行次数,默认无限
具体使用
新建mysql-lock.sh监控死锁脚本,内容如下:
#!/bin/bash
# 输入慢sql日志
pt-deadlock-logger --config /usr/local/percona-toolkit/config/pt-deadlock.cnf
在/usr/local/percona-toolkit/config/目录下新增pt-deadlock.cnf文件,内容如下
#login to MySQL server#
host=#host
port=3306
#
user=xx
password=yy
charset=utf8
#
#log to file
tab
log=/usr/local/log/pt_deadlock.log
daemonize
interval=5
说明:
- tab:代表输出是带上制表符,格式化显示,更加清晰
- log:指定日志文件用来存储死锁检测信息输出
- daemonize:放到后台运行,守护进程模式
- interval:每隔5秒检测一次
执行mysql-lock.sh脚本
出现pt-deadlock-logger命令不存在错误,则需要执行如下命令即可
ln -s /usr/local/percona-toolkit/bin/pt-deadlock-logger /usr/bin/
分析死锁日志信息
从死锁的日志中我们可以清晰的知道死锁产生的时间和语句,对于我们定位和分析死锁提供了很大帮助。
扩展
本文介绍的是将死锁的日志输出到文件中,也可以将死锁日志输出到对应的表中。
./pt-deadlock-logger h=172.13.14.15,P=3306,u=root,p=root --dest h=172.13.14.15,P=3306,D=test,t=deadlocks,u=root,p=root
其中t:代表是死锁的表名,如果产生死锁,可以查看deadlocks表即可。
总结
本文介绍了常见死锁监控工具的使用,监控工具只能给我提供定位和分析的帮助,如何在程序中避免死锁产生才是解决问题的根源,后续的性能优化章节将具体的分析讲解。