swap 与内存压力:加了 swap 为什么还是卡

一、现象与影响面:加了 swap,卡顿没走

症状:小内存服务器(1-2G)周期性卡顿几十秒又自己恢复,SSH 敲命令都慢半拍;或者你已经加了 swap,”该好一点了”却没有——卡顿照旧,只是换了个姿势。内存压力的卡是全场一起卡:接口超时、数据库慢、命令行卡顿同时出现,这与单进程吃 CPU 的问题形态完全不同。

动手之前先立一个判断原则:swap 是缓冲垫,不是解药。它只在”内存偶发超出”时替你争取时间;内存长期不够时,swap 只是把”内存不够”翻译成”磁盘 IO 不够”——磁盘比内存慢两个数量级,卡顿会更久而不是更短。反模式一:一卡就加 swap。如果换页已经持续活跃,加 swap 等于把性能问题降级成一个更慢的问题。先取证,再决定加不加。

排查主线:free 看水位与趋势 → vmstat 的 si/so 判定是不是真抖动 → 找出谁躺在 swap 里 → 核对 swappiness 的真实语义 → 按决策表选”加 swap”还是”治本”。所有命令都在卡的那台服务器上跑。

二、第一步:free 看的不是 free,是 available

很多人被 free 输出的第一列骗了十年。看懂每列语义是判断内存压力的前提:

free -h
1.               total   used   free   shared  buff/cache   available
1. Mem:          1.8Gi   1.5Gi  180Mi   24Mi       120Mi      210Mi
1. Swap:         2.0Gi   640Mi  1.4Gi
1. ↑ free 少不等于内存紧张:buff/cache 是内核拿去缓存的闲置内存,
1.   应用要用时立刻让出。判断水位只看 available——"不换页就能挤出来"的估算

单点数值不够,挂个 watch 看趋势,一分钟就够定性:

watch -n 1 free -h          # 每秒刷新,盯一至两分钟
1. 两种典型曲线:
1.   available 在某个区间内波动,偶有下探但总回弹     ← 峰值代谢,健康
1.   available 单调下探、长期不复返                    ← 有进程在持续吃,压力为真

反模式二:把 free 数值低当故障报修。free 少而 available 充足,是内核缓存正常工作的样子,不是泄漏。这一步回答”内存压力是真是假”;压力为真,下一步看 swap 到底在帮谁、坑谁。

三、第二步:vmstat 的 si/so,判定”真抖动”还是”偶发换页”

内存压力与 swap 的关系,用 vmstat 每秒采样最直接:

vmstat 1 10
1. procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
1.  r  b   swpd   free   buff  cache    si   so    bi    bo   in   cs  us  sy  id  wa
1.  1  0  65536 180000  24000 120000     4    8   120    90  210  380  12   4  74  10
1.  2  1 131072 120000  24000 118000   240  380   140  4200  380  620  15   6  21  58
1.  2  1 196608  86000  22000 116000   260  410   110  5100  420  700  14   5  12  69
1. ↑ si/so 每行都有几百的数、wa 一路走高——换页风暴,磁盘在替内存扛

两列是关键:si(swap in)与 so(swap out),每秒换入换出的 KB 数。判定标准不是”非零”,而是持续性:

si/so 表现 判定 下一步
持续非零(每行都有数百以上)且 wa 高 换页风暴,内存真不够,卡顿正来自换页 IO 第四节找出元凶,第六节治理
偶发几行非零随即归零 峰值过境的正常代谢,swap 在正确兜底 不用动,接入监控即可
全程为 0 但机器仍卡 瓶颈不在内存,别在 swap 上耗着 转 CPU、磁盘 IO 等其他方向

卡顿时刻 si/so 持续活跃,就完成了第一层实锤:这不是”加了 swap 就好”的问题,换页本身正在制造卡顿。现在找是谁在换。

四、第三步:找出谁躺在 swap 里

内核按进程记账换页,每个进程在 /proc 下都有 VmSwap 字段。一个循环就能排出”换页大户”:

# 服务器上(root);按换出量从大到小列前几名
swapon --show
1. NAME       TYPE  SIZE  USED PRIO
1. /swapfile  file    2G  640M   -2      ← 有哪些 swap、各用掉多少

for p in /proc/[0-9]*/; do
  s=$(awk '/VmSwap/{print $2}' "$p/status" 2>/dev/null)
  [ "${s:-0}" -gt 0 ] && printf '%10d KB  %s\n' "$s" "$(cat "$p/comm" 2>/dev/null)"
done | sort -rn | head
1.    512000 KB  mysqld
1.     86000 KB  java
1.     12000 KB  myapp-worker
1. ← 延迟敏感的进程躺在 swap 里,就是卡顿元凶

看排名要带业务眼光:数据库、Redis 这类进程换出的每一页,命中时都要从磁盘读回来,一次查询的耗时能翻几十倍;Java、Go 这类运行时被换出后,GC 与调度会引发连锁换页。反过来说,换出的是偶尔才访问的后台进程,那属于 swap 的正常用法。排名把”机器内存不够”细化成”哪个进程该限内存或该挪走”——带着这份名单进治理决策。

五、第四层:swappiness 的语义正名

