ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

CentOS 7 swap交换空间配置指南:容量、创建、调优与排错

CentOS 7 swap交换空间配置指南:容量、创建、调优与排错

1. 先把账算明白:CentOS 7 需不需要交换空间

在 CentOS 7 上加交换空间(swap)这件事,看起来只是个dd加mkswap的操作,但我在实际交付中见过太多人把它做成了“加完之后系统更卡”的结果。原因基本都不在命令敲错,而在于动手之前没算清楚三件事:这台机器到底缺不缺 swap、缺多少、加在什么地方。CentOS 7 这套系统本身对交换空间的依赖程度和后来的版本不太一样,它的默认安装流程在物理内存足够时经常干脆不给你划 swap,尤其是各种云主机镜像、最小化安装镜像,装完free -h一看,Swap 那一行赫然是 0。这时候你心里得有个判断:是这台机器真的不需要,还是安装时被跳过了。

交换空间的作用,说白了就是给内存找一个“溢出的临时仓库”。物理内存不够用时,内核把最近不怎么活跃的内存页挪到磁盘上,把位置腾给正在跑的热数据,等那些被挪走的页再次被访问,再换回来。这个动作叫换出(swap out)和换入(swap in),vmstat里的si、so两列就是它们的实时速率。它的价值不在于“提速”,而在于防止一个偶发的内存尖峰直接把进程干掉——也就是避免 OOM Killer 一斧头砍掉你的数据库或者 Web 服务。反过来说,如果一台机器的 swap 长期被大量读写,那它一定是内存严重不足,加 swap 只是在给硬件拖延时间,正确的解法是加内存,而不是无限堆 swap 文件。

这篇文章面向三类人:刚接手一台 CentOS 7 服务器、发现没有交换空间不知道怎么补的运维新手;手里有老业务跑在 CentOS 7 上、需要做资源加固的中级工程师;以及想搞清楚“swap 文件、swap 分区、swappiness 到底怎么回事”的开发者。我会把容量怎么算、文件怎么建、fstab 怎么写、报错怎么查,一步步拆开讲清楚,中间穿插我自己踩过的坑。只要你有一台能登上去的 CentOS 7,跟着做就能完成,不需要重装系统,也不需要停机。

1.1 交换空间在 CentOS 7 里到底承担什么角色

很多人对 swap 的印象停留在“内存不够时用的假内存”,这个理解不算错,但太粗。Linux 的内存管理里,swap 承担的不只是容量补充,它还是内核回收匿名内存页的唯一出口。所谓匿名页,就是没有对应磁盘文件的那些内存,比如进程的堆、栈、malloc 出来的缓冲区。文件页(比如可执行文件、被 mmap 的文件)在内存紧张时可以直接丢弃,反正磁盘上有原件,下次访问再读回来就行;但匿名页没有原件,内核想回收它,只能写进 swap。这就意味着一件事:即使你的系统内存看起来很充裕,只要它需要做内存整理、需要给连续的大块分配腾地方,swap 就有可能被用到一点点。完全没有 swap 的机器,在某些内存压力场景下内核的回旋余地会窄一些。

这也是为什么我不建议“内存够大就永远不加 swap”。一台 16G 内存跑着 Java 应用的机器,平时用掉 6G,看起来绰绰有余,但业务高峰期一次全量缓存加载可能瞬间冲到 15G 以上,这时候有 4G swap 兜底和没有,结果就是“慢一点”和“进程被杀”的区别。当然前提是这块 swap 所在磁盘的 IO 能力别太差,机械盘上做 swap 在现代负载下体验非常糟糕,SSD 或者本地 NVMe 上是可接受的。

还有一个容易被忽略的点:CentOS 7 的休眠(hibernation)依赖 swap,需要 swap 容量大于物理内存。服务器场景基本用不上,但如果你在虚拟机或者测试机上折腾休眠功能,这一点得记住,容量不够是直接睡不下去的。

1.2 swap 文件、swap 分区、zram 三条路怎么选

在 CentOS 7 上加交换空间,主流就三种做法,各有各的适用边界,我把它们放在一张表里对比,方便你直接对号入座:

