先确认oom killer是否动手:执行dmesg | grep -i "killed process" | grep mysqld,若输出含out of memory: killed process xxx (mysqld),再结合docker inspect容器 --format='{{.state.oomkilled}}'为true且退出码137,即可确证;随后须设docker内存硬限(如--memory=512m)并同步收紧my.cnf中innodb_buffer_pool_size(≤容器内存60%~70%)、max_connections等参数,改完重启容器并验证生效。

确认是不是OOM Killer干的
别急着调MySQL配置,先看日志。执行 dmesg | grep -i "killed process" | grep mysqld,如果输出里有类似 Out of memory: Killed process 12345 (mysqld),就坐实了——不是MySQL自己崩溃,是Linux内核把它杀了。
再补一手验证:docker inspect mysql-container --format='{{.State.OOMKilled}}' 返回 true,且退出码是 137(128 + 9),基本可以闭眼断定是内存超限触发的强制终止。
- 宿主机
free -h显示可用内存很低、swap为0,风险极高 -
docker stats mysql-container看峰值内存是否贴近你设的--memory值 - 注意:即使
docker stats显示当前内存不高,也可能有瞬时尖峰被cgroup截断并触发OOM
给MySQL容器加硬性内存限制
没设 --memory 就等于裸奔。Docker默认不限制,MySQL会按配置文件拼命吃内存,直到系统扛不住。
重启容器时必须带上内存上限,例如:
docker run -d \ --name mysql \ --memory=512m \ --memory-swap=512m \ -e MYSQL_ROOT_PASSWORD=123456 \ -v ./my.cnf:/etc/mysql/conf.d/my.cnf \ -p 3306:3306 \ mysql:8.0
-
--memory是硬限制,超了直接被杀;--memory-swap=512m表示禁用swap(设成和memory相等),避免IO拖慢 - 数值别拍脑袋:2GB宿主机建议 ≤ 512m,4GB宿主机可设到1G~1.2G,留足空间给系统和其他进程
- 千万别漏掉
--memory-swap,否则Docker可能允许使用无限swap,反而让OOM更隐蔽
同步收紧MySQL内部内存参数
只靠Docker限制不够。MySQL启动后还会按 my.cnf 里的配置分配内存,比如 innodb_buffer_pool_size 默认可能占到2GB以上,远超容器限制。
在挂载进容器的 my.cnf 文件中,明确写死关键参数:
[mysqld] innodb_buffer_pool_size = 256M max_connections = 50 sort_buffer_size = 256K join_buffer_size = 256K tmp_table_size = 16M max_heap_table_size = 16M
-
innodb_buffer_pool_size必须 ≤ 容器--memory的 60%~70%,且是innodb_buffer_pool_chunk_size(默认128M)的整数倍 -
max_connections要配合连接缓冲区算总账:50 × (256K + 256K + 16M) ≈ 800MB,已逼近512M限制,所以必须压低 - 删掉已弃用的
query_cache_size和冗余的key_buffer_size,它们也抢内存
别信“在线调参”能救急
SET GLOBAL innodb_buffer_pool_size = 256*1024*1024 看起来快,但实际坑多:
- 该值必须是
innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances的整数倍,否则MySQL自动向下取整,你根本不知道它设成了多少 - 仅改运行时参数,容器重启后失效;而OOM常发生在重启瞬间,此时旧配置仍生效
- 某些版本(如MySQL 5.7之前)根本不支持在线调整buffer pool size
- 临时降低后,若没同步改配置文件,下次重启还是爆
真正可靠的做法只有:改 my.cnf → 重启容器 → 验证 SHOW VARIABLES LIKE 'innodb_buffer_pool_size';。
最容易被忽略的一点:Docker容器里MySQL读的是 /etc/mysql/conf.d/ 下的配置,不是镜像内置的 /etc/mysql/my.cnf;挂载错路径或文件权限不对,会导致配置完全不生效。











