关键词:OOM、Swap、Linux 内存、2核2G 服务器、运维复盘
结论先行:Swap 不是性能方案,但在 OOM 面前,它是救命绳。
一、事故背景
我有一台 2核2G 的云服务器,主要用途是运行一个博客网站:
Halo(Spring Boot)
MySQL
Nginx
访问量不算高,但有一天开始,网站出现了非常诡异的情况:
页面偶尔打不开
服务会“莫名其妙”重启
日志里没有明显报错
重启服务器后短暂恢复,过一会儿问题再次出现
一开始我以为是程序 Bug,直到我第一次真正看懂了 OOM。
二、什么是 OOM?我当时是怎么“被它教育”的
OOM,全称 Out Of Memory,意思是:
系统内存耗尽,Linux 内核为了自保,强制杀死某个进程。
关键点在于:
被杀的进程通常不会给你任何体面的告别。
对我来说,表现就是:
Java 进程突然消失
网站直接 502
没有 Java 异常栈
只有系统日志里一句冷冰冰的:
Out of memory: Kill process xxxx (java)
那一刻我才意识到:
不是程序挂了,是系统扛不住了。
三、为什么 2核2G 服务器这么容易 OOM?
问题并不复杂,但非常常见。
1. Java 默认配置是“无上限”的
在没有明确设置 -Xmx 的情况下:
JVM 会根据系统内存自动扩展堆
在小内存服务器上,这几乎等于“放飞自我”
2. 系统内存不是只给 Java 用的
同一台机器上,还有:
MySQL
Linux 内核
文件缓存(page cache)
其他守护进程
当这些同时争抢内存时,OOM 是迟早的事。
3. 没有 Swap,系统连“缓冲区”都没有
当时我服务器的状态是:
内存快满
Swap = 0
一旦有内存峰值,系统没有任何缓冲空间
👉 结果就是:OOM Killer 直接出手。
四、我做的第一件正确的事:创建 Swap 分区
在明确问题根源后,我做的第一件事不是“重装系统”,而是:
给服务器加一块 Swap。
Step 1:创建 2GB Swap 文件
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
并写入 /etc/fstab,保证重启后生效:
/swapfile none swap sw 0 0
Step 2:调整 swappiness(非常关键)
echo 'vm.swappiness=10' | tee /etc/sysctl.d/99-swappiness.conf
sysctl -p /etc/sysctl.d/99-swappiness.conf
这一步的意义是:
平时尽量不用 swap
只有内存快撑不住时才用
五、Swap 生效后,发生了什么变化?
1. OOM 消失了
这是最直接的变化:
Java 不再被系统杀死
网站不再“莫名其妙”挂掉
2. 系统行为变得“温和”
通过 free -h 我看到:
swap 偶尔使用几十 MB
内存峰值被“削平”
CPU 抖动明显减少
这说明:
Swap 成功扮演了“缓冲带”的角色。
六、我后来才明白的一件事:Swap 不是解决方案本身
非常重要的一点:
Swap 不能替代内存,它只是延迟死亡。
如果只是“加 swap”,而不做任何优化:
程序还是会慢
IO 会变多
最终仍然可能崩
所以,在启用 Swap 之后,我还做了这些事:
限制 JVM 最大内存
压缩 MySQL Buffer Pool
删除不必要的插件
Swap 只是第一道防线,不是终点。
七、什么时候应该用 Swap?什么时候不该?
✅ 适合用 Swap 的场景
小内存服务器(1–4GB)
Java / Node / Python 服务
内存偶发峰值
希望避免 OOM
❌ 不该依赖 Swap 的场景
长期高负载
swap 使用量持续增长
页面明显变慢
这时候,正确的选择是:
优化配置,或者加内存。
八、这次事故带给我的三个教训
OOM 往往不是程序 Bug,而是资源边界失控
Swap 是服务器的安全气囊,不是发动机
默认配置在小服务器上,几乎一定是错的
结语
这次 OOM 事故让我真正理解了一件事:
服务器不是“挂了”,
而是在用最极端的方式提醒你:
你超出了它的能力边界。
Swap 让我有机会从事故中活下来,
而真正让我系统稳定下来的,是后续对内存的尊重。