调小innodb_lock_wait_timeout会加剧应用卡顿,因其仅加速事务失败而非减少锁,导致重试频繁、日志暴增、CPU和连接数飙升;应优先优化锁粒度、持有时间及SQL逻辑。

为什么 innodb_lock_wait_timeout 调小反而让应用更卡?
它只控制「等锁超时时间」,不减少锁本身。设成 1 秒,不是让锁变短,而是让事务更快失败——结果是重试更频繁、日志里满屏 Lock wait timeout exceeded,CPU 和连接数反而飙升。
真正要动的是锁的粒度和持有时间:
-
innodb_row_lock_time_avg和innodb_row_lock_waits这俩状态值必须先查,确认是不是真有行锁争用(不是所有“慢”都怪锁) - 业务层能用
SELECT ... FOR UPDATE NOWAIT就别用默认阻塞式加锁,避免线程卡在等待队列里 - 批量更新尽量按主键顺序执行,乱序更新容易引发间隙锁升级和死锁
innodb_buffer_pool_size 设太大,为什么并发写反而变慢?
Linux 内存页回收机制在 Buffer Pool 占用超 75% 物理内存时会触发 kswapd 频繁扫描,导致 I/O 等待升高;同时 InnoDB 自己的 LRU 淘汰逻辑在大池子里响应变钝,脏页刷盘节奏紊乱。
实操建议:
- 生产环境保守设为物理内存的 50%–60%,8GB 机器别硬塞 6GB
- 如果实例混跑其他服务(比如 Redis、Java 应用),再往下压 5–10%
- 配合
innodb_buffer_pool_instances = 8(>= 8GB 时),避免单个 LRU 链表锁竞争
间隙锁(Gap Lock)在什么场景下必须关?怎么安全关?
唯一明确能关的场景:业务确定不用可重复读(RR)隔离级别,且已验证读已提交(RC)下不会出现幻读问题——比如纯日志类、报表类只读库,或订单号由雪花算法生成、绝无范围插入的写入链路。
关法很直接,但副作用明显:
- 改配置
transaction_isolation = 'READ-COMMITTED',重启生效(SET命令不持久) - RC 下
UPDATE/DELETE语句不再加 gap lock,但唯一索引等值查询仍会加 record lock - 注意:半一致性读(semi-consistent read)开启后,
UPDATE可能跳过已被其他事务修改但未提交的行,导致更新丢失
innodb_thread_concurrency 设成 0 还是 32?实际效果差很多
这个参数本质是 InnoDB 层的「协程调度门禁」,不是 CPU 核数。设 0 表示不限流,所有线程自由进入内核队列;设 32 则强制排队,但排队逻辑老旧,容易造成空转等待。
现代 SSD + 多核场景下更推荐:
- 保持默认 0,靠 OS 调度和连接池(如 HikariCP 的
maximumPoolSize)控并发量 - 若观察到
innodb_mutex_spin_waits明显偏高,再尝试设为 CPU 核数 × 2(非物理核数) - 绝对不要设成 1 或 2——这不是“更串行就更安全”,而是人为制造瓶颈
锁冲突从来不是单个参数能解决的事。最常被跳过的动作是:检查 SQL 是否走了索引、是否在事务里干了不该干的事(比如调外部 HTTP)、有没有没 commit 的长事务占着锁不放。参数只是兜底,代码才是源头。



















