innodb buffer pool 大小需按实际负载调优而非机械设为内存70–80%;应结合命中率、young/old区流动指标、实例数与cgroup限制综合判断,核心是保障热数据驻留young区且冷查询不污染。

innodb_buffer_pool_size 设为物理内存 70–80% 真的靠谱吗?
这个比例不是万能公式,而是针对「独占 MySQL 实例 + 没有大并发连接 + 数据集可缓存」的典型 OLTP 场景的经验起点。它成立的前提是:系统不跑其他内存大户(比如 Redis、Java 应用),且 innodb_buffer_pool_size 确实能装得下热数据。一旦你用的是容器环境、或启用了 innodb_buffer_pool_instances > 1 却没调好实例数,70% 反而会加剧 mutex 争用。
- 物理内存 64GB 的机器,别直接设
innodb_buffer_pool_size = 52G;先看SHOW ENGINE INNODB STATUS里Buffer pool hit rate是否稳定在 99%+ - 如果实例同时跑着 Elasticsearch,那留给 MySQL 的缓冲池顶多 40–50%,否则 OOM killer 很可能半夜杀掉
mysqld - 容器中部署时,
innodb_buffer_pool_size必须小于 cgroup memory limit,否则启动失败并报错Cannot allocate memory
怎么知道 buffer pool 真的被有效利用了?
别只盯命中率。InnoDB 的 LRU 列表分 young 和 old 两段,真正反映冷热分离效果的是 old_blocks_hit_rate 和 young_blocks_moved 这两个指标,它们藏在 INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STATS 里。
- 查询
SELECT pool_id, pages_data, pages_dirty, pages_old FROM INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STATS;,如果pages_old长期接近 0,说明 old 区根本没被填满,LRU 分割失效 -
SHOW ENGINE INNODB STATUS输出中找Buffer pool hit rate和Pages made young,后者过低(比如每秒 - 若
pages_made_not_young占比高(>30%),说明大量页面刚进 old 区就被淘汰,此时应调小innodb_old_blocks_pct(默认 37,可试 25)
为什么 buffer pool 调大后 QPS 反而跌了?
常见于高并发短连接场景。buffer pool 变大 → 每个 buffer chunk 更多 → innodb_buffer_pool_instances 默认值(通常是 8)跟不上 → 所有线程争抢同一 latch,OS WAIT ARRAY 中的 mutex 等待飙升。
- 检查
SHOW STATUS LIKE 'Innodb_buffer_pool_wait_free';,非零值说明有线程卡在等空闲页 - 当
innodb_buffer_pool_size > 16G,必须同步调大innodb_buffer_pool_instances,推荐按buffer_pool_size / 1G取整,但上限不超过 64 - 不要设
innodb_buffer_pool_instances = 1来“简化”,这等于把所有并发请求塞进一个单点瓶颈
监控 LRU 行为该看哪些具体字段?
核心不是总页数,而是页面在 young/old 区间的流动节奏。重点关注三个动态指标:
-
innodb_buffer_pool_pages_made_young:每秒有多少 page 被提前拉回 young 区(说明访问热点集中) -
innodb_buffer_pool_pages_made_not_young:每秒多少 page 在 old 区未被访问就淘汰(说明 old 区设置过大或扫描类查询太多) -
innodb_buffer_pool_read_requests与innodb_buffer_pool_reads的比值,持续低于 99.5 就得查磁盘 I/O 或 buffer pool 是否真不够
这些值在 SHOW GLOBAL STATUS 里实时可查,建议每 30 秒采样一次,画成趋势图——突降的 pages_made_young 往往早于慢查询报警出现。
实际调优永远从 workload 出发,而不是从内存百分比出发。buffer pool 不是越大越好,而是让 hot data 稳稳留在 young 区、cold scan 不污染它。这点容易被忽略:很多 DBA 调完 size 就停手,却没配好 innodb_old_blocks_time,结果全表扫描一跑,整个热区就被冲垮。










