Linux swap 交换分区调优:服务器内存压力管理实战

当一台服务器的物理内存接近耗尽时,进程可能被内核直接杀掉,表现为网站突然超时、数据库连接被拒绝。Linux swap(交换分区)就是在这种场景下的兜底手段:它把一部分磁盘空间当作内存的溢出区,让系统在物理内存不足时仍然能够喘过气来。这篇指南教你如何按实际负载规划 swap 大小、调整 swappiness(内核换出的倾向程度)参数、监控交换活动的趋势,并在内存压力结束后安全回收 swap 空间。

swap 的调优本质上是在“性能”和“存活”之间做权衡:用磁盘换内存会让速度变慢,但总比 OOM(Out Of Memory,内存耗尽)时进程直接被杀死要好。下面我们从原理讲起,再一步步给出可执行的配置与验证方法。

Linux swap 交换分区调优 封面配图:物理内存到交换分区的溢出示意

理解 swap 的作用与代价

swap 是内核把物理内存中暂时不用的页面(page,内存管理的最小单位)写到磁盘的机制。当系统内存不足时,内核通过页交换把这些冷页面挪到交换区,腾出物理内存给正在热用的进程。对数据库或高并发的 Web 服务来说,swap 的真正价值不在于让它运行得更快,而在于避免瞬间的内存尖峰直接导致服务崩溃。

不过 swap 有清晰的代价。磁盘的随机读写延迟远高于内存——固态硬盘的随机读延迟通常在 0.1 毫秒左右(典型区间),而内存只有纳秒级。如果频繁触发 swap 换出换入,进程可能因为等待磁盘 I/O 而明显变慢,这在 MySQL、Redis 这类对延迟敏感的应用上尤为明显。一个典型的例子是:当 Redis 使用 swap 时,单个键的读写延迟可能从微秒级别跳到毫秒级别,直接影响线上响应时间。

 # 查看当前系统是否启用了 swap 以及交换量
 free -h
 swapon --show

上面的命令会告诉你系统当前有没有交换分区、交换了多少。如果 swapon --show 没有任何输出,说明这台机器目前没有启用 swap。要判断是否需要它,可以先观察物理内存的占用率,再结合实际流量来定,而不是一上来就盲目添加。

判断是否需要配置 swap

是否配置 swap,取决于你的业务类型和可用物理内存。对大多数生产服务器,我们给出的判断思路是这样的:先看内存水位,再看应用属性,最后决定 swap 的大小和类型。

如果服务器主要跑的是 Nginx、PHP-FPM 这类 Web 服务,内存占用会随并发上涨而波动,配置一个适度的 swap 作为缓冲是有价值的。如果跑的是 MySQL 等常驻数据库,我们更建议优先保证物理内存充足,把 swap 当作最后的保险丝,而不是常规运行空间。你可以参考 服务器监控搭建实践 一文,先建立内存与负载的可观测性,再判断 swap 是否真的会成为瓶颈。

判断是否需要 swap 的最小步骤:

 # 查看运行中的进程占用内存的排序,找内存大户
 ps aux --sort=-%mem | head -20
 # 查看内存压力相关统计是否有回收活动
 cat /proc/pressure/memory

/proc/pressure/memory 里的 some 列代表有至少一个任务在等待内存的累计时间比例(示例值 0.05 表示约 5% 的时间有内存等待)。如果这个值持续偏高,同时物理内存接近占满,就值得配置 swap 来缓冲压力尖峰。

如何规划 swap 大小与类型