方案实现方式优点缺点适用场景
swap 文件在已有文件系统上建一个普通文件不用改分区表、不用重启、随时可加可删、容量调整灵活受文件系统开销影响,性能略低于裸分区;某些文件系统需要额外处理绝大多数在线业务的临时扩容、云主机、无法改分区的情况
swap 分区独立分区,类型 82(MBR)或 8200(GPT)走块设备直读直写,绕开文件系统层,性能最好需要有空闲分区位或未分配空间,可能要停机调整分区表新装系统规划阶段、对 IO 有要求的场景
zram内核模块压缩内存块设备压缩后等效容量大,完全不走磁盘 IOCentOS 7 内核需要额外装kmod-zram,配置略繁琐,吃 CPU内存小、磁盘慢的轻量机、容器宿主机

我的默认建议是:能不动分区表就不动,优先用 swap 文件。原因很现实——生产机器上改分区表的风险和成本远高于收益,而 swap 文件在 SSD 上的性能损失对绝大多数业务来说根本感知不到。只有在新建机器、规划磁盘布局的时候,我才会顺手划一个独立 swap 分区,因为那时候改分区零成本。

zram 这条路在 CentOS 7 上不是默认配置,需要装kmod-zram并手动配置zramctl,属于“有特定需求才折腾”的范畴。如果你的机器内存只有 1G 到 2G,磁盘又是低配云盘,zram 的收益会很明显;但如果你是常规的 8G 以上配置,老老实实用 swap 文件更省心。

1.3 容量定多少:一张能直接抄的对照表

swap 大小没有绝对标准,但业内流传着一套比较通行的对照经验,我在实际项目里也是按这个基准来,再根据业务特性做微调:

物理内存推荐 swap 大小说明
≤ 2 GB内存的 2 倍小内存机器 swap 是刚需,别省
2 GB ~ 8 GB等于物理内存常见的折中方案
8 GB ~ 64 GB4 GB ~ 8 GB内存越大,swap 边际收益越低
> 64 GB4 GB 即可主要作用是兜底,不求容量

举个具体例子:一台 4G 内存的 CentOS 7 云主机,按表应该配 4G swap。但我实际会看它跑什么——如果跑的是 MySQL 且innodb_buffer_pool_size已经吃掉了 3G,那我会把 swap 配到 4G 甚至 6G,因为 MySQL 的内存模型容易出现尖峰;如果只是跑个 Nginx 加静态页面,2G swap 我都嫌多。

再补一个计算细节,避免新手在这里翻车:这里的“G”在dd和fallocate里要用MiB来换算,因为工具按 1024 进制算。4 GiB 就是4096个 1 MiB 块,写成bs=1M count=4096。如果你按 1000 进制敲成count=4000,得到的是 3.9 GiB 左右,虽然不影响使用,但free -h显示出来的数字会让人强迫症发作。

2. 动手前的家底盘点与参数核算

我一向的习惯是:任何资源变更之前,先花两分钟把家底摸清楚。这两分钟能帮你避开至少一半的低级错误,比如在只剩 2G 空间的根分区上想建 4G 的 swap 文件、比如系统里其实早有一个没被激活的 swap 分区、比如你打算放 swap 的那块盘其实是网络存储。下面几条命令,敲完截个图存着,出问题的时候能省很多事。

2.1 四条命令看清内存、磁盘和现有 swap

free -m swapon --show df -h lsblk -f

free -m看内存和 swap 总量,单位 MB,比free -h更适合做精确比对。重点看两列:available是真正可用的内存估算值,Swap那一行如果是0 0 0,说明当前完全没有交换空间。swapon --show会列出已经激活的 swap 设备,如果输出为空,说明确实没有启用的;如果这里有东西,那你得先确认它是不是你想保留的,别重复添加。

df -h用来确认目标分区的剩余空间。这里有个经验值:swap 文件建议不要把分区塞满,至少留 20% 以上余量,因为文件系统本身需要空间做元数据和日志,塞太满会引发一连串奇怪的问题。lsblk -f则是看块设备布局和文件系统类型,这决定了你能不能建 swap 文件——XFS 和 ext4 都没问题,CentOS 7 默认就是 XFS。

# 确认是否已经有 swap 分区但没启用 fdisk -l | grep -i swap cat /proc/swaps

/proc/swaps是最权威的“当前生效列表”,比swapon --show更底层。有时候你会遇到一种情况:/etc/fstab里明明写了 swap 条目,但free显示是 0,那多半是开机时挂载失败了,这时候dmesg | grep -i swap往往能找到原因。

