Tiusx

MySQL热点行并发更新导致lock_wait_suspend_thread死循环性能骤降

· 开发

适用环境

  • MySQL 5.7.20 ~ 5.7.27(5.7.28 之前版本)
  • 高并发更新同一行记录(秒杀库存扣减场景)

问题现象

某互联网公司订单系统,秒杀活动开始后,库存更新SQL响应时间从平均2ms飙升至30秒以上。 show processlist 大量线程状态为 updating,16核服务器CPU使用率飙升至800%。

排查过程

  1. 执行 show engine innodb status;,输出存在大量锁等待记录,LATEST DETECTED DEADLOCK 为空,没有死锁。
  2. 通过 performance_schema 采集锁事件,lock_wait_suspend_thread 事件占比异常偏高。
  3. 将MySQL升级到5.7.28测试,故障现象完全消失。
  4. 查阅官方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版本。