死锁排查与解决
2024 年双十一零点,订单服务的数据库连接池突然耗尽,大量请求超时。DBA 紧急介入,发现是死锁导致的。
事故过程:
- 商家 A 和商家 B 同时处理两笔订单(订单 1 和订单 2)
- 商家 A 锁了订单 1,等订单 2;商家 B 锁了订单 2,等订单 1
- 死锁形成,两个商家互相等待
这不是技术故障,是事务设计缺陷导致的业务层面死锁。今天这篇,把 InnoDB 死锁从根上讲透。
一、死锁的定义 🔴
1.1 死锁的形成条件
死锁的四个必要条件(Coffman 条件):
- 互斥条件:资源一次只能被一个事务持有
- 持有并等待:事务持有资源的同时,等待其他事务释放资源
- 不可抢占:资源不能被强制从持有事务中抢走
- 循环等待:事务之间形成循环等待链
MySQL InnoDB 的死锁:两个或多个事务互相持有对方需要的锁,形成循环等待。
1.2 InnoDB 的死锁处理机制
MySQL InnoDB 有死锁检测机制:
1.3 ❌ 错误示范
候选人原话:"死锁就是锁等待超时了。"
问题诊断:混淆了死锁和锁等待超时。死锁是两个事务互相等待;锁等待超时是一个事务等另一个事务释放锁。死锁由 MySQL 自动检测并处理;锁等待超时需要设置 innodb_lock_wait_timeout。
候选人原话 2:"InnoDB 能完全避免死锁。"
问题诊断:错误。InnoDB 只能检测并处理死锁,不能完全避免死锁。业务层必须合理设计事务来减少死锁发生的概率。
【面试官心理】 这道题我会从生产事故切入,然后问具体的死锁案例。如果候选人能在 SHOW ENGINE INNODB STATUS 的输出中快速定位问题,说明他有实战经验。
二、死锁的典型场景 🔴
2.1 场景一:行锁争用
2.2 场景二:间隙锁 + 插入
2.3 场景三:不同事务访问顺序不一致
三、死锁排查方法 🟡
3.1 查看死锁日志
输出示例(LATEST DETECTED DEADLOCK 部分):
3.2 关键信息解读
3.3 信息收集
四、死锁预防策略 🟡
4.1 统一资源访问顺序
4.2 减少事务持有时间
4.3 降低隔离级别
4.4 避免在事务中交互用户
五、生产调优 🟢
5.1 配置死锁检测
5.2 监控告警
5.3 常见死锁处理流程
- 发现:监控告警或用户投诉响应慢
- 确认:SHOW ENGINE INNODB STATUS 确认死锁
- 分析:读懂死锁日志,确定事务之间的等待关系
- 处理:终止持有锁较少的事务,或优化 SQL 改写
- 预防:修改业务逻辑,统一访问顺序
【面试官心理】 死锁是 MySQL 面试中最考验实战经验的题目之一。能说出完整排查流程和预防策略的候选人,说明他真正踩过坑、救过火。