
你是不是也碰到过这种场景:
服务器还没干什么活,突然变得响应迟钝,top 一看,Swap 使用飙升,负载爆表,MySQL 卡得像拨号上网。更迷的是,内存看起来还没用完,到底是谁在背后搞鬼?
很多人一看到 swap,就直觉“内存不够了”。但事情真有这么简单吗?Linux 的内存管理机制复杂得不像话,Swap 只是其中的一个“排气阀门”——问题的出现可能是因为风压太大,也可能是阀门本身就出了问题。
别急,我们这篇文章就带你从多个角度把这个谜团扒开,掰开了揉碎了讲清楚:
- Swap 是怎么运作的?
- 什么场景下它会失控暴涨?
- 如何判断是否“该担心”?
- 怎么调优,甚至让它不再捣乱?
Swap 是内存的“备胎”,但它的性格比你想象得复杂
Swap 的本质是“虚拟内存”——当物理内存不够时,Linux 会把部分“暂时用不到”的内存页写到磁盘上。说白了,这就是操作系统的“腾地方”策略。
但这个策略看起来体贴,执行起来却常常翻车。为什么?因为磁盘(即便是 SSD)的访问速度远低于内存,尤其是高并发业务,一旦系统频繁地把数据来回搬运,性能直接跪了。
而且,Linux 并不总是“快用完内存了”才用 swap,它有自己的一套调度机制,比如:
- 某个进程的内存活跃度不高;
- 系统认为该内存页长期不活跃;
- 当前内存压力较大(但还没爆);
你以为 swap 是紧急备用,系统却把它当成“主动整理房间”的手段。
Swap 暴涨背后的可能真相
让我们举几个真实的场景看看 swap 为何暴涨:
1. 某个内存泄露的守护进程“默默长胖”
比如日志收集器、某个旧版的 Python 进程。它们不常 crash,也不频繁响应,但会稳定地增长内存占用。直到某个瞬间被系统当作“可 swap 对象”打包出局,swap 立马被吃掉几个 GB。
2. 数据库缓存+业务内存+突发流量合体爆发
数据库吃内存,应用吃内存,突然来波用户请求,系统调度不过来就会“拆东墙补西墙”,把旧页 swap 掉。然而你很可能发现,MySQL 的性能瞬间崩了——因为它部分 buffer pool 被 swap 出去了!
3. Docker、K8s 容器环境下 Swap 难以察觉
容器里默认不开 swap,宿主机却可能默默地 swap 出了一堆进程,甚至不知不觉把整个 namespace 弄得半死不活。这个过程你在容器里根本察觉不到。
判断 Swap 是否真的成了问题,不只是看“用了多少”
一个最大的误区是:看到 swap 用了 3GB,就慌了。
Swap 被使用 ≠ 性能有问题
你得结合这些信息一起判断:
si / so
(swap in/out)的速率是否持续活跃?vmstat
中 swap 页的活动频率是否高?- 系统是否频繁 I/O wait?
- 用户请求是否响应变慢?
- top 或 htop 中 RES(实际驻留内存)值是否严重下降?
特别要关注的是:swap usage 增加的趋势 + 系统响应的延迟变化,这两个组合拳才说明 swap 的使用正在拖慢系统。
那 swapiness 到底该怎么设?
Linux 的 vm.swappiness
是个神奇的参数:
- 默认值是 60,意味着内核在内存使用到 40% 时就开始考虑 swap。
- 如果你调成 10,表示内核会尽量不 swap,除非真的撑不住。
- 设置成 0 并不代表“完全不用 swap”,只是“极度保守地使用”。
如果你的机器是数据库服务器、实时计算服务、低延迟服务,请大胆地:
bashsysctl -w vm.swappiness=10
如果你希望彻底禁用 swap(有足够内存撑住),可以:
bashswapoff -a
但切记,禁用 swap 是一个“宁可用完崩溃”的策略,只适合你能控制应用行为的场景。
查 Swap 之祸根:排查思路全流程
这里我们搞一套实用套路,甭管啥业务,总能跑起来看出点问题:
第一步:谁吃了 swap?
bashsmem -rs swap
如果没有 smem,可用 top/htop 看 SWAP 列排序,找出“胖子”。
第二步:Swap 活跃度是否高?
bashvmstat 1 5
留意 si(swap in)和 so(swap out)是否持续为非 0。
第三步:磁盘 IO 是不是变慢了?
bashiostat -x 1
看看 r/s 和 await,swap 活跃通常会伴随磁盘 IO 激增。
第四步:查看进程具体 swap 内容(高阶)
bashcat /proc/<pid>/smaps | grep -i swap
还能进一步了解哪些 segment 被 swap 出去了,定位是否为常驻内存的关键代码段。
实战调优建议:从系统级、应用级双手出击
✅ 系统级优化
- 降低 swappiness
- 升级内核版本(部分版本 swap 管理有 bug)
- 使用 zswap / zram(内存压缩页)
- 增加物理内存(最直接但最贵)
✅ 应用级优化
- 限制进程最大内存使用(ulimit)
- 避免大对象频繁申请释放(尤其是 Python/C++)
- 检查容器中是否运行了内存泄露服务
- 减少业务内存的 resident size,如缓存缩小
真实案例:一次 swap 爆炸引发的凌晨事故
某 SaaS 平台凌晨用户大量导出数据,导致 Python 后端部分 worker 暂时性内存冲高。系统调度 swap 后,“打包出去了”一些后台进程的关键堆栈。
虽然页面还能加载,但核心接口访问变慢,一分钟后服务开始“假死”。最终发现 swap in/out 每秒高达 3000 页,导致磁盘 IO 拥堵,MySQL 慢查询激增,彻底击穿。
解决方法包括:
- 限制 worker 并发数;
- 降低 swappiness;
- 提前预警内存水位线;
- 增加日志 swap 活跃的告警规则。
Swap 不是“洪水猛兽”,也不是“好兄弟”
它更像是你内存系统里一位沉默的搬运工。你不给它压力,它不出声;你猛地给它塞活,它就偷偷把一些“你没用过的”东西给你处理掉。
真正的问题是——你知道他在做什么吗?
不要被 swap 数值吓到,也不要对其放任自流。结合业务、IO、延迟、活跃页,做出适配策略才是王道。