mysql无硬性内存上限,需通过cgroup v2的memory.max实现硬隔离;innodb_buffer_pool_size是主要内存消耗项,per-connection参数需谨慎配置;systemd memorymax=4g为裸机推荐方案。

MySQL 进程本身不支持直接配置内存上限
MySQL 没有类似 max_memory_mb 这样的全局配置项来硬性限制总内存占用。它的内存使用由多个独立参数控制,比如 innodb_buffer_pool_size、sort_buffer_size、tmp_table_size 等——这些是“软上限”,实际运行中可能叠加超限,尤其在高并发下。
常见错误现象:mysqld 进程 RSS 内存持续上涨,最终被系统 OOM killer 杀掉,日志里出现 Killed process <pid> (mysqld)</pid>。
-
innodb_buffer_pool_size是最大头号内存消耗者,建议设为物理内存的 50%–75%,但绝不能盲目设到 80% 以上 -
sort_buffer_size和read_buffer_size是 per-connection 分配的,连接数多时会指数级放大,应保持默认(256K/128K)或更低,而非调大 -
tmp_table_size和max_heap_table_size必须相等,否则内存临时表会悄悄退化成磁盘临时表,影响性能且难以察觉
cgroup v2 是当前唯一可靠的 MySQL 内存硬隔离方案
Linux cgroup v2(不是 v1)能真正限制 mysqld 进程组的总内存使用,包括 page cache、anon memory、buffers 等全部 RSS 占用。v1 的 memory.limit_in_bytes 在内核 4.5+ 后已弃用,且对 MySQL 常因 page cache 行为失效。
使用场景:容器环境(Docker/Podman 默认用 cgroup v2)、裸机部署需强资源保障时。
- 确认系统启用 cgroup v2:
mount | grep cgroup输出含type cgroup2 - 创建限制目录并设上限(例如 4GB):
sudo mkdir -p /sys/fs/cgroup/mysql→echo 4294967296 > /sys/fs/cgroup/mysql/memory.max - 将 mysqld 进程移入该 cgroup:
echo <pid> > /sys/fs/cgroup/mysql/cgroup.procs</pid>(启动后执行,或改用 systemd service 的MemoryMax=4G更稳妥) - 注意:cgroup v2 下
memory.high是软限,仅触发回收;必须用memory.max才是硬限
systemd 服务配置是最简落地方式(推荐裸机部署)
绕过手动操作 cgroup 目录,直接在 MySQL 的 systemd unit 文件里声明内存约束,重启即生效,且随进程生命周期自动管理。
操作路径:/etc/systemd/system/mysqld.service.d/override.conf(如不存在则新建)
[Service] MemoryMax=4G MemorySwapMax=0
关键点:
- 必须用
MemoryMax,MemoryLimit是旧版 v1 兼容项,在 v2 下无效 -
MemorySwapMax=0强制禁止 swap,避免内存压力下性能雪崩 - 修改后执行:
sudo systemctl daemon-reload && sudo systemctl restart mysqld - 验证是否生效:
systemctl show mysqld | grep Memory,再看cat /sys/fs/cgroup/system.slice/mysqld.service/memory.max
容易被忽略的 page cache 和 buffer pool 交互
MySQL 的 innodb_buffer_pool_size 只管 InnoDB 数据页缓存,而 Linux page cache 还会额外缓存 iblog、系统表空间、甚至查询结果文件——这部分不受 MySQL 参数控制,却会计入 cgroup 内存总量。
这意味着:即使你把 innodb_buffer_pool_size 设为 3G,cgroup memory.max=4G 仍可能被触发 OOM,尤其在大批量导入或备份时。
- 监控真实内存压力用:
cat /sys/fs/cgroup/system.slice/mysqld.service/memory.current(不是free或top) - 备份时临时调低
innodb_buffer_pool_size(如减半),或改用--single-transaction减少一致性读开销 - 如果用
mysqldump+ gzip,gzip 进程也得放进同一 cgroup,否则它吃掉的内存不算在 mysqld 限额里










