mysql死锁监控工具pt-deadlock-logger

731 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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事务产生死锁。信息如下:

图片.png

原因:因为客户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语句.

图片.png

通过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/

分析死锁日志信息

图片.png

从死锁的日志中我们可以清晰的知道死锁产生的时间和语句,对于我们定位和分析死锁提供了很大帮助。

扩展

本文介绍的是将死锁的日志输出到文件中,也可以将死锁日志输出到对应的表中。

./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表即可。

总结

本文介绍了常见死锁监控工具的使用,监控工具只能给我提供定位和分析的帮助,如何在程序中避免死锁产生才是解决问题的根源,后续的性能优化章节将具体的分析讲解。