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 的组合拳。两步根治:
- 按内存大小压低
MaxRequestWorkers(1GB 机器取 10–15); - 开 1–2GB swap 给内核兜底。
改完重启即生效,实例重启也不丢(fstab 持久化)。
本文由 AI 辅助生成