2.2 swappiness 该调到多少

vm.swappiness这个参数控制内核“有多愿意”把匿名页换出去,取值范围 0 到 100。CentOS 7 的默认值是30,不是老版本常见的 60。数值越高,内核越倾向于主动换出;越低,越倾向于保留在内存里、宁可去回收文件页和丢弃缓存。

我见过不少人一上来就抄“改成 1”或者“改成 0”,然后抱怨系统变卡。这里得说清楚:swappiness=0在 CentOS 7 的内核上并不是“完全不用 swap”,它只是在内存和 swap 都够用的时候尽量避免换出,一旦内存真的见底,还是会换。对于服务器,我的实际取值习惯是这样:

  • 数据库、缓存类服务(MySQL、Redis):设成 10。这类进程的内存是它自己精心管理的,被换出去再换回来纯属浪费。
  • 普通 Web、应用服务器:保持默认 30,省事且平衡。
  • 加了 swap 只是为了兜底、内存长期吃紧的机器:可以适当调高到 40 到 60,让内核更早动手,避免临门一脚 OOM。

临时调整用sysctl vm.swappiness=10,永久生效写进/etc/sysctl.d/下新建的配置文件,别直接改/etc/sysctl.conf—— 多文件分层管理更清晰,也方便回滚:

echo 'vm.swappiness = 10' > /etc/sysctl.d/99-swap.conf sysctl -p /etc/sysctl.d/99-swap.conf

注意:swappiness改完之后不会立刻看到效果,它影响的是内核后续的回收决策,观察窗口建议放在几小时甚至一天的量级上,别改完一分钟就去vmstat看一眼然后下结论。

2.3 交换文件放哪个目录、哪块盘

位置选择上有几个原则,都是踩过坑之后总结的:

第一,别放在网络文件系统上。NFS、CIFS 这类共享存储上建 swap,内核直接拒绝,swapon会报错。而且就算能挂上,网络延迟会让 swap 变成灾难。

第二,尽量放在 IO 能力最好的本地盘上。如果你的机器有 SSD 数据盘挂在/data,把 swap 文件放那儿比放根分区更合理,能减少和系统日志争抢 IO。但也要权衡:数据盘如果做的是 RAID 或者有快照策略,swap 文件产生的巨量写入会污染快照、也会让备份变得很臃肿。

第三,避开业务写入热点目录。我一般直接用/swapfile这种根目录下的独立文件,或者在/var/swap/下自建目录。不建议放/tmp,因为有些机器/tmp挂了 tmpfs(重启清空),也有安全加固策略会定期清理/tmp,swap 文件被删掉就麻烦了。

第四,注意 SELinux 上下文。CentOS 7 默认开启 SELinux,在某些自定义目录下创建 swap 文件后swapon可能被拒绝,/var/log/audit/audit.log里会有 AVC 记录。最省事的做法就是放根目录,标准路径的上下文是正确的。

# 确认目标目录所在分区和剩余空间 df -h / # 确认 SELinux 状态,Enforcing 时要注意上下文 getenforce

3. 主力方案:用 swap 文件加交换空间

这是我给 CentOS 7 加交换空间时用得最多的一条路,全流程在线完成,不需要重启,不需要停机,做完立刻生效。整个过程分五步:建文件、改权限、格式化、启用、写 fstab。看起来简单,但每一步都有值得说的细节,尤其是第一步的文件创建方式,选错了后面会莫名其妙报错。

3.1 创建文件的两种写法与 bs/count 换算

创建 swap 文件的标准写法是用dd:

dd if=/dev/zero of=/swapfile bs=1M count=4096 status=progress

if=/dev/zero表示输入源是零设备,of是输出文件,bs=1M count=4096组合起来就是 4096 MiB,也就是 4 GiB。这里bs和count的乘积就是文件大小,改容量只需要改这两个数的乘积,比如 2G 就写bs=1M count=2048,8G 写count=8192。

status=progress是让 dd 输出进度,CentOS 7 的 coreutils 版本支持这个参数,不加的话你会对着一个没有任何输出的终端干等,容易误以为卡死了。如果你手上是更老的系统或者 busybox 的 dd,这个参数会报错,那就去掉,改用kill -USR1 <pid>手动看进度。

