在低配置服务器(如 1核 1G / 1核 2G 的云服务器)上运行 MySQL 8.0 Docker 镜像时,经常会遇到容器无限重启、数据文件被锁等隐蔽问题。本文结合一次真实的排查过程,记录从 OOM 崩溃(Exit Code 137) 到 文件锁冲突(Error 11) 的完整踩坑与解决路径。
启动 MySQL 容器后,查看日志 docker logs -f mysql-docker,发现初始化到 InnoDB 步骤时中断:
mysql-docker | ... [System] [MY-013576] [InnoDB] InnoDB initialization has started.
mysql-docker exited with code 137 (restarting)
Exit Code 137 对应 Linux 信号 128 + 9 (SIGKILL),代表进程被 Linux 内核的 OOM Killer(内存溢出杀死机制) 强制终止了。
MySQL 8.0 默认启动配置对内存要求较高,初始化 InnoDB 时会预分配较大的 Buffer Pool。当宿主机可用内存不足时,内核为了防止系统宕机,会直接杀死占用内存最大的 mysqld 进程。
在宿主机运行以下命令即可确认是否为内存问题:
# 查看宿主机系统内核日志
dmesg -T | grep -i oom
# 查看 Docker 是否记录了 OOM
docker inspect mysql-docker --format='{{.State.OOMKilled}}'
如果输出 true 或包含 Killed process ... (mysqld),则确定为内存溢出。
在对容器限制内存或强杀容器重启后,日志可能会出现新的报错:
[ERROR] [MY-012574] [InnoDB] Unable to lock ./ibdata1 error: 11
- Error 11 (
EAGAIN / Resource temporarily unavailable):说明数据文件ibdata1已经被另一个进程加了写锁(Write Lock)。 - 产生原因:当上一次容器因为 OOM 突然崩溃时,后台可能残留了未完全退出的孤儿进程;或者旧容器虽然停止了,但系统底层仍持有着对挂载卷的文件句柄。
使用 lsof 查看谁占用了 ibdata1:
# 查出占用 ibdata1 的进程
lsof /var/lib/mysql/ibdata1
输出示例:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mysqld 429692 systemd-coredump 9uW REG 253,1 12582912 31823670 /var/lib/mysql/ibdata1
- 标识解读:
9uW中的W代表 Write Lock(写锁),证明 PID429692独占了文件。 - 用户解释:
systemd-coredump是由于 Docker 容器内的mysql用户 UID(如 999)映射到了宿主机的对应账户名,进一步证实这是上次崩溃残留的容器进程。
针对以上两个问题,正确的处理顺序是:清理残留锁进程 -> 优化 MySQL 配置 -> 配置容器内存与 Swap。
在宿主机强杀残留的 mysqld 进程:
# 1. 强杀残留进程
kill -9 429692
# 2. 清理旧容器
docker stop mysql-docker && docker rm mysql-docker
小内存环境下运行 MySQL 8.0,必须限制内存开销。建议调小 InnoDB 缓冲池并关闭 Performance Schema:
--innodb-buffer-pool-size=128M(或 256M):将缓冲池降低到合理范围(默认值往往是 1G 或更多)。--performance-schema=OFF:关闭性能监控,可直接省出 200MB~400MB 内存。
docker run -d \
--name mysql-docker \
--restart=always \
--memory=1g \
-v /var/lib/mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=your_password \
mysql:8.0 \
--innodb-buffer-pool-size=128M \
--performance-schema=OFF
version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: mysql-docker
restart: always
deploy:
resources:
limits:
memory: 1024M # 限制容器最大内存
command:
- --innodb-buffer-pool-size=128M
- --performance-schema=OFF
environment:
MYSQL_ROOT_PASSWORD: your_password
volumes:
- ./data:/var/lib/mysql
如果物理内存只有 1GB,建议添加 2GB 的 Swap(交换分区)防止内存突发溢出被 OOM 杀死:
# 创建并启用 2GB Swap 文件
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 永久生效(追加到 /etc/fstab)
echo '/swapfile swap swap defaults 0 0' | sudo tee -a /etc/fstab
- 退出码 137 = 内存不足被内核杀掉 (OOM),排查优先级看
dmesg。 - 错误 11 (Unable to lock) = 进程残留或锁未释放,优先用
lsof查 PID 并强杀。 - 低配服务器必备配置:降低
innodb-buffer-pool-size+ 关闭performance-schema+ 开启系统Swap,三管齐下可让 MySQL 在 1G 内存的轻量云服务器上稳定运行。
