死锁检测器本身不导致cpu飙升,真正原因是高频率死锁检测触发,源于大量事务在热点行反复争抢锁;show engine innodb status无死锁记录但cpu高,因检测按需触发且频繁遍历等待图;关键证据是transactions段中“trx has been waiting”密集重复出现;修复须从应用层重构事务顺序、拆分热点或改用乐观锁。

死锁检测器本身不会直接导致CPU飙升;真正耗CPU的是高频率的死锁检测触发,根源是大量事务在热点行上反复争抢锁。
为什么 SHOW ENGINE INNODB STATUS 里看不到死锁记录,CPU却很高?
死锁检测是“按需触发”的:只有当事务尝试获取锁被阻塞时,InnoDB 才会启动死锁检测逻辑。如果大量事务卡在同一个 UPDATE 语句(比如更新影院账户余额),每个阻塞都会触发一次检测——哪怕最终没形成环路,检测过程本身就要遍历等待图、做图遍历运算,CPU 就这么被吃光了。
- 现象:
SHOW PROCESSLIST中大量线程状态为updating或Locked,但---------------- LATEST DETECTED DEADLOCK ----------------段为空 - 关键指标:在
TRANSACTIONS段中,观察Trx has been waiting for ... sec的事务数量是否持续增长 - 注意:
innodb_deadlock_detect=ON是默认值,关掉它反而会让等待变成长时间 hang,不解决根本问题
如何用 SHOW ENGINE INNODB STATUS 快速确认是死锁检测开销?
重点看三处输出:
-
---BUFFER POOL STATISTICS---中Pages made young和not young比值是否严重失衡(如not young占比超 95%)→ 表明缓冲池压力不大,排除 IO 型 CPU 消耗 -
BACKGROUND THREAD中Main thread state=sleeping→ 排除主线程忙于刷脏页等后台任务 -
TRANSACTIONS段末尾是否有密集的类似:------- TRX HAS BEEN WAITING 12 SEC FOR THIS LOCK TO BE GRANTED:...
连续出现 5 条以上,且锁对象高度重复(如都卡在PRIMARY上同一行)→ 这就是死锁检测高频触发的铁证
修复必须从应用层切入,不是调参数能绕过的
单纯调大 innodb_lock_wait_timeout 或关 innodb_deadlock_detect 只会让问题更隐蔽——请求堆积、响应延迟飙升,用户感知更差。
- 优先重构事务顺序:把热点行操作(如
UPDATE cinema_account SET balance = balance + ?)挪到事务**最后**执行,缩短锁持有时间 - 拆分热点:给影院账户加分片键(如按
cinema_id % 4分成 4 个逻辑账户),写请求分散到不同行 - 用乐观锁替代:对余额类场景,改用
UPDATE ... SET balance = ? WHERE id = ? AND balance >= ?+ 重试,避免行锁长期持有 - 绝对不要在事务里混杂网络 I/O 或慢查询——这会人为拉长锁持有窗口,放大争抢概率
死锁检测开销从来不是配置问题,而是事务设计暴露了锁粒度与业务节奏的错配。最危险的信号,是监控里 CPU 脉冲和 Trx has been waiting 日志增长完全同步——这时候再查慢 SQL 已经晚了,得立刻回溯代码里那几行 UPDATE 的上下文。