提到 swap 必谈 vm.swappiness,但围绕它的误解多得离谱。先正名:它是内核在”回收 page cache”与”把匿名页换出到 swap”之间的倾向权重,取值 0-100,默认 60(长期稳定默认,具体语义以所用内核的 ip-sysctl 文档为准):

常见误解 实际语义
“60 表示用到 60% 内存才开始 swap” 它不是水位阈值,是两种回收路径之间的权重倾向
“设 0 就是禁用 swap” 不是。0 只表示尽量避免换出匿名页,真要禁用请 swapoff
“设 100 内存随便换,肯定不卡” 只是更积极换出,不是开关;数值越大热数据越容易被换走
# 服务器上;临时改用 sysctl,永久生效写入 sysctl.d
sysctl vm.swappiness
1. vm.swappiness = 60

sysctl -w vm.swappiness=10
echo "vm.swappiness=10" > /etc/sysctl.d/99-swappiness.conf   # 重启后仍生效

实践口径:数据库、缓存这类延迟敏感服务所在的主机调低(10 左右),让内核优先回收缓存而不是把热数据换出;通用业务机保持默认即可。诚实边界:swappiness 是调倾向,不是调容量——si/so 持续活跃时把它调小只能减轻症状,不能止血,止血靠下一节的决策。

六、治理决策:什么时候加 swap,什么时候治本

所有取证都指向同一张决策表:

症状 决策 理由
偶发峰值击穿 available(备份、编译、月结批任务) 加 swap 兜底 换出的是冷页,代价小,还能让内核晚一点动用 OOM 杀手
si/so 持续活跃、wa 居高不下 治本:给泄漏进程限内存、加内存、或把服务挪走 持续赤字 swap 挡不住,只会把卡顿拉得更长
VmSwap 排名集中在单个进程 治理那个进程,而不是动整机 容器场景给该容器设 memory 限额;自研服务先查泄漏
裸机没配 swap,偶发峰值直接丢进程 补一个小 swapfile 内存不足时内核 OOM killer 直接杀进程,swap 是它之前的最后缓冲

决定加 swap,用文件方式最灵活(ext4 上一步到位;btrfs 等文件系统对 swapfile 另有限制,以内核与发行版文档为准):

fallocate -l 2G /swapfile        # 开一块 2G 的文件
chmod 600 /swapfile              # 权限必须收紧,不设 swapon 会直接拒绝
mkswap /swapfile                 # 格式化成 swap
swapon /swapfile                 # 立即启用,swapon --show 可验
echo '/swapfile none swap sw 0 0' >> /etc/fstab   # 写进 fstab,重启仍生效

swap 多大合适?诚实地说没有万能公式。”内存两倍”是上个年代小内存机器的经验,8G 内存的服务器照抄只会白占盘。原则是小而稳:兜底用 1-4G,具体大小由第二步观察到的峰值缺口决定;桌面机要休眠的另算,休眠要求 swap 不小于物理内存。至于治本清单:给名单上的进程设内存限额、查代码泄漏(内存泄漏的定位是另一类独立故障,本文不展开)、单机纵向到顶就考虑把服务横向分担。

七、根因清单:按出现频率排序

根因 典型特征 一行验证
泄漏型进程持续吃内存 available 单调下探不复返 watch -n 1 free -h 盯两分钟
批处理/备份撞峰 卡顿时刻与计划任务时刻吻合 卡顿时刻表对照 cron 计划
数据库/缓存热数据被换出 慢查询与卡顿同时爆发,重启后短暂好转 VmSwap 排名看 mysqld/redis
小内存机 swappiness 默认偏高 available 尚有余量却频繁 so sysctl vm.swappiness
没配 swap 的裸机遇峰值被 OOM 进程莫名消失,dmesg 有杀进程记录 dmesg -T | grep -i oom
buff/cache 被误读为泄漏 “used 一直涨”实为缓存吃满 free -h 只看 available 列

八、预防

措施 做什么 边界
available 水位告警 低于 10-15% 告警,采 available 而不是 free 阈值按业务峰值留量,别照抄别人的数
换页持续性告警 si/so 连续 N 分钟非零即告警 比”swap 用量”更早发现问题——用量涨起来时卡顿已经开始
VmSwap TOP 采集 巡检带上第四节的一行排名 只采前几名,全量遍历在进程多的机器上偏慢
装机基线 装机清单含 swapfile 与 swappiness 基线值 数据库主机与通用主机基线不同,分开写

这套走法收拢成一句:available 的趋势判定内存压力真假,si/so 的持续性判定 swap 是在兜底还是在遭殃,VmSwap 排名指认元凶——偶发峰值交给 swap 缓冲,持续赤字只有治本一条路,swappiness 从头到尾都只是倾向调节,不是容量。

延展阅读:free、vmstat、dmesg 这些观测命令的日常用法,见《Linux 常用命令》;单机内存纵向加到头还扛不住时,下一步是把服务横向分担,见《多节点集群架构规划》。

版本核实(以官方文档为准):free 的 available 列语义、vmstat 的 si/so/wa 列含义、vm.swappiness 默认 60 且为回收倾向权重、swapon 对 swapfile 权限的强制检查,均为长期稳定的内核与工具行为;fallocate 创建 swapfile 在 btrfs 等文件系统上有额外限制,以内核与发行版文档为准;OOM killer 的触发与定位属另一类故障,本篇只作现象衔接,不展开其机制细节。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