bs的取值也有讲究。理论上bs越大写入越快,但超过一定程度收益就很小了,而且占用内存做缓冲。我一般用1M,追求速度的时候用8M或者64M,实测在 SSD 上 4G 的文件大概十几秒到几十秒能写完,具体取决于磁盘。机械盘上就耐心点,这时候可以考虑fallocate。

3.2 fallocate 与 dd 的差别在哪

fallocate是另一条创建路径,速度极快,因为它只分配元数据、不实际写零:

fallocate -l 4G /swapfile

快是快,但它有个历史遗留问题:在某些文件系统上,fallocate分配出来的文件是“稀疏”的,也就是有空洞,mkswap一做校验就会拒绝:

mkswap: /swapfile: warning: don't erase bootbits sectors (dos partition table detected). Use -f to force.

或者更直接的:

swapon: /swapfile: swapon failed: Invalid argument

根因就是文件有空洞,内核不允许把有空洞的文件当 swap 用,因为它无法保证 swap 页的物理映射是连续的。XFS 在 CentOS 7 上对fallocate的支持是比较完整的,一般不会出问题,但我遇到过在 ext4 老内核上翻车的案例。所以我的实际做法是:能用 dd 就用 dd,赶时间可以用 fallocate,但建完必须用下面这条命令验证一下:

filefrag -v /swapfile | head -5

如果输出里extents数量是 1,说明文件是连续的、没有空洞,可以放心用;如果是几十上百个 extent,说明碎片化严重或者有空洞,老老实实删掉用 dd 重建。

提示:如果你确实要用 fallocate 又要确保安全,可以建完之后用dd if=/swapfile of=/dev/null bs=1M完整读一遍,能顺利读完整说明块映射是实的。这一步会花时间,但比出事强。

3.3 权限、mkswap、swapon 一条龙

文件建好之后,接下来三步一气呵成:

chmod 600 /swapfile mkswap /swapfile swapon /swapfile

chmod 600这一步新手最容易漏。swap 文件里存的是进程内存的原始内容,可能是密码、密钥、用户数据,权限必须收紧。如果你跳过这步直接mkswap和swapon,swapon会给你一个警告:

swapon: /swapfile: insecure permissions 0644, 0600 suggested.

这个警告不阻止操作,但会让人误以为成功了。实际上文件确实被启用了,只是权限不对,安全审计过不去。我见过有人在自动化脚本里把这条警告忽略掉,后来安全扫描报了一堆高危,回头查起来还挺费劲。

mkswap的输出会告诉你 UUID、页大小和容量,正常长这样:

Setting up swapspace version 1, size = 4194300 KiB no label, UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

这里有个实用技巧:如果mkswap提示Device or resource busy,说明这个文件已经被某个 swap 占用了,先swapoff再操作。如果提示Killed或者直接卡住,那多半是内存不足导致mkswap进程被杀,这种时候要先把内存压力降下来。

swapon成功是没有输出的,Unix 哲学里“没消息就是好消息”。验证要用:

swapon --show free -h cat /proc/swaps

三条命令任何一条能看到新加的 swap,就说明生效了。

3.4 写进 fstab:格式细节与开机验证

命令行启用只是临时的,重启就没了。要持久化,得写/etc/fstab:

echo '/swapfile none swap defaults 0 0' >> /etc/fstab

这里有个细节我要特别强调:第二种字段(挂载点)不要写swap,写none。虽然写swap在很多系统上也能正常工作,但标准写法是none,因为 swap 没有挂载点的概念。字段含义依次是:设备路径、挂载点、文件系统类型、挂载选项、dump 备份标志、fsck 检查顺序。最后两个都必须是0,swap 不需要备份也不需要 fsck。

更严谨的写法是指定优先级:

echo '/swapfile none swap defaults,pri=10 0 0' >> /etc/fstab

pri参数在多块 swap 时才有意义,数值越大越优先使用。单块 swap 写不写都行,但写上是个好习惯,方便以后扩展。

写完 fstab 千万别直接 reboot 了事。fstab写错导致开机进 emergency mode 是我见过最高频的翻车方式,尤其是在远程服务器上,重启之后连不上,只能提工单。正确的做法是先验证:

