1. 从一次线上告警说起:swap 到底该不该开
凌晨两点,某台跑了十几个容器实例的服务器突然开始疯狂告警,内存使用率飙到 95% 以上,SSH 登录进去敲个命令都要等好几秒。第一反应是某个服务内存泄漏,结果free -h一看,物理内存确实快满了,但 swap 分区几乎没怎么用。当时脑子里冒出的第一个念头就是:swap 是不是没开够,或者根本没生效?
这个场景我相信不少做运维或者后端的朋友都遇到过。关于 Linux 上的 swap,圈子里一直有两派观点:一派认为 swap 是保命符,物理内存不够时能顶上去,避免进程被 OOM Killer 直接干掉;另一派认为 swap 是性能杀手,一旦用上磁盘交换,延迟直接起飞,还不如让进程干脆点被杀死然后快速重启。这两种说法都有道理,但前提是你得先搞清楚 swap 到底是什么、怎么配、怎么启停、什么时候该调。
这篇内容就围绕Linux swap 及启停操作这个主题,把 swap 的底层逻辑、配置方法、启停流程、参数调优和常见坑一次性讲透。不管你是刚接触 Linux 的新手,还是已经管过几十台机器的老手,都能从中找到可以直接抄作业的操作步骤和排查思路。我会尽量用大白话把原理讲清楚,同时给出完整的命令行操作,保证你看完就能上手。
2. swap 的本质:它到底在解决什么问题
2.1 物理内存不够时的缓冲垫
先打个比方。物理内存就像你办公桌上的面积,进程就是桌上的文件。桌子就那么大,文件多了放不下,怎么办?你可以把暂时不看的文件先放到旁边的抽屉里,等要用的时候再拿回来。swap 就是这个抽屉,它位于磁盘上,速度比内存慢得多,但容量可以做得很大。
Linux 的内存管理采用虚拟内存机制,每个进程都以为自己拥有一整块连续的内存空间。当物理内存紧张时,内核会把一些不常访问的内存页(page)写到 swap 空间,腾出物理内存给更活跃的进程使用。这个过程叫换出(swap out),当进程再次访问这些页时,再换入(swap in)回内存。整个机制对应用是透明的,进程本身感知不到。
关键点在于:swap 不是用来提升性能的,它是用来防止内存耗尽导致系统崩溃或进程被杀的。理解这一点,后面很多决策就顺了。
2.2 swap 的几种存在形式
swap 在 Linux 上有两种常见形态,选择哪种直接影响后续的启停操作方式。
| 形式 | 说明 | 优点 | 缺点 |
|---|---|---|---|
| swap 分区 | 独立的分区,类型为 Linux swap | 性能稳定,不依赖文件系统 | 创建后调整大小麻烦,需要重新分区 |
| swap 文件 | 普通文件,通过 mkswap 格式化 | 灵活,随时可增可减 | 性能略受文件系统影响,需注意碎片 |
早期大家习惯划一个独立分区,因为机械硬盘时代分区连续性好,性能有优势。现在 SSD 普及,文件系统和裸设备的性能差距已经很小,swap 文件的灵活性优势就凸显出来了。尤其是云服务器,很多默认就是用 swap 文件,扩容缩容都方便。
提示:如果你用的是 LVM 逻辑卷,也可以创建 LV 作为 swap,兼具灵活性和分区性能,是折中方案。
2.3 swappiness:决定内核多积极使用 swap
vm.swappiness是 swap 相关最重要的一个内核参数,取值范围 0 到 100。它表示内核在回收内存时,使用 swap 的倾向程度。值越高,内核越倾向于把内存页换出到 swap;值越低,越倾向于保留在内存里,必要时直接回收缓存。
很多人误以为 swappiness=0 就是完全禁用 swap,这是错的。即使设为 0,在内存极度紧张时内核仍然可能使用 swap,只是积极性最低。真正禁用 swap 要用swapoff。
不同场景的推荐值:
- 数据库服务器:建议 1 到 10。数据库对延迟极其敏感,宁可多用缓存也不愿换出。
- 通用服务器:建议 10 到 30。平衡内存利用和性能。
- 桌面/开发机:建议 60 左右,默认值即可,内存不够时能顶住。
- 容器宿主机:建议 0 到 10,避免容器内存被换出导致抖动。
这个值可以通过sysctl临时调整,也可以写进配置文件持久化,后面实操部分会详细讲。
3. 查看当前 swap 状态:先摸清家底再动手
3.1 用 free 快速看全局
最常用的命令就是free,加上-h参数让数字带单位,可读性更好。
free -h输出大概长这样:
total used free shared buff/cache available Mem: 15Gi 12Gi 1.2Gi 300Mi 2.5Gi 2.1Gi Swap: 4.0Gi 512Mi 3.5Gi这里重点看 Swap 那一行。total 是 swap 总大小,used 是已使用量,free 是剩余量。如果 total 是 0,说明当前系统没有启用任何 swap。
available这一列也值得关注,它表示在不使用 swap 的情况下,还能给新进程分配多少内存。这个数字比 free 更有参考价值,因为它把可回收的缓存也算进去了。
3.2 用 swapon 看具体设备
free只给总量,想知道具体是哪个分区或文件在充当 swap,用swapon命令。
swapon --show或者老一点的写法:
swapon -s输出会列出每个 swap 设备的名称、类型、大小和已使用量。比如:
NAME TYPE SIZE USED PRIO /swapfile file 4G 512M -2 /dev/sda2 partition 2G 0B -3PRIO 是优先级,数值越高越优先使用。多个 swap 设备时,内核会先用在优先级高的设备上。如果优先级相同,则会轮询使用(类似 RAID0 的条带效果),这在多块磁盘时能提升 swap 吞吐。
3.3 用 /proc/swaps 看内核视角
还有一个更底层的方式,直接读内核暴露的接口:
cat /proc/swaps内容和swapon --show基本一致,但这是内核实际识别的状态,排查问题时更权威。有时候配置文件写了但没生效,看这个文件就能确认。
3.4 检查内存和 swap 的实时压力
想知道 swap 到底有没有在被频繁读写,可以用vmstat观察 si 和 so 两列。
vmstat 1 5si 表示每秒从 swap 换入的内存页数,so 表示每秒换出的页数。如果这两个值长期非零,说明系统内存压力大,正在频繁交换,这时候性能大概率已经受影响了。单位是 KB,如果 si/so 达到几万甚至几十万,那基本可以确定内存严重不足。
注意:偶尔出现非零的 si/so 是正常的,比如某个大进程刚启动时。关键是看是否持续。
4. 创建 swap:分区和文件两种方式
4.1 创建 swap 文件(推荐,最灵活)
这是目前最常用的方式,尤其适合云主机和容器环境。整个过程分几步:创建文件、设置权限、格式化、启用、持久化。
第一步,用fallocate或dd创建一个指定大小的文件。fallocate速度更快,因为它直接分配磁盘块,不实际写入数据。
sudo fallocate -l 4G /swapfile如果文件系统不支持fallocate(比如某些老旧的 ext3 或特殊文件系统),用dd兜底:
sudo dd if=/dev/zero of=/swapfile bs=1M count=4096bs=1M count=4096就是 4096 个 1MB 块,合计 4GB。dd会实际写入零,所以慢一些,但兼容性最好。
第二步,设置权限。swap 文件里可能包含敏感的内存数据,必须限制访问。
sudo chmod 600 /swapfile第三步,格式化为 swap。
sudo mkswap /swapfile输出会显示 UUID 和大小,确认无误。
第四步,启用。
sudo swapon /swapfile第五步,验证。
swapon --show free -h第六步,持久化。编辑/etc/fstab,加一行:
/swapfile none swap sw 0 0这样重启后会自动挂载。注意不要写错字段,否则可能导致开机失败。
4.2 创建 swap 分区
如果是在裸机或虚拟机上,还有未分配的空间,可以划一个分区出来。用fdisk或parted操作。
sudo fdisk /dev/sdb进入交互界面后,依次按n新建分区,p选主分区,设置起止扇区,然后按t把分区类型改成82(Linux swap),最后w保存。
分区创建后,格式化和启用:
sudo mkswap /dev/sdb1 sudo swapon /dev/sdb1持久化同样写进/etc/fstab:
/dev/sdb1 none swap sw 0 0提示:分区方式一旦确定,调整大小比较麻烦,需要删除重建。所以规划时留点余量。
4.3 swap 大小怎么定
这是个老生常谈的问题。传统建议是物理内存小于 2GB 时,swap 设为内存的 2 倍;2GB 到 8GB 时设为等于内存;大于 8GB 时设为 4GB 到 8GB。但这套规则来自内存昂贵的年代,现在参考价值有限。
更实际的判断依据:
- 是否要休眠(hibernate):如果要支持休眠,swap 必须大于等于物理内存,因为休眠时要把整个内存内容写入 swap。
- 内存是否经常吃紧:如果监控显示内存长期在 80% 以上,swap 可以给大一点,比如内存的 50% 到 100%。
- 是否有大内存机器:128GB 以上的机器,swap 给 8GB 到 16GB 通常够用,主要作为应急缓冲。
- 容器环境:容器一般不单独配 swap,由宿主机统一管理。
我个人的习惯是,通用服务器给 4GB 到 8GB,数据库服务器给 2GB 到 4GB 并调低 swappiness,桌面机给内存的一半。这个没有标准答案,结合监控数据调整最靠谱。
5. 启停 swap:命令、顺序和注意事项
5.1 启用单个 swap 设备
启用用swapon,后面跟设备路径或文件路径。
sudo swapon /swapfile sudo swapon /dev/sdb1如果想一次启用/etc/fstab里所有 swap 条目,可以用:
sudo swapon -a这个命令在开机脚本里会调用,手动执行时也会读取 fstab,把没启用的都启用。
5.2 停用 swap 设备
停用用swapoff,同样跟路径。
sudo swapoff /swapfile sudo swapoff /dev/sdb1停用所有:
sudo swapoff -a这里有个关键点:停用 swap 时,内核需要把 swap 里所有已使用的页换回物理内存。如果物理内存不够,这个操作会失败,甚至触发 OOM。所以停用前一定要确认内存有足够余量。
可以先看free -h,如果 swap used 比较大而物理内存 free 很小,贸然swapoff风险很高。稳妥做法是先释放缓存、停掉非核心服务,或者分批停用。
5.3 调整 swap 优先级
多个 swap 设备时,可以用-p指定优先级。
sudo swapon -p 10 /dev/sdb1 sudo swapon -p 5 /swapfile优先级高的先用。如果想让两块盘并行分担 swap 压力,设成相同优先级即可。
持久化优先级要写在 fstab 的 options 字段:
/dev/sdb1 none swap sw,pri=10 0 0 /swapfile none swap sw,pri=5 0 05.4 修改 swap 大小的完整流程
假设原来的 swap 文件是 2GB,想扩到 8GB。步骤是:先停用,删除旧文件,创建新文件,格式化,启用。
sudo swapoff /swapfile sudo rm /swapfile sudo fallocate -l 8G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfilefstab 里的条目不用改,因为路径没变。最后free -h确认新大小生效。
注意:停用前务必确认内存够用,否则可能卡死。生产环境建议在低峰期操作,并提前准备好回滚方案。
6. 内核参数调优:让 swap 用得更聪明
6.1 调整 swappiness
临时调整:
sudo sysctl vm.swappiness=10持久化写入/etc/sysctl.conf或/etc/sysctl.d/下的配置文件:
vm.swappiness = 10然后执行sudo sysctl -p生效。
前面说过,数据库服务器建议调低,通用服务器适中。这个值不是一成不变的,可以结合监控动态调整。比如发现 si/so 频繁但内存还有余量,说明 swappiness 偏高,可以降一点。
6.2 调整 vfs_cache_pressure
这个参数控制内核回收 inode 和 dentry 缓存的倾向,默认 100。值越高越倾向于回收缓存,值越低越倾向于保留。对于文件访问密集的服务,适当调低(比如 50)能提升缓存命中率,间接减少 swap 压力。
sudo sysctl vm.vfs_cache_pressure=506.3 调整 min_free_kbytes
这个参数决定内核保留的最小空闲内存。值太小,内存回收不及时,容易触发直接回收导致卡顿;值太大,又浪费内存。默认值由内核根据内存大小自动计算,一般不用动。特殊场景下可以微调,比如内存很大的机器适当调大,避免突发分配失败。
cat /proc/sys/vm/min_free_kbytes6.4 关闭 swap 的几种场景
有些场景确实建议关闭 swap:
- Kubernetes 节点:kubelet 默认要求关闭 swap,否则调度和资源计算会不准。新版本虽然支持 swap,但配置复杂,多数生产环境仍关闭。
- 高性能数据库:如某些内存数据库,宁可 OOM 也不愿换出导致延迟抖动。
- 实时性要求高的服务:swap 换入换出的延迟不可控,会影响响应时间。
关闭方法就是swapoff -a,然后注释掉 fstab 里的 swap 条目,防止重启后恢复。
7. 常见问题与排查技巧实录
7.1 swap 没生效,free 显示为 0
可能原因有几个:一是 fstab 写错,字段不对或路径不对;二是文件权限不对,mkswap 后没 chmod 600;三是文件系统不支持,比如某些网络文件系统;四是 SELinux 或 AppArmor 拦截。
排查顺序:先swapon --show看有没有识别,再看dmesg | tail有没有报错,然后检查 fstab 语法,最后确认权限和文件系统类型。
7.2 swapoff 卡住或失败
多半是内存不够,内核无法把 swap 里的页换回。解决办法:先释放缓存echo 3 > /proc/sys/vm/drop_caches,停掉非核心服务,或者分批停用多个 swap 设备。如果实在不行,只能重启。
7.3 swap 使用率居高不下
说明内存长期不足。短期可以调大 swap 或调低 swappiness 缓解,但根本解决要么加内存,要么优化应用内存占用。用smem或ps aux --sort=-rss找出吃内存大户。
7.4 系统变慢但 CPU 不高
这很可能是 swap 抖动。用vmstat 1看 si/so,如果持续很高,基本可以确定。进一步用iotop看磁盘 IO,swap 设备的读写会很明显。解决办法是加内存或减少内存占用。
7.5 常见问题速查表
| 现象 | 可能原因 | 排查命令 | 解决方向 |
|---|---|---|---|
| swap total 为 0 | 未创建或未启用 | swapon --show | 创建并启用 |
| swapoff 失败 | 内存不足 | free -h | 释放内存或分批停用 |
| si/so 持续高 | 内存压力大 | vmstat 1 | 加内存或调优 |
| 开机 swap 未挂载 | fstab 错误 | dmesg | 修正 fstab |
| swap 文件权限错误 | 未 chmod 600 | ls -l | 重新设置权限 |
提示:排查 swap 问题时,养成先看
free -h、再看swapon --show、最后看dmesg的习惯,大部分问题能快速定位。
8. 实操心得与避坑经验
8.1 云主机上的 swap 陷阱
很多云厂商的默认镜像是不带 swap 的,尤其是高内存机型。原因之一是云盘 IO 有额外计费,频繁 swap 会产生成本。另一个原因是云厂商希望用户通过升配解决内存问题。所以拿到云主机后,第一件事就是确认 swap 状态,按需创建。
另外,云主机的系统盘通常不大,创建 swap 文件时注意别把根分区撑满。建议单独挂一块数据盘做 swap,或者控制文件大小。
8.2 容器环境的 swap 处理
Docker 默认容器可以使用宿主机的 swap,但可以通过--memory-swap限制。Kubernetes 则默认禁用 swap。在容器里跑内存敏感服务时,要特别注意宿主机 swap 的状态,避免容器内存被换出导致性能抖动。
如果宿主机 swap 很大而 swappiness 又高,容器里的进程可能被换出,表现为响应变慢但 CPU 不高。这时候调低宿主机 swappiness 或给容器设置内存限制更有效。
8.3 SSD 寿命的顾虑
有人担心 swap 频繁读写会缩短 SSD 寿命。实际上现代 SSD 的写入寿命(TBW)都很高,正常 swap 使用量远达不到损耗阈值。真正伤 SSD 的是持续大量写入,比如日志或数据库。swap 的写入量通常很小,除非内存严重不足导致持续交换,那种情况下性能问题比寿命问题更紧迫。
8.4 监控 swap 的实用指标
生产环境建议监控这几个指标:swap 使用率、si/so 速率、swappiness 当前值、OOM 事件次数。swap 使用率持续超过 50% 就值得关注,si/so 持续非零说明内存有压力,OOM 事件则说明已经出过问题。
可以用sar -S看历史 swap 使用,用sar -W看换入换出速率。这些数据对容量规划很有价值。
8.5 一个容易忽略的细节
/etc/fstab里 swap 条目的 options 字段,很多人只写sw,其实还可以加nofail。这样即使 swap 设备不存在,开机也不会卡住。对于云主机或经常调整磁盘的环境,这个选项很实用。
/swapfile none swap sw,nofail 0 0另外,如果 swap 文件所在的分区是 XFS,fallocate创建的文件可能有问题,建议用dd。这是 XFS 的一个已知特性,创建 swap 文件时要注意。
8.6 关于 swappiness 的一个误区
网上很多文章说 swappiness=0 就是禁用 swap,这是不准确的。前面提过,0 只是最低倾向,内核在必要时仍会使用 swap。真正禁用要用 swapoff。而且某些内核版本对 swappiness=0 的处理有差异,极端情况下可能导致 OOM 行为变化。所以如果目的是禁用 swap,直接 swapoff 更明确。
8.7 调整 swap 后的验证清单
每次调整 swap 后,建议按这个清单验证一遍:
free -h确认总量和可用量。swapon --show确认设备列表和优先级。cat /proc/swaps确认内核识别。sysctl vm.swappiness确认参数生效。- 重启一次,确认持久化配置正确。
这套流程走下来,基本能覆盖所有配置点,避免遗漏。
9. 写在最后的一点个人体会
swap 这个东西,说简单也简单,创建、启用、调参,几条命令的事;说复杂也复杂,涉及内存管理、性能权衡、场景适配,每个决策背后都有取舍。我自己的经验是,不要迷信任何一种教条,什么“必须开”或“必须关”都是片面的。关键是理解它的工作原理,然后结合自己的业务特点、硬件配置和监控数据来做判断。
对于大多数通用服务器,开一个适中的 swap,把 swappiness 调到 10 到 30,基本就能兼顾稳定性和性能。数据库和容器节点则要更保守一些。至于那些内存充足、延迟敏感的服务,关掉 swap 也完全合理。没有银弹,只有适合当前场景的方案。
最后分享一个小技巧:如果你不确定该不该开 swap,可以先开一个小一点的,比如 2GB,然后观察一段时间 si/so 和内存使用率。如果 swap 几乎没被用过,说明内存充足,开不开无所谓;如果 swap 用得很多,那要么加内存,要么优化应用,swap 只是给你争取时间的缓冲。数据不会骗人,让监控说话比拍脑袋靠谱得多。