行锁等待本身不耗CPU,但会引发高上下文切换和内核态争用:表现为% sy异常升高、cs飙升超20k/s,根源在于死锁检测O(N²)遍历、锁队列维护及mutex自旋,需结合performance_schema与系统指标交叉定位。

行锁等待本身不耗CPU,但会引发高上下文切换和内核态争用
行锁等待(如 Waiting for row lock 或 Locked)在 SHOW PROCESSLIST 或 performance_schema.data_lock_waits 中表现为线程阻塞,但它本身几乎不消耗用户态 CPU(%us)。真正让 CPU 拉满的是系统为维持大量阻塞线程所付出的调度代价:线程频繁唤醒/休眠、锁队列遍历、死锁检测循环、事务状态同步等操作全在内核态完成。此时 top 显示的往往是异常高的 %sy(内核态 CPU),而非 %us。
为什么几十个锁等待就能拖垮CPU
MySQL 的行锁管理不是静态查表,而是动态维护哈希链表 + 等待图(wait-for graph)。当出现锁冲突时:
- 每个新请求都要遍历当前所有锁等待链,判断是否成环(死锁检测)——这是 O(N²) 量级的计算
- InnoDB 每秒可能执行数百次
lock_deadlock_check,尤其在高并发 UPDATE/DELETE 场景下 - 大量线程卡在
srv_conc_enter_innodb等函数入口,反复尝试获取kernel_mutex或trx_sys->mutex,触发密集自旋 -
vmstat 1中cs(context switch)常突破 20k/s,远超常规业务负载
如何区分是锁等待还是慢SQL导致的CPU飙升
关键看三组指标组合:
- 如果
top中%sy > 40%且wa < 5%,同时vmstat的cs飙升 → 锁争用主导 - 如果
%us > 70%且PROCESSLIST中大量Sorting result、Sending data→ 计算型慢 SQL 主导 - 执行
SELECT * FROM performance_schema.events_waits_summary_global_by_event_name WHERE EVENT_NAME LIKE 'wait/synch/mutex/innodb/%' ORDER BY COUNT_STAR DESC LIMIT 5;,若trx_sys->mutex或lock_mutex排前三 → 锁系统已成瓶颈
临时止血比优化SQL更紧迫
锁等待引发的 CPU 飙升有雪球效应:一个长事务 hold 住行锁 → 后续 N 个请求排队等待 → 死锁检测开销指数增长 → 内核调度压力暴涨 → 更多线程无法及时释放 → 连接池打满。此时:
- 优先用
KILL QUERY [id]终止正在做UPDATE或DELETE的源头线程(别杀Sleep连接) - 检查
INFORMATION_SCHEMA.INNODB_TRX中TRX_STATE = 'LOCK WAIT'的事务,顺藤摸瓜找到TRX_WAITING_TRX_ID对应的持有者 - 紧急设置
innodb_lock_wait_timeout=3(默认 50),避免等待无限累积(注意应用层需捕获ERROR 1205) - 不要调大
innodb_buffer_pool_size—— 锁问题跟缓存大小无关,反而可能挤占 OS 调度资源
锁等待导致的 CPU 100% 往往藏得深:它不体现在慢日志里,SHOW PROCESSLIST 中的 INFO 字段还可能是空的,必须结合 performance_schema 和系统级指标交叉验证。最危险的是误判为“只是SQL慢”,结果花两小时优化索引,而真实瓶颈早就在内核锁队列里烧穿了。


















