buffer pool全局锁是并发瓶颈根源,innodb_buffer_pool_instances通过分实例解耦锁竞争,避免所有线程争抢同一把buf_pool_mutex;实例数需与chunk_size匹配,否则size设置会向上取整引发oom。

Buffer Pool全局锁是并发瓶颈的根源
MySQL 5.7 的 innodb_buffer_pool_size 再大,线程一多就卡在锁上——因为默认单实例配置下,所有线程访问缓冲池都得抢同一把全局锁(buf_pool_mutex)。这不是 CPU 不够,是串行化等待。你在 SHOW ENGINE INNODB STATUS\G 的 SEMAPHORES 段看到大量 RW-latch created in file buf0buf.cc,基本就能确认是它在拖慢吞吐。
innodb_buffer_pool_instances 不是“锦上添花”,而是解耦锁的关键
每个实例有自己独立的内存块、页哈希表和局部锁。线程访问某页时,由哈希函数决定落在哪个实例上,只争那一小块的锁。这意味着:
- 实例数从 1 增到 8,理论锁竞争热点被拆成 8 份
- MySQL 5.7+ 在 innodb_buffer_pool_size > 1G 时默认设为 8,不是随意定的
- 但如果你手动设了 innodb_buffer_pool_instances = 1,哪怕 buffer pool 是 16G,也还是单点锁
在线调整 size 时,instances 必须同步匹配,否则值会“悄悄变大”
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
Buffer Pool 竞争常被误判为 SQL 或索引问题
现象很像性能问题:QPS 上不去、慢查询增多、Threads_running 居高不下。但真实瓶颈可能藏在底层——比如 Buffer pool hit rate 仍是 99%,说明缓存有效;Created_tmp_disk_tables 也没飙升;可 SHOW PROCESSLIST 里一堆线程卡在 statistics 或 query end 状态。这时候该看 innodb_buffer_pool_wait_free 和 innodb_buffer_pool_resize_status,而不是急着加索引或改 SQL。