# 检查 fstab 语法,这一步不会真的挂载 mount -a # 或者更直观地看 swap 是否被正确识别 swapoff -a && swapon -a free -h

swapoff -a && swapon -a会先关掉所有 swap 再按 fstab 重新启用,如果 fstab 有问题,这一步就会报错,你能在还能连上服务器的时候发现问题。这个操作在内存吃紧的机器上有风险——关掉 swap 的瞬间如果内存不够,可能触发 OOM,所以建议在业务低峰期做,或者先确认free -m的 available 足够。

注意:如果 fstab 里同时存在旧的、已经失效的 swap 条目(比如换了磁盘但没改配置),swapoff -a之后swapon -a会报swapon: cannot find the device,但不会影响其他条目。这类报错不影响开机,但会污染日志,建议清理掉。

3.5 验收:压一压才知道能不能用

swap 加上了、fstab 写了、free也显示了,但这只能说明“配置正确”,不能说明“真的能用”。我习惯做一次轻量压测来验证交换链路是通的。

最温和的方式是用stress制造内存压力:

yum install -y stress stress --vm 1 --vm-bytes 5G --timeout 60s

同时在另一个终端跑:

vmstat 1 10

盯住si和so两列。如果有非零值出现,说明内核确实在换入换出,链路是通的。测完记得确认 swap 使用量回落:

free -m

还有一种更直接的验证方式,是临时把swappiness调到 100 再制造压力,能更快看到 swap 被使用。不过这个测试对线上业务有影响,只建议在测试机或者确认可以承受的机器上做。

如果没有stress,可以用一个最简单的内存占用脚本代替:

# 申请 5G 内存并保持 60 秒 python -c " buf = bytearray(5 * 1024 * 1024 * 1024) import time; time.sleep(60) " &

需要注意的是,如果你的机器内存本来就很充足,压力根本压不到 swap,那说明它暂时不需要 swap,这是好事,不用强求看到交换发生。

4. 备选方案:用 LVM 逻辑卷划 swap 分区

虽然我大部分时候推荐 swap 文件,但有些场景确实该走分区这条路。比如你正在规划一台新机器的磁盘布局,比如机器上有大块未分配的 LVM 空间,比如业务对 IO 延迟极其敏感。这时候用逻辑卷划一个 swap 分区,能绕开文件系统层,性能会好一些。

4.1 什么场景该走分区这条路

判断标准其实不复杂,我列几条,只要命中一条,就可以考虑分区方案:

  • 机器上用的是 LVM,vgdisplay能看到有富余的 free PE,直接lvcreate出一个逻辑卷,比建文件还快。
  • 随时可以重启、可以维护,不怕改分区表。
  • 正在做新机交付的标准镜像,希望布局干净、一目了然。
  • 某些特殊合规要求或运维规范明确要求 swap 必须是独立块设备。

反过来,如果机器是生产环境、不允许停机、根分区空间紧张但没法扩,那还是老老实实用 swap 文件,别为了那点性能去冒停机风险。

4.2 lvcreate 到 mkswap 的完整流程

先确认 LVM 有没有富余空间:

vgs lvs pvs

vgs输出里的VFree就是可用空间。假设卷组叫centos(CentOS 7 默认安装一般是这个名字),要划 4G swap:

lvcreate -L 4G -n swaplv centos

创建完之后设备路径是/dev/centos/swaplv,但也有可能是/dev/mapper/centos-swaplv,两个都指向同一个设备,用哪个都行。然后:

mkswap /dev/centos/swaplv swapon /dev/centos/swaplv swapon --show

写 fstab 的时候建议用/dev/mapper/路径,它比/dev/卷组名/逻辑卷名更稳妥,避免某些情况下符号链接解析出问题:

echo '/dev/mapper/centos-swaplv none swap defaults,pri=20 0 0' >> /etc/fstab

如果机器上还没有 LVM,而是有空闲分区,那就走传统分区路线,用fdisk或者parted划一个类型为82(MBR)或8200(GPT)的分区:

fdisk /dev/sdb # n 新建分区 -> t 改类型 -> 82 (Linux swap) -> w 保存 partprobe /dev/sdb mkswap /dev/sdb1 swapon /dev/sdb1

partprobe这一步别漏,它让内核重新读取分区表,否则/dev/sdb1这个设备节点可能还不存在。

