mysql被oom killer杀掉主因是innodb_buffer_pool_size超memavailable且未预留os/agent/脚本空间,需用cat /proc/meminfo | grep memavailable校准,并监控innodb_buffer_pool_wait_free>0及命中率

MySQL 被 OOM Killer 杀掉,90% 以上是 innodb_buffer_pool_size 吃得太满,且没给系统、agent、backup 留余量——不是配置太小,而是设得“太准”又没校准真实可用内存。
怎么看是不是 innodb_buffer_pool_size 撑爆了系统?
别只信 free -h 的 MemTotal,它在云主机(比如 AWS t3/t4、阿里云共享型)上严重虚高。真正该盯的是内核当前能立刻分配的内存:
-
cat /proc/meminfo | grep MemAvailable:这个值才是你敢分给 MySQL 的“硬上限” -
ps aux --sort=-%mem | head -5:确认mysqld是否真排第一;如果不是,先杀掉那个 Python/Java/Node 进程 -
SHOW ENGINE INNODB STATUS\G里搜Innodb_buffer_pool_wait_free:如果 > 0,说明 page cleaner 已经跟不上淘汰速度,buffer pool 卡死在极限边缘 -
dmesg -T | grep -i "killed process" | grep mysqld:看到类似Kill process 1234 (mysqld) score 956就是 OOM Killer 下的手
怎么安全在线调小 innodb_buffer_pool_size?
重启前必须压住内存,否则下次启动直接失败。MySQL 5.7+ 支持在线调小,但有硬约束:
- 单位必须是字节:
SET GLOBAL innodb_buffer_pool_size = 2147483648(即 2GB),写2G会报错 - 新值必须是
innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances的整数倍(默认 chunk_size=128MB,instances=8 → 最小步进 1024MB) - 调小过程是渐进释放,查
SHOW STATUS LIKE 'Innodb_buffer_pool_resize_status'看进度,别中断连接 - 永久生效仍需改配置文件:
innodb_buffer_pool_size = 2G(这里可以带单位),但注意:这个值只在下次重启后固化
为什么调小了 innodb_buffer_pool_size 还 OOM?盯这三个非 buffer pool 内存源
innodb_buffer_pool_size 是大头,但不是全部。OOM 常见真凶其实是这些“配角”:
-
performance_schema开了全量内存监控:performance-schema-instrument = 'memory/% = COUNTED'会让memory/sql/sp_head::main_mem_root单项吃掉几 GB——关掉或至少限制为'memory/sql/% = COUNTED' -
table_open_cache+table_open_cache_instances:高并发下每个 instance 都缓存一份表结构;若大量触发器/存储过程,table_open_cache_instances设太高(如 16)会成倍放大sp_head内存占用——混合部署建议设为 1 或 4 - per-connection 缓冲区爆炸:
sort_buffer_size、join_buffer_size、tmp_table_size×max_connections。比如max_connections=500且sort_buffer_size=4M,光这一项就可能吃掉 2GB
监控必须落地到两个关键指标,而不是只看“用了多少”
光看 Innodb_buffer_pool_pages_total 和 pages_free 没用,要盯实际压力信号:
- 缓冲池命中率:
SHOW STATUS LIKE 'Innodb_buffer_pool_read%';算(1 - Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests),持续低于 95% 才说明真缺内存;高于 99% 还设那么大,就是浪费 - 等待释放页:
Innodb_buffer_pool_wait_free必须为 0,哪怕只是偶尔 > 0,都代表 buffer pool 已逼近临界点,再涨一点就会卡死 - 别忽略隐性开销:数据字典内存(
show engine innodb status里搜dictionary memory allocated)、连接线程栈、jemalloc 元数据——它们不归 buffer pool 管,但一样吃MemAvailable
最易被忽略的一点:调整完 innodb_buffer_pool_size 后,一定要用 mysqld --defaults-file=/etc/my.cnf --verbose --help | grep buffer_pool 验证配置是否真被加载——systemd 环境变量、mysql.server 脚本、宝塔面板自动生成的覆盖配置,都可能让你的修改静默失效。











