MySQL死锁排查:日志抓取与诊断思路
死锁问题概述
MySQL死锁是指两个或多个事务相互等待对方释放锁资源,导致事务无法继续执行。在IDC高并发业务场景下,死锁虽常见但若处理不及时可能引发连锁故障。本文聚焦死锁日志的获取方法与排查流程,帮助运维人员快速定位根因。
开启死锁日志记录
默认情况下MySQL仅记录最后发生的死锁信息,建议通过以下配置记录所有死锁:
- innodb_print_all_deadlocks=1:将每个死锁的详细信息输出到MySQL错误日志(error log)。
- log_error:确认错误日志路径,例如
/var/log/mysql/error.log。
配置生效后重启MySQL或使用 SET GLOBAL innodb_print_all_deadlocks=1;(MySQL 5.6+支持动态修改)。
抓取死锁日志的方法
方法1:从错误日志中提取
查看错误日志:tail -10000 /var/log/mysql/error.log,搜索关键字 "LATEST DETECTED DEADLOCK" 或 "DEADLOCK"。MySQL将输出每个死锁的事务ID、等待的锁、持有的锁以及事务的SQL语句。
方法2:使用SHOW ENGINE INNODB STATUS
执行 SHOW ENGINE INNODB STATUS\G,在输出中找到 LATEST DETECTED DEADLOCK 段。注意:该命令仅显示最近一次死锁,适合现场实时排查。配合 INNODB_TRX、INNODB_LOCKS 等系统表可获取更全面的锁信息。
方法3:搭建死锁监控工具
使用 pt-deadlock-logger(Percona Toolkit)持续监控死锁并将记录写入表或文件:
- 安装Percona Toolkit
- 运行
pt-deadlock-logger --iterations=0 --dest D=test,t=fred u=root - 分析记录的事务ID、等待时间、语句等。
排查死锁的通用思路
第一步:分析死锁日志
从日志中确定两个(或更多)事务,找出它们各自持有的锁和等待的锁。重点关注:
- 事务隔离级别:常见死锁在REPEATABLE READ下更易发生间隙锁冲突。
- 索引使用情况:未使用索引的更新会导致全表扫描加锁,增加死锁概率。
- SQL语句顺序:不同事务对同一组表的操作顺序不一致。
第二步:复现与验证
根据日志中的SQL和表结构,在测试环境构造类似并发请求。使用 SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX; 监控事务状态。
第三步:优化方案
常见解决策略包括:
- 统一访问顺序:所有事务按相同顺序操作表(如按主键升序)。
- 减少锁范围:为高频更新字段建立索引,避免间隙锁。
- 降低隔离级别:业务允许时使用READ COMMITTED以消除间隙锁。
- 拆分长事务:缩短事务持有锁的时间。
总结
死锁排查的核心是抓全日志、分析锁冲突、反查SQL逻辑。推荐生产环境开启 innodb_print_all_deadlocks,并结合pt-deadlock-logger实现自动化监控。掌握以上思路可大幅缩短MTTR(平均修复时间),保障IDC数据库稳定性。