4.3 多块 swap 的优先级 pri 怎么配

当系统里有多块 swap,内核会按pri值从高到低使用,相同pri的情况下会做类似 RAID0 的轮询分配(striping)。这个特性挺有用:

  • 想让 SSD 上的 swap 先用、机械盘上的只在极端情况下用:SSD 那块设pri=100,机械盘设pri=10。
  • 两块盘性能相当,想分摊 IO 压力:设成一样的pri,内核会轮流写,等效于并行 IO。

命令行临时启用时可以直接指定:

swapon -p 100 /swapfile

但注意,命令行指定的优先级只对当次生效,重启后以 fstab 为准。所以持久化配置必须写进 fstab 的挂载选项里。

5. 高频故障与排查实录

swap 相关的问题有个共同点:报错信息都很短,但根因可能隔了十万八千里。我把这些年遇到的、以及帮别人排查过的典型情况整理成一张速查表,遇到问题先扫一遍,能省下不少翻文档的时间。

5.1 报错速查表

报错信息典型原因处理办法
swapon: /swapfile: insecure permissions 0644文件权限过宽chmod 600 /swapfile后重新swapon
swapon failed: Invalid argument文件有空洞、碎片化,或文件系统不支持删除后用dd重建;用filefrag -v验证
swapon: cannot find the devicefstab 里的设备路径失效确认设备存在,更新 fstab 或删除该条目
mkswap: /swapfile: command not found类错误未装util-linux或 PATH 异常yum install -y util-linux
开机进入emergency modefstab 写错,swap 条目无法挂载登录后mount -o remount,rw /,修正 fstab
swapon: /swapfile: read swap header failed忘记执行mkswap先mkswap /swapfile
Device or resource busy该设备已作为 swap 启用先swapoff再操作
dd执行极慢、几乎无进度磁盘性能差或文件系统碎片严重换目标盘;改用fallocate加验证
加了 swap 后系统明显变卡swap 所在磁盘 IO 能力不足迁移 swap 到 SSD;降低swappiness
free显示有 swap 但swapon --show为空是两个不同时刻的状态,或容器命名空间隔离重新确认/proc/swaps

5.2 三个让我半夜爬起来改配置的坑

第一个坑是fstab 写错导致远程机器起不来。那次是给一台云主机加 swap,fstab 里手抖把设备路径写成了/swapfile(多了个空格),重启之后系统直接进 emergency mode,SSH 连不上,最后是通过控制台的 VNC 进去mount -o remount,rw /,用vi改回来才恢复。从那之后我给自己定了规矩:改完 fstab 必须swapoff -a && swapon -a验证,验证通过再重启;如果是不能承受停机的机器,干脆把重启安排在维护窗口。

第二个坑是fallocate 建的文件 mkswap 成功、swapon 失败。当时系统是 ext4,fallocate -l 8G建出来的文件mkswap一路绿灯,swapon报Invalid argument,查了半天以为是 SELinux 或者内核限制。最后用filefrag -v一看,extents 有 60 多个,文件是碎片化的。删掉改用dd重建,一次就好了。这件事让我彻底放弃在不确定的文件系统上用fallocate走捷径。

第三个坑是swap 加上去了,但 OOM 还是发生了。有一台 8G 内存的机器加了 4G swap,业务高峰依然被 OOM Killer 干掉了进程。查dmesg发现 OOM 触发时 swap 只用了 300M。原因是swappiness=30,内核在内存还没见底的时候不愿意换出,等到它想换的时候,内存分配已经是原子上下文,来不及了。后来把swappiness调到 60,并且把 swap 迁到 SSD 上,问题才缓解。这个案例说明:swap 容量和 swappiness 是两个独立的旋钮,只调一个未必有效。

5.3 缩容与删除 swap 的正确顺序

删 swap 的顺序错了会很难受。正确顺序是:先从 fstab 里删掉条目,再swapoff,最后删文件。如果先删文件,正在使用的 swap 会报错;如果先swapoff再改 fstab,中间重启一次就白干了。

# 1. 从 fstab 删除对应行(用 sed 精确匹配,别手抖删错) sed -i '\#^/swapfile#d' /etc/fstab # 2. 停用 swapoff /swapfile # 3. 确认已停用 swapon --show # 4. 删除文件 rm -f /swapfile

