运行 MySQL 8.0 的服务器,swap 分区是否必须关闭?如何设置 vm.swappiness?

在运行 MySQL 8.0(尤其是高负载、OLTP 场景)的生产服务器上,强烈建议关闭 swap 分区或将其影响降至最低,但“必须关闭”需结合具体场景审慎判断。更准确的说法是:应避免 MySQL 工作集被换出(swapped out),因此需通过合理配置 vm.swappiness 和内存规划来实现,而非绝对禁用 swap。

以下是专业、可落地的建议:


✅ 一、为什么 swap 对 MySQL 不友好?

  • MySQL(尤其 InnoDB)严重依赖内存缓存(innodb_buffer_pool_size),其性能对内存延迟极度敏感。
  • 若 buffer pool 或热点数据页被 swap 到磁盘,一次逻辑读可能触发 毫秒级 swap I/O(甚至百毫秒),远超 SSD 的微秒级随机读,导致查询雪崩、连接堆积、主从延迟激增。
  • Linux OOM Killer 可能在内存压力下优先 kill mysqld 进程(因其内存占用大),而非其他小进程。

⚠️ 注意:swap 并非“完全无用”。它在以下场景仍有价值:

  • 防止突发内存泄漏/异常导致 OOM Kill(提供缓冲时间);
  • 支持 hibernation(休眠);
  • 容器环境(如 Docker/K8s)中,swap 可辅助资源隔离(但需谨慎启用)。

✅ 二、vm.swappiness 推荐设置(关键!)

场景 vm.swappiness 值 说明
专用 MySQL 服务器(物理机 / 虚拟机,内存充足) 1(✅ 最佳实践) 极小化主动 swap,仅在内存真正耗尽时才考虑 swap;保留系统稳定性,避免 OOM Kill。
内存严重受限(如 innodb_buffer_pool_size > 80% RAM)且无法扩容 0 禁用 主动 swap(内核不主动换出匿名页),但 仍允许 swap 用于紧急内存分配(如 mmap(MAP_ANONYMOUS) 失败时)和 THP 退化等。
⚠️ 注意:swappiness=0 ≠ swap 被禁用(swap 分区仍可被使用,例如 kswapd 在极端 OOM 时仍可能换出)
多用途服务器(MySQL + 其他服务)或云环境(如 AWS EC2) 1 ~ 10 平衡稳定性与性能,避免 MySQL 内存被轻易换出。
绝对禁止 swap(测试/特殊合规要求) 0 + swapoff -a + /etc/fstab 注释 swap 行 ✅ 彻底禁用,但失去最后防线,OOM 风险升高。

❌ 不要设为 60(默认值)或更高 —— 这会显著增加 MySQL 页面被换出的概率。

🔧 如何设置(永久生效):

# 1. 临时生效(重启前有效)
sudo sysctl vm.swappiness=1

# 2. 永久生效:编辑 /etc/sysctl.conf
echo 'vm.swappiness=1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# 3. (可选)验证当前值
cat /proc/sys/vm/swappiness

✅ 三、配套最佳实践(比单纯调 swappiness 更重要!)

  1. 合理规划内存

    • innodb_buffer_pool_size 建议设为 物理内存的 50%–75%(专用服务器),确保 OS 缓存、文件系统、连接线程等有足够空间。
    • 避免过度分配(如设为 90%+),否则 OS 内存不足 → kswapd 活跃 → swap 风险上升。
  2. 监控 swap 使用

    # 实时查看 swap 使用(重点关注 si/so 列)
    vmstat 1 5    # si: swap-in KB/s, so: swap-out KB/s → 理想值应长期为 0
    
    # 查看 MySQL 进程是否被 swap
    sudo cat /proc/$(pgrep -f "mysqld")/status | grep -i "swap"
    # 或使用 smaps(更详细)
    sudo awk '/^Swap:/ {swap+=$2} END{print "Total swap used by mysqld: " swap " KB"}' /proc/$(pgrep -f "mysqld")/smaps
  3. 禁用透明大页(THP)(MySQL 8.0 强烈要求)

    # 临时禁用
    echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
    # 永久禁用(添加到 /etc/rc.local 或 systemd service)
  4. 使用 cgroups v2(现代 Linux)限制 MySQL 内存上限(防内存溢出)

    # 示例:限制 mysqld 最多使用 32GB 内存(含 swap)
    sudo systemctl set-property mysqld.service MemoryMax=32G

✅ 四、结论(一句话总结)

MySQL 8.0 生产服务器不应依赖 swap,而应通过 vm.swappiness=1 + 合理 innodb_buffer_pool_size + 监控 + THP 禁用,确保工作集常驻物理内存;swap 分区可保留但应几乎不被使用——这不是“必须关闭”,而是“必须使其失效于 MySQL 性能路径”。

如需进一步优化,可提供您的:

  • 服务器内存总量 & innodb_buffer_pool_size 设置
  • free -h 和 vmstat 1 5 输出
  • MySQL 错误日志中是否有 Out of memory 或 swap 相关警告

我可以帮您做针对性诊断 👍


✅ 参考来源:MySQL 官方文档(Optimizing for InnoDB)、Percona 最佳实践、Linux 内核文档(Documentation/admin-guide/mm/swap.rst)。

未经允许不得转载:CLOUD技术博 » 运行 MySQL 8.0 的服务器,swap 分区是否必须关闭?如何设置 vm.swappiness?