MySQL热点行并发更新导致lock_wait_suspend_thread死循环性能骤降
· 开发
适用环境
- MySQL 5.7.20 ~ 5.7.27(5.7.28 之前版本)
- 高并发更新同一行记录(秒杀库存扣减场景)
问题现象
某互联网公司订单系统,秒杀活动开始后,库存更新SQL响应时间从平均2ms飙升至30秒以上。
show processlist 大量线程状态为 updating,16核服务器CPU使用率飙升至800%。
排查过程
- 执行
show engine innodb status;,输出存在大量锁等待记录,LATEST DETECTED DEADLOCK为空,没有死锁。 - 通过 performance_schema 采集锁事件,
lock_wait_suspend_thread事件占比异常偏高。 - 将MySQL升级到5.7.28测试,故障现象完全消失。
- 查阅官方Release Notes,确认该版本修复InnoDB锁唤醒机制缺陷 Bug #29807653。
根本原因
大量线程并发争抢同一行记录锁时,InnoDB内部 lock_wait_timeout_thread 负责唤醒等待线程。
旧版本存在缺陷:大量等待线程获得锁或者超时退出时,唤醒逻辑在 lock_wait_suspend_thread 入口发生无效自旋(spin),造成CPU空转,业务SQL执行被严重阻塞。
解决方案
方案一:升级MySQL版本(首选)
升级至 5.7.28+ 或者 8.0.18+,版本内置锁唤醒逻辑优化补丁。
方案二:业务层削峰打散热点行
把热点库存拆分为多行,例如库存拆成10份,业务随机选择行执行更新,分散锁竞争压力。
方案三:应用层串行排队
- Redis队列把并发更新请求串行处理
- 使用
SELECT ... FOR UPDATE搭配GET_LOCK()实现应用层锁排队
影响范围
该问题只有热点行激烈锁竞争场景才会触发,普通业务更新不受影响。秒杀、抢购类业务务必核查MySQL版本。