搜索全站
报错排查 10 分钟阅读

服务器内存不足时给 WordPress 加 swap 的正确做法

1G 内存的小机器跑 WordPress,流量一高就被 OOM 杀进程。加 swap 能兜底防崩溃。本文讲清 swap 创建、swappiness 调优、SSD 上的注意事项,以及 swap 救不了的情况。

U
UFO_PF 2025-07-07 · 阅读 10 分钟
服务 报错排查
阅读提示
本文约 3,714 字,预计阅读 10 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:内存一满,站点就 502

低配云服务器(1 核 2G、2 核 2G)跑 WordPress 的常见症状:

  • 平时正常,备份、更新、批量操作时站点卡死;
  • MySQL 进程被杀,站点报”数据库连接失败”;
  • 日志里全是 Out of memory: Kill process;
  • 装了 Redis + MySQL + PHP-FPM + Nginx,内存刚好卡在临界点。

绝大多数云主机默认没有 swap(阿里云、腾讯云、AWS 的镜像都默认关闭)。这意味着内存一满,内核直接杀进程,没有任何缓冲。加一个 swap 文件,相当于给系统留了一条”慢但不会死”的退路。

原理分析:swap 是什么,代价是什么

swap 是磁盘上的一块空间,当物理内存紧张时,内核把不常用的内存页换出到磁盘,腾出物理内存给活跃进程。

好处:

  • 内存峰值时有缓冲,不会立刻 OOM;
  • 冷数据(比如长时间不用的 PHP-FPM 空闲进程)被换出,热数据留在内存。

代价:

  • 磁盘比内存慢几个数量级。一旦开始大量交换,系统会变得极慢(俗称”swap 抖动”);
  • SSD 有写入寿命,频繁 swap 会消耗(但对现代 SSD 影响很小,不必过度担心)。

关键认识:swap 是保险丝,不是扩容。它的价值在于”偶尔用到时不会死”,而不是”让你放心超售内存”。如果 si/so(换入换出)持续很高,说明内存真的不够,该升级配置了。

swappiness 参数控制内核使用 swap 的倾向:

  • 0:尽可能不用 swap(在内存回收时才用,Linux 3.5+ 的语义);
  • 1:最低限度使用;
  • 60:默认值,比较积极;
  • 100:非常积极。

对服务器,推荐 10–30:既保留兜底能力,又不会在日常运行时把热数据换出去。

保姆级实操

第一步:查看当前 swap 情况

free -h
swapon --show
cat /proc/sys/vm/swappiness

如果 Swap: 0B,说明没开。

第二步:创建 swap 文件

推荐大小:

物理内存 swap 建议
≤ 2GB 内存的 2 倍
2–8GB 等于内存大小
8–64GB 8GB
> 64GB 4–8GB(或不用)
# 创建 2GB 的 swap 文件(fallocate 最快)
sudo fallocate -l 2G /swapfile

# 如果 fallocate 报错(某些文件系统不支持),用 dd
sudo dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress

# 权限必须 600,否则 swapon 拒绝
sudo chmod 600 /swapfile

# 格式化
sudo mkswap /swapfile

# 启用
sudo swapon /swapfile

验证:

free -h
# Swap:  2.0Gi  ...

第三步:设置开机自动挂载

# 备份 fstab
sudo cp /etc/fstab /etc/fstab.bak

# 追加一行
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# 检查语法(无输出即正常)
sudo mount -a

第四步:调整 swappiness

# 临时生效
sudo sysctl vm.swappiness=20

# 永久生效
echo 'vm.swappiness=20' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

另外一个有用的参数(减少内核缓存对 swap 的干扰):

# 控制"内核为 page cache 回收多少 inode/dentry 缓存",默认 100
echo 'vm.vfs_cache_pressure=50' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

第五步:WordPress 侧同步调整内存限制

swap 只是兜底,WordPress 本身也要合理设限。在 wp-config.php 里:

// 前台不需要太大,后台才需要
define( 'WP_MEMORY_LIMIT', '128M' );
define( 'WP_MAX_MEMORY_LIMIT', '256M' );

同时 PHP-FPM 的 memory_limit 要匹配(不能低于 WordPress 的设置):

; /etc/php/8.2/fpm/php.ini
memory_limit = 256M

注意:memory_limit 是所有 PHP-FPM 进程各自的限制,不是总量。10 个进程 × 256M 理论峰值就是 2.56GB。这也是 PHP-FPM 进程数计算 里要用真实 RSS 而非 memory_limit 的原因。

第六步:监控 swap 使用情况

# 实时看换入换出(si/so 列,单位 KB/s)
vmstat 1

# 看哪些进程用了 swap
for f in /proc/[0-9]*/status; do
  pid=$(basename $(dirname $f))
  swap=$(awk '/VmSwap/{print $2}' $f 2>/dev/null)
  [ -n "$swap" ] && [ "$swap" -gt 0 ] && \
    echo "$pid $(awk '/^Name/{print $2}' $f) ${swap}kB"
done | sort -k3 -rn | head -10

判断标准:

  • si/so 长期为 0 → swap 只是保险,配置合理;
  • si/so 偶尔非零 → 峰值时有缓冲,这正是我们想要的;
  • si/so 持续几百 KB/s 以上 → 内存真的不够,该升级配置。

常见踩坑

  1. fallocate 创建的 swap 文件在某些文件系统上不可用(如某些版本的 btrfs、OpenVZ 的老内核)。用 dd 更保险,只是慢一点。
  2. 权限没设 600:swapon 报 insecure permissions 0644, fix with: chmod 600。
  3. 云服务器用云盘:swap 在云盘上 I/O 更慢,抖动时更卡。可以考虑用 zRAM(内存内压缩 swap),比磁盘 swap 快很多:

bash
sudo apt install zram-tools -y
sudo systemctl enable --now zramswap

zRAM 把内存压缩后当 swap 用,相当于”用 CPU 换内存”,在小内存机器上效果比磁盘 swap 好得多。

  1. 案例:某 1G 内存站加了 2G swap,结果站点反而更慢了——因为 swappiness 保持默认 60,MySQL 的 innodb_buffer_pool 被换出到磁盘,每次查询都走磁盘 IO。把 swappiness 改成 10 并把 buffer_pool 从 512M 降到 256M 后恢复正常。swap 不能替代正确的内存规划。
  2. 容器环境:Docker/K8s 里加 swap 要宿主机支持,且 K8s 默认禁用 swap。容器内改不了,需要在宿主机配。
  3. 误以为 swap 能解决一切:如果 dmesg 里持续 OOM,说明峰值需求远超物理内存,swap 只是延后死亡。真正的解法是减少内存占用——查哪个插件吃内存(用 Query Monitor 看 Memory Usage),或者上 Redis 减少重复加载。
  4. 删除 swap(如果后续升级了内存):

bash
sudo swapoff /swapfile
sudo rm /swapfile
# 记得把 /etc/fstab 里那行删掉

总结

swap 的正确定位:防止偶发峰值导致 OOM 的保险,不是性能方案。配置四步:fallocate 建文件 → chmod 600 → mkswap + swapon → 写 fstab 持久化;再把 vm.swappiness 调到 10–30,避免日常运行时把热数据换出去。判断配置是否健康看 vmstat 的 si/so:长期为 0 最好,偶尔非零正常,持续很高就必须加内存或减占用。同时别忘了检查 WordPress 的 WP_MEMORY_LIMIT 和 PHP 的 memory_limit 是否设得过大(虚高限制会让 OOM 来得更早)。关于内存占用的进一步优化,可参考 PHP-FPM 进程数计算 和 WordPress Redis 对象缓存。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。