认识常用命令
show engine innodb status;
介绍
show engine innodb status; 是 innodb 存储引擎提供的一个诊断工具,它会输出一份非常详细的报告,包含 innodb 内部多个维度的状态信息。这份报告主要包含以下几个部分:
- background thread: 后台主线程(如刷新脏页)的活动信息。
- semaphores: 信号量信息,用于诊断线程间争用和锁等待。如果系统存在大量锁等待,这里会有体现。
- latest detected deadlock: 这是你最关心的部分。它记录了最近一次发生的死锁的详细信息,包括:
- 导致死锁的事务:涉及死锁的多个事务的线程id、正在执行的sql语句(可能不是完整的业务sql,而是锁等待相关的内部sql)。
- 事务持有的锁和等待的锁:清晰展示了每个事务已经持有什么锁,以及它正在尝试获取什么锁。
- 回滚的事务:innodb 选择哪个事务作为“牺牲品”来回滚以打破死锁。
- transactions: 当前活跃的事务信息。
- file i/o: i/o 相关线程信息。
- buffer pool and memory: 缓冲池和内存的使用统计。
- row operations: 行操作相关的统计信息。
为什么没查到你的死锁信息?
核心原因:**latest detected deadlock** 只记录最近一次死锁。
想象一下,它是一个只能容纳一条记录的“死锁日志表”。当发生一个新的死锁时,旧的记录就会被覆盖。
所以,可能的情况是:
- 在你的程序报错和你在数据库执行
show engine innodb status;之间的这段时间内,系统又发生了新的死锁,把你遇到的那个死锁信息给覆盖掉了。 - 数据库可能在你查询之前重启过,因为这份报告是存储在内存中的,重启后会清空。
方式汇总
方式一:执行show engine innodb status;命令
直接执行该命令查看最近的一次死锁日志记录:
show engine innodb status;
方式二:死锁日志记录
初始化
步骤一:开启并配置永久的死锁日志记录
这是最重要的一步,能让你在死锁发生后从容地分析。
1、开启 innodb 死锁日志打印到错误日志:
确保你的 mysql 配置文件中(如 my.cnf 或 my.ini)有以下配置:
[mysqld] innodb_print_all_deadlocks = on
这个配置会让 innodb 将每一次死锁的详细信息都记录到 mysql 的错误日志(error log)中,而不是仅仅在 show engine innodb status; 中保留最近一次。
修改后需要重启 mysql 服务,或者动态设置(需要有权限):
set global innodb_print_all_deadlocks = on;
2、配置并监控错误日志:
找到你的 mysql 错误日志文件路径(可以通过 show variables like 'log_error'; 查看)。
之后,每当发生死锁,你都可以去这个日志文件里搜索 "deadlock" 关键字,找到完整的死锁报告。
步骤二:捕获并分析死锁现场
当你的应用程序(例如,日志中、监控系统)报告死锁错误时(mysql 通常会返回 error 1213),立即去检查错误日志。
你会看到类似这样的报告(这是一个简化示例):
*** (1) transaction: transaction 123456, active 10 sec starting index read mysql tables in use 1, locked 1 lock wait 4 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 mysql thread id 100, os thread handle 0x..., query id 1000 ... updating delete from t1 where a = 1 *** (1) holds the lock(s): -- 事务1持有的锁 record locks space id 100 page no 10 n bits 80 index primary of table `test`.`t1` trx id 123456 lock_mode x locks rec but not gap record lock, heap no 5 physical record: ... *** (1) waiting for this lock to be granted: -- 事务1在等待的锁 record locks space id 100 page no 11 n bits 80 index sec_idx of table `test`.`t1` trx id 123456 lock_mode x locks rec but not gap waiting record lock, heap no 6 physical record: ... *** (2) transaction: transaction 123457, active 15 sec starting index read mysql tables in use 1, locked 1 4 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 mysql thread id 101, os thread handle 0x..., query id 1001 ... updating delete from t1 where a = 2 *** (2) holds the lock(s): -- 事务2持有的锁 record locks space id 100 page no 11 n bits 80 index sec_idx of table `test`.`t1` trx id 123457 lock_mode x locks rec but not gap record lock, heap no 6 physical record: ... *** (2) waiting for this lock to be granted: -- 事务2在等待的锁 record locks space id 100 page no 10 n bits 80 index primary of table `test`.`t1` trx id 123457 lock_mode x locks rec but not gap waiting record lock, heap no 5 physical record: ... *** we roll back transaction (2) -- 数据库选择回滚了事务2
步骤三:解读死锁报告并定位业务代码
分析上面的报告,关键是找到:
涉及的事务:两个(或多个)事务分别在执行什么 sql?
示例中,两个事务都在执行 delete,但条件不同 (a=1 和 a=2)。
- 锁的持有和等待关系:
- 事务1:持有了
primary索引上某行的x锁,正在等待sec_idx索引上某行的x锁。 - 事务2:持有了
sec_idx索引上某行的x锁,正在等待primary索引上某行的x锁。
- 事务1:持有了
- 死锁成因:
这就形成了一个典型的“循环等待”:事务1等事务2,事务2又在等事务1。数据库为了打破僵局,选择回滚其中一个(这里是事务2)。
排查过程
1、立即捕获死锁现场
# 1. 立即查询最新死锁信息(趁还没被覆盖) show engine innodb status\g # 2. 检查死锁记录是否已开启 show variables like 'innodb_print_all_deadlocks'; # 3. 如果未开启,立即开启(避免后续死锁丢失) set global innodb_print_all_deadlocks = on;
2、定位日志中的死锁情况
# 1. 找到错误日志位置 mysql -e "show variables like 'log_error';" # 2. 实时监控错误日志中的死锁(推荐) tail -f /var/log/mysql/error.log | grep -a 50 -b 5 "deadlock" # 3. 或者搜索历史死锁记录 grep -a 50 "deadlock" /var/log/mysql/error.log
3、快速分析核心问题
在死锁日志中,重点关注以下4个部分: text latest detected deadlock ------------------------ *** (1) transaction: [关键点1:事务1信息] transaction 1234, active 10 sec updating mysql tables in use 1, locked 1 [看这里→] update table_x set ... where id = 1 [关键sql1] *** (1) holds the lock(s): [关键点2:事务1持有的锁] record locks index `idx_name` of table `db`.`table` trx id 1234 lock_mode x *** (1) waiting for this lock(s): [关键点3:事务1等待的锁] record locks index `primary` of table `db`.`table` trx id 1234 lock_mode x waiting *** (2) transaction: [关键点4:事务2信息] transaction 1235, active 8 sec updating [看这里→] update table_x set ... where id = 2 [关键sql2]
4、快速诊断模板
对照这个模板分析:
| 检查项 | 要问的问题 | 常见原因 |
|---|---|---|
| 死锁类型 | 是不同索引冲突还是相同资源争用? | 跨索引死锁常见 |
| sql语句 | 两个事务执行的具体sql是什么? | update/delete 容易死锁 |
| 资源顺序 | 事务访问资源的顺序是否一致? | 顺序不一致是主因 |
| 事务大小 | 事务中是否包含多个sql? | 大事务容易死锁 |
| 索引使用 | where条件是否走了合适索引? | 无索引导致锁表 |
紧急应对策略:
-- 1. 查看当前锁等待情况(辅助分析) select * from information_schema.innodb_locks; select * from information_schema.innodb_lock_waits; -- 2. 查看当前活跃事务 select * from information_schema.innodb_trx order by trx_started desc;
死锁解决方案
1、分析是否事务过大导致。
2、有无涉及到两段代码为:
a b
b a
的过程
相关排查思路文章
[2]. mysql 故障案例分析:从死锁到数据丢失的全面诊断指南
到此这篇关于mysql死锁类deadlock问题排查的文章就介绍到这了,更多相关mysql死锁类deadlock排查内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论