innodb buffer pool 实例数过小是并发瓶颈主因,因全局锁导致线程串行化排队;调大 innodb_buffer_pool_instances 可分拆锁热点,每个实例拥有独立页哈希表与局部锁;在线调整 buffer pool size 时需满足 chunk 粒度约束,否则易触发 oom。

innodb_buffer_pool_instances 设置过小是主因,不是配置不够或 SQL 写得差,而是锁争用没拆开。
Buffer Pool 全局锁是并发瓶颈的根源
MySQL 5.7 默认 innodb_buffer_pool_instances = 1,哪怕你设了 16G 缓冲池,所有线程访问页时都得抢同一把 buf_pool_mutex。这不是 CPU 不够,是串行化排队——SHOW ENGINE INNODB STATUS\G 的 SEMAPHORES 段里反复出现 buf0buf.cc 行号,基本就是它。
为什么调大 innodb_buffer_pool_instances 能缓解
每个实例有自己独立的页哈希表、内存块和局部锁。线程访问某页时由哈希函数决定归属哪个实例,只争那一小块锁:
-
instances从 1 改成 8,理论锁热点被切分 8 份 - 5.7+ 在
innodb_buffer_pool_size > 1G时默认设为 8,是有依据的 - 手动设回
1,再大的 buffer pool 也白搭
在线改 innodb_buffer_pool_size 时容易踩的坑
MySQL 5.7 把 buffer pool 拆成固定大小的 chunk 管理,默认 innodb_buffer_pool_chunk_size = 128MB。生效值必须满足:
innodb_buffer_pool_size = innodb_buffer_pool_chunk_size × innodb_buffer_pool_instances × N
所以:
- 设
SET GLOBAL innodb_buffer_pool_size = 1500M,当前instances = 8→ 最小粒度是128 × 8 = 1024M→ 实际生效为2048M - 在 2GB 虚机上极易触发 OOM killer 杀掉
mysqld - 查完
@@innodb_buffer_pool_instances后,一定要手算最小粒度再设值,别信 SET 返回 OK 就真 OK 了
信号量等待常被误判为 SQL 或索引问题
现象很像性能问题:QPS 上不去、Threads_running 居高不下、慢查询增多。但真实瓶颈可能藏在底层:
-
Buffer pool hit rate仍是 99%,说明缓存有效 -
Created_tmp_disk_tables没飙升 -
SHOW PROCESSLIST里一堆线程卡在statistics或query end状态
这时候翻 SEMAPHORES 段比优化 SQL 更快见效——尤其当等待堆栈反复指向 buf0buf.cc、btr0sea.cc 或 row0ins.cc 时,别犹豫,先动 instances 和 chunk_size。