swap 的大小没有放之四海皆准的答案,我们给出基于内存容量的参考区间,实际值应结合你的工作负载调整。对 2GB 物理内存的 [VPS](https://cn.hostease.com/vps/)(Virtual Private Server,[虚拟专用服务器](https://cn.hostease.com/vps/))来说,建议 swap 设为 1GB 到 2GB(示例);对 8GB 及以上内存的服务器,swap 在 2GB 到 4GB 往往就够用(典型区间),因为大内存机器更依赖 swap 的保险丝角色而非容量本身。

这里需要澄清一个常见误区:swap 不是越大越好。过大的 swap 会让内核倾向于把更多页面换出,反而拖慢性能;过小的 swap 则无法在内存尖峰时起到缓冲作用。决定“恰好”的值,要看 swap 实际换出了多少——如果常年只用到几百 MB,说明配多了;如果一旦触发就马上耗尽,说明配少了。

swap 有两种常见形态:一种是传统的磁盘分区或文件(swapfile),另一种是基于内存的 zram(把压缩后的页面放进内存)。对追求极致延迟的 Redis、数据库负载,可以把一部分 zram 作为缓冲;对需要持久化兜底的普通服务器,磁盘上的 swapfile 更直接。下面是一种在根分区上创建 swapfile 的做法:

 # 以 2GB 为例,创建可交换的稀疏文件
 sudo fallocate -l 2G /swapfile
 sudo chmod 600 /swapfile
 sudo mkswap /swapfile
 sudo swapon /swapfile

创建后要写入 /etc/fstab 让它在重启后自动挂载,否则重启就失效。如果你管理多台服务器,建议把 swap 的分配记录在统一配置清单里,避免不同机器参数不一致带来的排查困难。

用 swappiness 控制换出倾向

swappiness 是内核决定“多积极地换出匿名内存页”的系数,取值从 0 到 100,默认通常是 60。数值越高,内核越愿意把内存页面挪到 swap;数值越低,越倾向于优先复用缓存并尽量保留物理内存。

对数据库这类延迟敏感的应用,我们通常把 swappiness 调低(例如 10),让内核尽量少用 swap、优先挤压文件缓存。对内存经常告警、容易 OOM 的 Web 服务器,可以维持中等偏低的默认值或略作上调,避免进程被杀死。调整方法是对每个运行中的实例实时生效,同时写入 sysctl 配置以便重启后保留:

 # 实时调整(示例值 10)
 sudo sysctl vm.swappiness=10
 # 持久化到配置文件
 echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.d/99-swap.conf
 sudo sysctl --system

调完 swappiness 后建议观察一到两个业务周期,重点看两点:内存压力是否缓解、关键进程的延迟有没有因为换出而变差。如果调低后 OOM 反而更容易发生,就适当回调。这个参数没有最优的绝对值,只有适合你负载的区间。在高并发 Web 层的场景下,可以把 Nginx 与 PHP-FPM 的内存控制结合 Nginx 限流与速率限制配置 一起看,先抑制流量尖峰,再调整内存参数,效果往往好于只调 swap。

swappiness 参数高低对比示意:低倾向保留内存,高倾向换出到交换分区

监控 swap 使用与内存压力

swap 调优的反馈闭环必须建立在监控之上。仅用 free -h 看一眼剩余值远远不够,因为 swap 的“总量变化”会掩盖“换出频率”这一关键信号。高换出频率意味着系统在做大量无效搬移,即使 swap 总量没满,也不代表健康。

推荐关注的指标包括:swap 已用与可用、swap in/out 的页交换速率,以及 /proc/pressure/memory 的等待时间。你可以用 vmstat 快速采样换页速率:

 # 每秒采样一次,连续 10 次,重点看 si(swap in)和 so(swap out)
 vmstat 1 10

如果 si(从 swap 读回内存的页数)和 so(写入 swap 的页数)这两列持续出现非零值,说明系统正在频繁交换,需要进一步排查是物理内存不足,还是 swappiness 设置过高。把这类指标纳入常驻监控,可以更早发现容量规划的缺口。配合 Grafana 服务器运维监控部署实战 建立内存与换页的看板,能让 swap 的走势一目了然。

内存回收与 swap 空间整理

当内存压力已经过去、系统运行平稳时,长期滞留的 swap 内容不会自动归还,会让交换区保持高占用状态,既浪费可查询的缓冲能力,也可能在下次尖峰时触发不必要的换页。此时可以主动回收 swap:先把 swap 内容搬回内存,再重新启用。

 # 确认有足够空闲内存后,关闭 swap 再重新开启
 sudo swapoff /swapfile
 sudo swapon /swapfile

执行 swapoff 会把 swap 里的页面全部读回物理内存,因此务必在内存余量充足时进行,否则可能把压力转移到物理内存甚至导致 OOM。回收后可以再次运行 free -h 确认 swap 已清零。如果是长期高负载的数据库服务器,我们不建议频繁做这种回收操作,因为它本身会带来一次短暂的 I/O 抖动;更稳妥的做法是把监控与回收写成定时观察的流程,只在真正必要的时候手动执行。关于内存压力下数据库类的慢查询监控,可以结合 MySQL 慢查询分析方法与优化实践 一起排查,判断问题是来自内存还是查询本身。

常见误区与排障经验

swap 相关的排障,最常见的是把症状和根因搞混。系统内存紧张时,日志里可能出现进程被 OOM 杀死,很多人第一反应是加大 swap。但如果根因是某个应用存在内存泄漏,或者物理内存本身就规划不足,加大 swap 只会延缓崩溃,并不会解决根本问题。

 # 查看内核记录的 OOM 事件,判断是谁在消耗内存
 dmesg | grep -i "oom" | tail -20
 # 结合进程历史,定位内存增长最快的进程
 ps aux --sort=-%mem | head -10

一个常见误区是:只要加了 swap 就高枕无忧。实际上,如果应用对延迟极度敏感,swap 的引入反而可能带来不可接受的性能波动。另一个误区是在 32 位系统或老内核上盲目追求大 swap,受寻址与文件系统限制,这类部署往往达不到预期效果。判断问题方向时,建议先排除配置层面的因素,例如 Redis 这类内存数据库是否因为持久化或淘汰策略配置不当而占满内存,可参考 Redis 数据持久化与恢复机制全面解析 排查内存配置与淘汰策略。

内存在压力过后回收并整理交换分区空间的过程示意

最后总结一下可落地的操作顺序:先用 free -h/proc/pressure/memory 确认是否真的存在内存压力;再按负载类型规划 swap 大小并创建;接着用 sysctl 调整 swappiness 并持久化;随后通过 vmstat 与监控看板持续观察换页速率;最后在压力结束后按需回收。对内存经常告警的业务,把监控做扎实往往比反复调参更能提前发现容量问题。你现在就可以打开终端,用 free -hvmstat 1 5 验证一遍这台服务器是否存在换页活动;如果你的服务器规格有限、内存经常吃紧,你也可以结合 Hostease 的 VPS 主机方案 评估更充裕的内存配置,避免把 swap 当作长期运行空间。如果你需要把这套方法应用到自己的服务器,可以先从调整 swappiness 开始,再逐步验证效果。

发表评论