mysql5.7在docker环境中运行内存异常修复

鸿辰 Linux 12

关于内存异常的讨论

简单来说,这是一个发生在 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,但我测试并未生效,可以自行尝试,设置过程如下

    1. 找到 Docker 服务配置文件:Docker 守护进程的配置文件通常位于
      /etc/systemd/system/docker.service
      或
      /lib/systemd/system/docker.service。
    1. 修改配置:使用 sudo 权限编辑该文件。在 [Service] 部分下,找到或以添加 LimitNOFILE 行,将文件描述符限制设置为一个合理值,比如 1048576
      [Service]
      ... (其他配置)
      LimitNOFILE=1048576
      ... (其他配置)
    1. 重启 Docker 服务:保存文件后,需要重新加载配置并重启 Docker 服务,使修改生效。
      sudo systemctl daemon-reload
      sudo systemctl restart docker

测试

重新构建容器之后,进入MySQL容器,输入下面的命令查看限制是否生效

ulimit -n

如果显示值与配置的值相同,则表示已经生效,此时再查看内存情况,不会出现内存异常的问题。

标签: mysql docker 内存