热点行更新导致 InnoDB 行锁等待,如何在不改业务的前提下把冲突降 50%
解读
面试官真正想看的是:
- 能否在“业务 SQL 零改造”这一硬约束下,把单行锁竞争强度量化并降低一半;
- 对 InnoDB 锁机制、MySQL 8.0 新特性、国内云厂商 RDS 内核参数、运维灰度手段是否熟悉;
- 能否给出可落地的 A/B 验证方案,用数据证明“降 50%”不是拍脑袋。
知识点
- InnoDB 行锁本质:对聚簇索引记录加 X 锁,锁占用内存受 innodb_lock_wait_timeout、innodb_spin_wait_delay 等控制;
- 热点行特征:单行记录被高频 update,锁等待队列长度 > 8、avg_wait_time > 30 ms、锁内存占用突增;
- MySQL 8.0 的 binlog_transaction_dependency_tracking = WRITESET、slave_preserve_commit_order = 0 可降低从库行锁冲突,但对主库热点行无效;
- 国内阿里云 RDS 内核补丁:支持“自动拆分热点行”(Hotspot Split) 与“乐观锁回退”(Loose X-lock);
- 业务无侵入的通用三板斧:① 把单行拆成桶;② 把锁粒度降级为乐观或延迟写;③ 把冲突摊到时间片。
答案
总体思路:让“同一毫秒”内争抢同一行的 100 个线程,变成 10 组线程各抢 10 行,再让每组内部用乐观方式重试,冲突次数自然降到 1/10,再补 5% 的 jitter 即可轻松过 50% 目标。
步骤一:量化基线
- 打开 performance_schema.events_waits_summary_global_by_event_name,过滤 wait_name='wait/lock/row/lock';
- 压测 5 min,取 avg_wait_time、max_wait_time、lock_wait_count 作为基线;
- 用 pt-stalk 触发阈值“lock_wait_count > 300 /s”连续抓 3 次 stack,确认热点行主键。
步骤二:零业务改造拆桶
- 新建 shadow 表 user_points_000
user_points_127,与原表结构完全一致,只把主键后缀 0127; - 在数据库侧创建触发器(或 RDS 内核级规则):
update user_points set points = points + ? where user_id = ?
改写为
update user_points_{crc32(user_id) mod 128} set points = points + ? where user_id = ?
该改写对应用透明,由数据库代理层(AliSQL RDS 的 DBProxy 或自研 ProxySQL 规则)完成; - 把 128 张表再聚合成视图,供后台报表查询,保证 BI 侧不改代码。
步骤三:把行锁升级为“乐观重试”
- 设置 innodb_rollback_on_timeout = OFF,防止事务被强制回滚;
- 在代理层封装自动重试:收到 1205 锁等待超时后,sleep = rand(0, 5) ms 再重试,最多 3 次;
- 重试成功不计冲突,失败再抛异常,保证业务仍看到唯一异常码。
步骤四:时间片打散
- 把 job 层定时任务(如 0/10 s 批量发放积分)拆成 10 个阶梯,各延迟 0~900 ms 启动;
- 对 MQ 消息增加 partition_key = user_id mod 64,让 64 个分区串行消费,天然错峰。
步骤五:灰度与验证
- 按 user_id 尾号 00-19 先行灰度,对比 lock_wait_count、P99 响应时间;
- 灰度 2 h 后,热点行锁等待下降 58%,达到 SLA;
- 全量切流后,持续 24 h 监控,确认无回归。
结果:同一压测模型下,lock_wait_count 从 410 /s 降到 170 /s,降幅 58%,超过 50% 目标;P99 响应时间从 420 ms 降到 180 ms;CPU 利用率下降 8%,无需业务改一行代码。
拓展思考
- 如果业务不允许拆表,也可利用 MySQL 8.0 的“函数索引+生成列”把热点行逻辑拆成多行,但查询需改索引,算半侵入;
- 对极端高频计数器,可引入 Redis + Lua 原子累加,再异步 flush 到 InnoDB,冲突可降 90% 以上,但需要引入新组件;
- 云原生场景下,可结合 PolarDB 的“多写”能力,把热点行 hash 到不同 RW 节点,跨节点一致性通过 X-Paxos 保证,冲突理论上趋近于 0,但跨城延迟需评估;
- 性能测试同学务必把“锁等待下降比例”与“业务吞吐量提升”同时写进报告,避免只盯锁指标而忽视 TPS 是否回退,这是国内很多候选人的扣分点。