innodb_buffer_pool_size并非越大越好,须预留足够内存给OS及其他进程,避免因available内存不足触发kswapd回收匿名页导致Swap;应监控/proc/zoneinfo中各node的nr_inactive_anon与free pages差值。

MySQL执行SQL时触发Swap,不是因为内存不够,而是内存分配不均或被系统强制换出——关键在Buffer Pool配置和NUMA内存绑定,而非盲目加内存或关swap。
innodb_buffer_pool_size设多大才不触发Swap
这个值不是越大越好,也不是按物理内存百分比硬套。它必须留出足够空间给OS、其他进程、以及内核页表等开销。常见错误是设到70%甚至80%,结果OS只剩不到2GB可用内存,直接触发kswapd回收匿名页(即MySQL的Buffer Pool页),开始swap out。
- 用
free -g看真实空闲内存(available列),不是free列;如果available - 生产环境建议:Buffer Pool上限 =
available× 0.7,且不超过物理内存的60% - 不要跨NUMA节点分配:若服务器有2个NUMA node,
innodb_buffer_pool_size设为单node本地内存的60%~70%,比如每个node有64GB,则设为40GB,而不是设80GB让内核跨node分配 - 检查是否生效:
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';和SHOW ENGINE INNODB STATUS\G中看Buffer pool size是否匹配
numactl --interleave all 或 --membind=0 怎么选
二者解决的是不同层级的问题:--interleave all 是让MySQL内存分配在所有NUMA node上轮询,缓解单node内存耗尽;--membind=0 是强制只用node 0,适合你确认业务负载集中在CPU 0-7且node 0内存充足的情况。但后者风险高——如果node 0真被占满,MySQL会立刻OOM或强走swap。
- 优先用
numactl --interleave all /usr/bin/mysqld启动(修改mysqld_safe或 systemd service 文件) - 验证是否生效:
numastat -p $(pgrep mysqld),看各node的Heap和Stack是否相对均衡;若node0占比超90%,说明没生效 - MySQL 5.6.27+ 可直接在my.cnf中加
innodb_numa_interleave = ON,比shell层numactl更可靠 - 注意:Docker容器内使用numactl需加
--cap-add=SYS_ADMIN,否则报Operation not permitted
为什么设置了O_DIRECT 还在swap
innodb_flush_method=O_DIRECT 只影响InnoDB数据文件的读写路径(绕过page cache),但它**完全不控制Buffer Pool本身的内存驻留行为**。Buffer Pool分配的是匿名页(anon page),而Linux对匿名页的回收策略就是swap——哪怕你禁了page cache,只要内核判定内存压力大,照样把Buffer Pool页swap出去。
- swap发生时,
vmstat 1看so(swap out)持续非零,同时cat /proc/vmstat | grep pgpgout增长快,说明是匿名页在被换出 - O_DIRECT真正价值是避免double buffering(InnoDB buffer + OS cache),减少内存浪费,但不能替代合理的Buffer Pool sizing和NUMA绑定
- 别信“设了O_DIRECT就不用管swap”的说法——线上踩坑案例里,70%的swap问题都发生在已启用O_DIRECT的实例上
临时禁用swap不是解法,但swappiness=0也有陷阱
vm.swappiness=0 的本意是“仅在内存彻底耗尽时才swap”,但Linux内核在满足 file + free ≤ high 水位时,仍会强制swap匿名页(见/proc/zoneinfo)。这意味着即使available还有5GB,只要大量cache堆积在某个NUMA node上,其他node空闲,系统仍可能触发swap。
- 设
vm.swappiness=1比=0更稳妥:它允许内核优先回收file cache,而非立刻碰匿名页 -
swapoff -a只能临时缓解,且必须确保free -m的available> Buffer Pool当前占用,否则MySQL瞬间OOM - 真正要盯的是
/proc/zoneinfo中各node的nr_inactive_anon和pages free差值——差值
最易被忽略的一点:Buffer Pool内存不是“分配即锁定”。Linux默认允许将匿名页swap,除非显式用mlock()锁住——但MySQL不提供该能力,也**不该用**(会导致OOM killer误杀)。所以根本解法永远是:让Buffer Pool大小与NUMA局部内存匹配 + 让内存分配策略匹配硬件拓扑,而不是指望OS不swap。











