1GB 小机器跑 WordPress 被 OOM 干崩:根因与两步根治

1GB 小机器跑 WordPress 被 OOM 干崩:根因与两步根治

我的博客跑在 OCI 免费档的 1GB 内存实例上,前段时间突然整个打不开——SSH 还能登,但 80/443 全不通。排查下来是 apache2 被系统的 OOM killer 杀掉了,而且之后一直没自愈。这篇记录根因和最终的两步修复,给同样用小内存实例跑 WordPress 的人参考。

现象

SSH 正常,但:

  • curl http://blog.xxx/ 返回 000(连接不上)
  • 服务器 uptime 正常,进程在跑
  • ss -tlnp 看不到 :80 / :443 监听
  • systemctl status apache2 显示 failed (Result: oom-kill)

dmesg 里很直白:

Out of memory: Killed process 1096885 (apache2) ... UID:33

根因

两个因素叠加:

1. 实例太小,还没 swap

free -m 一看:总内存 956MB,Swap 是 0。没有交换分区,内核在内存见底时没有任何腾挪空间,只能直接 OOM kill。

2. apache 的 prefork MPM 配置太激进

默认配置:

<IfModule mpm_prefork_module>
    StartServers        1
    MinSpareServers     1
    MaxSpareServers     3
    MaxRequestWorkers   50
    MaxConnectionsPerChild  1000
</IfModule>

prefork 模式下每个 worker 是独立进程,各自加载一份 PHP,单个进程 RSS 大约 30–90MB(平均 ~80MB)。MaxRequestWorkers 50 意味着理论上能同时开 50 个 worker:

50 × 80MB ≈ 4GB,而机器总共才 956MB

低流量时 prefork 只留 1–3 个空闲 worker,内存够用;一旦并发上来(访问峰值、搜索引擎爬虫批量抓、或 wp-cli 批量操作),worker 数量往 50 涨,内存瞬间爆掉。因为没 swap,内核直接把 apache 进程杀掉。

修复(两步)

第一步:压低并发上限

MaxRequestWorkers 降到实例能吃下的范围。1GB 机器留 ~200MB 给系统和 MySQL,安全值约 10–15:

<IfModule mpm_prefork_module>
    StartServers        2
    MinSpareServers     2
    MaxSpareServers     6
    MaxRequestWorkers   12
    MaxConnectionsPerChild  2000
</IfModule>

MaxConnectionsPerChild 调大(1000→2000)让 worker 多复用几个请求再回收,减少频繁 fork 的内存抖动。MaxSpareServers 提到 6 是让空闲 worker 多留几个,应对突发不至于瞬间猛 fork。

最坏情况 12 × 80MB ≈ 960MB,机器扛得住。

改完校验:

sudo apache2ctl configtest   # 应显示 Syntax OK
sudo systemctl restart apache2

第二步:开 swap 兜底

比降并发更关键的是给内核一个缓冲池。新建 1GB 交换文件:

sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 持久化,避免重启后丢失
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

free -m 确认 Swap: 1023 即生效。

至此最坏情况变成:12 worker 满载(~960MB)+ 1GB swap 兜底,总承压约 2GB,OOM killer 基本没机会再触发

验证

重启后:

  • ss -tlnp 能看到 :80 / :443 监听
  • free -m 显示 Swap 1023MB
  • worker 数稳定在个位数,内存 used 约 389MB / available 约 408MB
  • 外网 curl 首页返回 200

为什么不复用 OOM 自愈

有人会问能不能让 systemd 自动拉起。apache2 本来就 enabled,但 OOM kill 后 unit 状态是 failed,systemd 不会自动 restart(除非配 Restart=always)。不过那只是”死了再拉”,没解决”为什么会死”。真正该做的是上面两步——把内存账算平,让它根本死不了。拉起兜底可以再加,但优先级低于根因治理。

小结

小内存实例跑 WordPress 被 OOM,本质是 prefork 多进程模型 × 高并发上限 × 零 swap 的组合拳。两步根治:

  1. 按内存大小压低 MaxRequestWorkers(1GB 机器取 10–15);
  2. 开 1–2GB swap 给内核兜底。

改完重启即生效,实例重启也不丢(fstab 持久化)。

本文由 AI 辅助生成

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理

滚动至顶部