swapoff在内存吃紧的机器上是有风险的,它需要把 swap 里的所有页读回内存,如果内存装不下,内核会开始杀进程。所以缩小或删除 swap 前,先看free -m的 available 是否大于当前 swap 使用量,不够就挑低峰期做。

至于缩容(比如把 8G 改成 4G),swap 文件不支持在线缩小,只能删了重建,流程就是上面的删除加重新创建。swap 分区的话可以用swapoff加lvreduce,但同样要先确保内存能扛住。

6. 长期维护:让交换空间不变成拖累

加 swap 是个一次性动作,但它的影响是长期的。我见过太多机器,swap 加上去之后就再也没人看过,直到某天监控报警说磁盘 IO 打满,一查发现是 swap 在被疯狂读写。所以配套的监控和参数固化,比加 swap 本身更重要。

6.1 用 vmstat 和 sar 盯住 si/so

判断 swap 是否健康,看两个指标就够了:换入换出速率,和使用量的趋势。

vmstat 1 5

输出里si(swap in)和so(swap out)单位是 KB/s。正常情况下这两个值应该长期为 0 或者接近 0。如果持续出现几百 KB/s 甚至几 MB/s,说明内存确实不够用,swap 正在承担实际工作负载。这时候要看的不是“swap 够不够大”,而是“哪个进程在吃内存”。

# 按内存占用排序看进程 ps aux --sort=-rss | head -10 # 看 swap 使用分布 for f in /proc/*/status; do awk '/^Name|VmSwap/{printf "%s ", $2} END{print ""}' $f 2>/dev/null; done | sort -k2 -n -r | head

这条 for 循环能列出每个进程的VmSwap,直接告诉你谁的哪部分内存被换出去了。如果发现是某个 Java 进程大量被换出,那基本可以确定堆设置不合理,得回去调-Xmx。

sar需要装sysstat包,能看历史趋势,比vmstat更适合做容量规划:

yum install -y sysstat systemctl enable --now sysstat sar -S 1 5 # 实时看 swap 使用 sar -S -f /var/log/sa/sa15 # 看某天的历史数据

6.2 把参数固化到 sysctl 与监控里

参数这块,我建议统一放在/etc/sysctl.d/99-swap.conf,内容参考:

vm.swappiness = 10 vm.vfs_cache_pressure = 50

vfs_cache_pressure控制内核回收 dentry 和 inode 缓存的倾向,默认 100。调低到 50 会让内核更倾向于保留文件系统缓存,间接减少匿名页被换出的压力。这个参数对文件服务器、Web 服务器效果比较明显,但也别调太低,太低会导致内存里堆积大量缓存,反而挤占应用内存。

监控方面,我一般会配两条告警规则:

  • swap 使用率超过 50% 持续 10 分钟:说明内存长期不足,需要扩容或优化应用。
  • si或so持续大于 1024 KB/s 超过 5 分钟:说明 swap 正在进行高频 IO,磁盘可能成为瓶颈。

这两条规则的阈值不是拍脑袋定的。50% 是个经验分界线,超过它说明系统已经有一半的内存压力转移到了磁盘上;1024 KB/s 则是考虑到即使是 SSD,持续的兆级 swap IO 也会明显影响其他服务的 IO 响应时间。

最后补一个容易被忽略的点:容器环境里的 swap 是受限的。如果这台 CentOS 7 上跑着 Docker,容器默认继承宿主机的 swap 配置,但--memory-swap参数会限制单个容器能用的 swap 上限。宿主机加了 swap,不等于容器能用到,这一点在做资源规划的时候要对齐清楚,不然会出现“宿主机明明有 swap,容器还是被 OOM”的情况。

我个人在实际操作中的体会是,swap 这东西属于“平时想不起来、出事时指望它”的基础设施。真正决定它价值的不是容量大小,而是你有没有搞清楚它为什么存在、什么时候会被用到、用到什么程度就该报警。我现在的习惯是每接手一台 CentOS 7,第一件事就是跑一遍free -m和swapon --show,看到 swap 是 0 就先按内存大小配一份,顺便把swappiness和监控一起落了——这套动作五分钟能做完,但省下的是未来某天凌晨被电话叫醒的麻烦。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进