pt-deadlock-logger 检测死锁

pt-deadlock-logger 是 Percona Toolkit 中的一个命令行工具。它的核心作用就是帮你自动、持续地记录下 MySQL 数据库发生的每一次死锁

💡 为什么需要它?

MySQL 自己提供的 SHOW ENGINE INNODB STATUS 命令虽然能看到死锁信息,但它有个很大的局限:只能看到最近一次发生的死锁。如果死锁发生得很频繁,之前的记录很快就会被覆盖掉,这就给排查问题带来了困难。

pt-deadlock-logger 正是为了解决这个问题而生的。它会定时去检查 SHOW ENGINE INNODB STATUS 的输出,一旦发现新的死锁,就把它记录下来,让你能保留一份完整的"死锁历史记录",方便事后分析。

🛠️ 它是怎么工作的?

可以把它理解成一个自动化的"死锁记录员":

  1. 持续监控 :工具会按设定的时间间隔(比如每30秒)去查询一次SHOW ENGINE INNODB STATUS
  2. 智能识别:它能识别出哪些死锁是"新的",从而避免重复记录同一条死锁信息。
  3. 保存结果 :它有两种记录方式:
    • 直接输出到屏幕(STDOUT)。
    • 保存到数据库表 (通过--dest参数),这是最推荐的方式,方便后续用SQL查询和分析。同时也可以用--log参数写入文件。

📋 如何用它来记录死锁?

使用 pt-deadlock-logger 其实不复杂,核心步骤就两步。

第一步:准备一张存放死锁记录的表

为了将死锁信息持久化保存,需要在某个数据库中创建一张专用的表。可以手动执行建表语句,或者直接用工具自带的 --create-dest-table 参数自动创建。

推荐使用的表结构通常包含以下字段,记录了死锁发生时的详细信息:

字段名 作用
server 发生死锁的服务器
ts 检测到死锁的时间
thread 发生死锁的线程ID
txn_id 事务ID
user / hostname 执行该操作的数据库用户名和主机
db / tbl / idx 发生死锁的数据库、表和索引
lock_type / lock_mode 锁的类型和模式
query 导致死锁的SQL语句
victim 该事务是否被选为"牺牲者"被回滚

第二步:启动监控工具

准备好存储表后,就可以运行工具来开始监控了。以下是一个基本用法的示例:

bash 复制代码
pt-deadlock-logger \
  --host=源数据库IP \
  --user=用户名 \
  --password=密码 \
  --dest h=目标数据库IP,D=目标数据库,t=deadlocks,u=用户名,p=密码 \
  --interval=30 \
  --run-time=3600
  • --host--user 等是连接被监控的数据库的信息。
  • --dest 指定了存放死锁记录的数据库、表以及连接信息
  • --interval=30 表示每30秒检查一次死锁。
  • --run-time=3600 表示运行1小时后退出。如果不加这个参数,工具会一直运行下去,通常在生产环境会配合 --daemonize 让它作为后台进程常驻。

总而言之,pt-deadlock-logger 就像一个自动记录死锁事件的"黑匣子",对于分析死锁频发的原因、优化应用代码非常有帮助。

模拟与验证死锁记录

为了验证效果,可以人为制造一次死锁。例如,在两个会话中,按相反的顺序更新同一张表的记录

会话1

sql

ini 复制代码
START TRANSACTION;
UPDATE t1 SET c2 = 'greatsql' WHERE id = 1;

会话2

sql

ini 复制代码
START TRANSACTION;
UPDATE t1 SET c2 = 'GreatSQL' WHERE id = 2;

会话1(此时被阻塞等待)

sql

ini 复制代码
UPDATE t1 SET c2 = 'greatsql' WHERE id = 2;

会话2(形成死锁,并回滚)

sql

vbnet 复制代码
UPDATE t1 SET c2 = 'GreatSQL' WHERE id = 1;
-- 此时会报错:ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

4. 查看记录的死锁详情

工具运行后,再去查询之前创建的 deadlocks 表,就能看到死锁的详细记录了

server ts thread user db tbl idx lock_type lock_mode wait_hold victim query
localhost 2024-03-20 15:12:51 1216 root test_db t1 PRIMARY RECORD X w 1 UPDATE t1 SET c2 = 'GreatSQL' WHERE id = 1
localhost 2024-03-20 15:12:51 1230 root test_db t1 PRIMARY RECORD X w 0 UPDATE t1 SET c2 = 'greatsql' WHERE id = 2

从表中可以清楚地看到:发生死锁的时间(ts)、哪个线程(thread)、在哪个库哪个表(db, tbl)、锁的类型(lock_mode)、哪个事务是牺牲者被回滚了(victim),以及导致死锁的具体SQL(query)。这个结构化信息比直接看 SHOW ENGINE INNODB STATUS 的文本要清晰得多

相关推荐
Ethan010719 小时前
数据库死锁-应用层重试
mysql
宠友信息1 天前
消息序号如何保证即时通讯源码聊天记录稳定加载
java·spring boot·redis·python·mysql·uni-app
笨蛋不要掉眼泪1 天前
MySQL架构揭秘:慢查询日志详解
数据库·mysql·架构
️学习的小王1 天前
MySQL 实战:从建表到索引管理的完整指南
数据库·mysql·oracle
宠友信息2 天前
MySQL复合索引与Druid优化仿小红书源码个人主页查询链路
数据库·spring boot·websocket·mysql·uni-app
minji...2 天前
MySQL数据库 (十九) MySQL图像化界面,MySQL连接池
数据库·mysql·navicat·mysql workbench·mysql连接池·数据库图形化界面
文档搬运工2 天前
Innodb Cluster安装
mysql
想躺平的小羊2 天前
MySQL中LAST_DAY函数用法
数据库·mysql
光影6272 天前
MySQL基础入门
数据库·笔记·sql·学习·mysql·学习方法