Linux Swap 使用暴增?一文读懂排查与调优全流程

Linux Swap 使用暴增?一文读懂排查与调优全流程

你是不是也碰到过这种场景:

服务器还没干什么活,突然变得响应迟钝,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”,只是“极度保守地使用”。

如果你的机器是数据库服务器、实时计算服务、低延迟服务,请大胆地:

bash
sysctl -w vm.swappiness=10

如果你希望彻底禁用 swap(有足够内存撑住),可以:

bash
swapoff -a

但切记,禁用 swap 是一个“宁可用完崩溃”的策略,只适合你能控制应用行为的场景。


查 Swap 之祸根:排查思路全流程

这里我们搞一套实用套路,甭管啥业务,总能跑起来看出点问题:

第一步:谁吃了 swap?

bash
smem -rs swap

如果没有 smem,可用 top/htop 看 SWAP 列排序,找出“胖子”。

第二步:Swap 活跃度是否高?

bash
vmstat 1 5

留意 si(swap in)和 so(swap out)是否持续为非 0。

第三步:磁盘 IO 是不是变慢了?

bash
iostat -x 1

看看 r/s 和 await,swap 活跃通常会伴随磁盘 IO 激增。

第四步:查看进程具体 swap 内容(高阶)

bash
cat /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、延迟、活跃页,做出适配策略才是王道。

知识库

TCP 队头阻塞困境揭秘:高并发下连接延迟暴涨的真正原因

2025-7-9 11:09:28

知识库

Ping 不丢包却访问慢?深入解析 ICMP 与真实网络体验的差距

2025-7-10 10:35:06

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