关于内存异常的讨论
简单来说,这是一个发生在 MySQL 5.7 及其之前版本,在新版 Linux 内核(如 openEuler)上的已知 Bug。
Bug 编号与版本:这是一个在 MySQL 官方 Bug 系统有记录的已知问题 Bug#96525。它影响了 MySQL 5.7 及更早的版本,而在 MySQL 8.0.19/8.0.20 及之后版本中已被修复。
触发机制:新版的 Linux 内核(以及 Docker)会给进程分配一个异常大的文件描述符限制值(例如 1073741816)。MySQL 5.7 在处理这个巨大的数值时存在逻辑缺陷,它会错误地根据这个数值来申请一块巨大的内存空间,从而导致内存瞬间飙升到数 GB 甚至数十 GB。
解决方案
社区给的解决办法(在 Docker 启动时加 –ulimit nofile=…)是合理且常用的临时/部署层解决方案;长期方案可以是升级到包含修补的 MySQL 版本(8.0.19+ 的修补)。
在 docker-compose.yml 文件中 添加 ulimits配置
version: '3.4'
services:
mysql:
image: mysql:5.7.31-arm64
container_name: test-mysql
command: --default-authentication-plugin=mysql_native_password
restart: always
# 加入配置
ulimits:
nofile:
soft: 1048576 # 软限制,进程可以超过,但最大不能超过硬限制
hard: 1048576 # 硬限制,进程无论如何都不能超过的上限
environment:
MYSQL_ROOT_PASSWORD: 123456
networks:
- test_net
ports:
- "3306:3306"
volumes:
- ./volumes/mysql/data:/var/lib/mysql
- ./volumes/mysql/conf.d/my_custom.cnf:/etc/mysql/conf.d/my_custom.cnf也有相关资料显示,可以设置 Docker 守护进程的 LimitNOFILE,但我测试并未生效,可以自行尝试,设置过程如下
- 找到 Docker 服务配置文件:Docker 守护进程的配置文件通常位于
/etc/systemd/system/docker.service 或 /lib/systemd/system/docker.service。
- 找到 Docker 服务配置文件:Docker 守护进程的配置文件通常位于
- 修改配置:使用
sudo权限编辑该文件。在[Service]部分下,找到或以添加LimitNOFILE行,将文件描述符限制设置为一个合理值,比如1048576:[Service] ... (其他配置) LimitNOFILE=1048576 ... (其他配置)
- 修改配置:使用
- 重启 Docker 服务:保存文件后,需要重新加载配置并重启 Docker 服务,使修改生效。
sudo systemctl daemon-reload sudo systemctl restart docker
- 重启 Docker 服务:保存文件后,需要重新加载配置并重启 Docker 服务,使修改生效。
测试
重新构建容器之后,进入MySQL容器,输入下面的命令查看限制是否生效
ulimit -n如果显示值与配置的值相同,则表示已经生效,此时再查看内存情况,不会出现内存异常的问题。


