ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

Linux Swap 交换分区深度解析:从原理到性能调优

Linux Swap 交换分区深度解析:从原理到性能调优 1. 从一次线上事故说起Swap 到底是什么前阵子我们小组在排查一个服务异常时碰到一个现象某台机器明明内存占用才 60%但服务接口的响应突然变得极慢甚至出现假死。登录服务器一看free -h 显示 Swap 被吃掉了好几个 G而正在运行的 Java 进程的 GC 日志里全是长时间停顿。那个瞬间我才真正意识到很多日常开发对 Swap 的认知还停留在“内存不够了才用”这个层面但实际上Swap 的触发时机、回收策略、内核参数调优都会直接影响生产环境的稳定性。这篇文章就把我对 Linux Swap 交换分区的理解、日常操作方法和踩过的坑整理出来希望对你有帮助。Swap 在 Linux 系统里就是一块磁盘空间专门用来充当内存的“后备队”。当物理内存RAM不够用的时候内核会把一些暂时没用的内存数据挪到 Swap 分区或 Swap 文件里腾出物理内存供当前活跃的进程使用。反过来当进程又需要这些数据时内核会把它们从 Swap 换回物理内存。听起来很简单对吧但实际用起来远不止这些。Swap 的规划是否合理、参数是否调优、生命周期管理是否到位决定了它是帮你兜底的保险丝还是拖垮整台机器性能的隐形炸弹。2. 深入理解 Swap它的真实作用与存在价值2.1 为什么有物理内存还要 Swap很多人问现在服务器内存动辄 64G、128G还要 Swap 干什么这个问题的核心在于内存的“尖峰需求”。拿数据库来说平时查询量平稳时内存占用可能在 30G 左右但如果某个时刻来了一个异常复杂的全表扫描内存瞬间可能飙到 50G。如果你不给系统留出 Swap 的缓冲空间内存直接被打满内核就会启动 OOM Killer 去杀进程。OOM Killer 的逻辑有时候很粗暴它不一定会杀你心里想的那个进程可能直接把关键的数据库进程干掉。我曾经在一台 64G 内存的机器上部署过一个数据分析任务数据量平时很稳定结果有一天上游数据源推送了一批异常数据任务瞬间把内存吃掉了 62G。如果没有配 SwapRedis 进程大概率被 OOM Killer 误杀。而那台机器正好配了 8G 的 Swap 分区系统硬是扛住了这次尖峰任务虽然慢了一些但至少服务没有全挂。所以 Swap 的核心价值不是替代物理内存而是给系统提供一个“喘息空间”让内存使用率不至于快速打到 100% 就触发杀进程的悲剧。2.2 Swap 的代价为什么说它“慢”Swap 用起来是有代价的而且是沉重的代价。物理内存的访问速度是纳秒级别的以 DDR4 内存为例延迟大约在几十纳秒到几百纳秒而普通 SSD 的访问延迟在几十微秒级别机械硬盘更是毫秒级别。这个差距意味着当进程发生频繁的 Swap 换入换出时性能下降可能是几百倍甚至上千倍。所以一定要搞清楚一个概念Swap 是防死机制不是加速机制。它存在的意义是当内存真的不够时系统不至于立即崩溃给运维留出介入和处理的时间。如果你把 Swap 当成内存的“扩容工具”指望它显著增加可用内存总量那方向就错了。2.3 现代 Linux 环境下 Swap 的定位变化早年间内存昂贵服务器配个 2G 内存都算奢侈那时候 Swap 对很多人来说是“扩容手段”。如今内存便宜了机器标配几十个 G 甚至上百 GSwap 的定位也悄然发生了变化。现代场景下Swap 更多出现在这几种情况休眠suspend-to-disk需要 Swap 来保存内存镜像某些内存使用有尖峰特性的应用比如编译大型项目时临时内存暴涨内存碎片化严重时Swap 可以辅助内存回收容器和虚拟化环境中限制内存但不想 OOM 的场景此外在系统层面Linux 内核还会用 Swap 来实现内存页的“冷热分离”。内核通过 LRULeast Recently Used算法维护一个“最近最少使用”的页面列表长时间没有被访问的匿名页进程堆、栈等会被标记为冷页。当物理内存紧张时内核会优先把这些冷页换出到 Swap从而为主城区腾出空间。这个机制让有限的内存价值最大化也是 Swap 在现代内核中仍然不可替代的重要原因。3. 操作 Swap 前的准备状态查看与容量规划3.1 查看当前 Swap 使用状态不管你是要新增、调整还是清理 Swap第一步永远是看清现状。常用的命令就是 free 和 swapon。free -h这个命令输出里Swap 一行的 total、used、free 一眼就能看懂。我一般会顺便看一眼 buff/cache 那列因为很多时候 Swap 被使用并不一定是内存真不够而是缓存占得太多导致内核不得不启动 Swap 回收。swapon --show这个命令能列出当前启用的 Swap 设备/文件包括类型partition/文件、大小、Used 量和优先级Priority。我习惯用这个命令确认系统当前在用的是哪个 Swap避免调整时改错了对象。还有一个更细的命令cat /proc/swaps输出内容基本和 swapon --show 类似但它是内核态直接暴露的信息在排查某些极端问题时更可靠。3.2 Swap 容量规划到底配多大合适关于 Swap 容量网上有几个说法最经典的是“物理内存的 1 到 2 倍”。这套说法源自红帽的官方文档但这只是“经典参考”不能无脑套用原因在于现在的内存量级已经和当年完全不同当年系统内存普遍是 256M、512M配个 1 到 2 倍的 Swap 确实能解决很多问题但现在的服务器动不动 64G、128G你要是按 2 倍配 256G Swap这纯属浪费磁盘空间而且永久性分区类型还会白白占一块磁盘。我的实际参考逻辑是这样的内存小于 2G 的轻量场景Swap 配 2 倍内存量内存 4G 到 16G 的通用服务器Swap 配 1 倍内存量或者固定 4G 到 8G内存 32G 以上的大内存服务器Swap 配 4G 到 8G 即可甚至可以不配但建议留一点兜底如果有明显的尖峰内存需求比如编译大型软件、跑批处理任务按最大内存需求的 1.25 倍来配 Swap另外要特别留意“低内存高并发”的场景。比如你内存只有 4G但跑了十几个 Java 服务物理内存明显不够。这时候 Swap 配 8G 也只是拖延问题真正该做的是加内存或减少服务数量而不是寄希望于 Swap。3.3 Swap 文件的取舍分区还是文件传统做法是单独划一个磁盘分区作为 Swap。这种方式的好处是性能稳定、不受文件系统碎片影响、开机挂载简单。但缺点是灵活性差分区大小后期调整非常麻烦需要重新分区甚至重装系统。现代 Linux 环境下我更推荐 Swap 文件。原因很简单创建和删除非常灵活想多大就多大随时可以回收不需要预先规划分区布局新手操作难度低在 LVM 环境下甚至可以做到在线扩容Swap 文件唯一需要担心的是文件系统碎片化对性能的影响。但说实话在内核层面Swap 文件是按页映射的文件系统的碎片化对 Swap 性能的实际影响远小于很多人想象的程度。在很多 Linux 发行版比如较新版本的 Ubuntu里默认安装就是 Swap 文件。4. 实操Swap 的创建、启用、验证与关闭4.1 创建 Swap 文件一步一步来我以最常见的 Swap 文件方案为例按顺序操作# 1. 创建交换文件比如 4G使用 fallocate 或者 dd fallocate -l 4G /swapfile # 如果 fallocate 命令报错比如某些文件系统不支持用 dd 替代 dd if/dev/zero of/swapfile bs1M count4096 # 2. 设置文件权限必须是 600否则系统会拒绝使用 chmod 600 /swapfile # 3. 格式化为 Swap 格式 mkswap /swapfile # 4. 启用 Swap 文件 swapon /swapfile # 5. 验证是否生效 swapon --show free -h需要说明的是为什么权限必须设置成 600因为 Swap 文件里存的都是物理内存换出的数据可能包含用户的敏感信息。权限过于宽松时普通用户就能读取这个文件直接导致内存数据泄露。这是安全检查的底线不能省略。另外fallocate 和 dd 的区别要注意。fallocate 是直接操作文件系统分配空间速度极快秒级完成但如果文件系统比较老比如某些老式的 XFSfallocate 出来的空间可能实际并没有真正分配底层块启用时会有问题。dd 是硬写盘速度慢但兼容性万无一失。生产环境我建议优先 fallocate一旦失败再回退到 dd。4.2 开机自动挂载配置 /etc/fstab单纯执行 swapon /swapfile 只在当前系统运行期间生效重启之后 Swap 文件就没了来源自然不会被挂载。要开机能自动启用得写进 /etc/fstab。echo /swapfile none swap sw 0 0 /etc/fstab这一段配置的含义是设备/文件路径为 /swapfile挂载点为 noneSwap 不挂载到目录树上文件系统类型是 swap挂载参数为 swswap 专用dump 和 fsck 选项都是 0。建议添加之后务必执行一次验证防止 /etc/fstab 写错导致开机时系统进入救援模式# 先卸载当前 Swap swapoff /swapfile # 用 fstab 里的配置重新挂载其实就是测试 fstab 写的对不对 mount -a swapon --show有的老手会直接用 swapon -a 来验证它会读取 /etc/fstab 中所有标记为 swap 的条目并启用。如果配置没问题一条命令搞定。4.3 调整 Swap 大小扩容与缩容的完整流程计划赶不上变化。刚开始配了 2G Swap后来应用内存需求变大想扩到 8G。Swap 文件的好处这儿就体现出来了不需要重新分区操作流程如下# 1. 释放 Swap必须确保内存充足 swapoff /swapfile # 2. 删除旧文件 rm -f /swapfile # 3. 创建新大小文件 fallocate -l 8G /swapfile chmod 600 /swapfile mkswap /swapfile # 4. 重新启用 swapon /swapfile这里的关键步骤是 swapoff。执行 swapoff 时内核要把 Swap 里的所有数据重新搬回物理内存。如果物理内存剩余不足swapoff 会卡住或者报错比如 “Cannot allocate memory”。这种情况下要么先停掉一些占用内存大的进程要么分批迁移借助 cgroup 等方式绝不能硬来。我刚接触 Linux 的时候有一次直接在内存几乎用满的机器上执行 swapoff结果整个会话直接卡死重启之后检查才发现内核在 swapoff 时进入了内存回收僵局这是非常危险的。4.4 关闭 Swap 的完整操作有些场景下需要临时关闭 Swap比如调整分区大小、迁移数据执行swapoff /swapfile如果要彻底禁用并删除swapoff /swapfile rm -f /swapfile # 删除 /etc/fstab 中对应的行特别需要注意的是不要在物理内存已经占满甚至 Swap 使用率还很高的情况下贸然 swapoff。正确姿势是先清理内存压力观察 free -h 确认物理内存可用量超过 Swap 已用量必要时先重启占用内存的核心进程或者回收页缓存例如 echo 3 /proc/sys/vm/drop_caches但生产环境要慎重再执行 swapoff4.5 多块 Swap 的管理优先级机制如果一个系统上有多个 Swap比如一个分区和一个文件可以给它们设置优先级。优先级高的 Swap 会被优先使用优先级相同的会被轮流使用类似于 RAID0 的横向扩展效果。swapon --priority100 /swapfile1 swapon --priority50 /swapfile2这个机制在混合存储环境下很有用。比如你有一块 NVMe SSD 和一块普通 SATA 盘想让内核优先用 NVMe 上的 Swap 文件就把它的优先级设高一点。加载顺序上也可以配合 fstab 的 pri 参数实现。优先级我实际用的不多但对那些有混合存储的场景还是有价值的这里简单记录一下。5. 性能调优Swappiness 与其他关键参数5.1 swappiness 参数Swap 的“触发阈值”Linux 内核里有一个非常核心的参数叫 swappiness默认值通常是 60。它控制的是内核在使用 Swap 时的“急切程度”取值范围 0 到 100。怎么理解这个值swappiness 越高内核越倾向于把内存页换出到 Swapswappiness 越低内核越倾向于回收页缓存Page Cache而不是去动进程的匿名内存页。举个例子。假设一台服务器同时跑着数据库和文件缓存。文件缓存是为了加速文件读取而占用的内存如果这些缓存被回收下次读文件就要重新走磁盘 IO。而数据库的匿名页被换出到 Swap数据库性能会断崖式下降。这种情况下你会希望内核优先回收文件缓存而不是把数据库的页换出去。于是就会把 swappiness 调低。我一般按照使用场景来参考数据库服务器MySQL、PostgreSQL 等建议 10 左右尽量少 SwapWeb 应用服务器建议 20 到 30桌面系统保持默认 60 即可有特别记忆体要求的建模任务建议接近 0 甚至为 0修改方式分为临时和永久# 临时生效 sysctl vm.swappiness10 # 永久生效 echo vm.swappiness10 /etc/sysctl.conf sysctl -p但必须说清楚这个参数只代表内核“倾向于”怎么选并不是说设成 0 就一定不开 Swap。如果物理内存真的耗尽内核依然会启动 Swap。所以别把 swappiness 当成 Swap 的开关来理解。5.2 vfs_cache_pressure控制目录和 inode 缓存的回收速率除了 swappiness另一个影响内存回收行为的参数是 vfs_cache_pressure默认 100。它控制的是内核回收目录项缓存dentry和 inode 缓存的“积极程度”。考虑一个文件服务器需要频繁创建和删除大量临时文件。这种情况下dentry 缓存和 inode 缓存非常容易被耗尽内存如果内核不积极回收会导致系统卡顿。这个时候可以适当调高 vfs_cache_pressure比如 200让内核更主动地回收这种缓存。反过来如果系统需要频繁访问大量小文件希望尽量保留 dentry 缓存可以把值调低比如 50。这个参数不像 swappiness 那么热门但在高 IO 场景非常有用。我遇到过一个场景某工具每次运行都会创建几万个临时文件导致内存被 dentry 缓存急剧占满Swap 频繁写入。把 vfs_cache_pressure 调整到 150 后情况明显改善。5.3 Swap 与内存回收的整体关系很多人以为 Swap 只在物理内存完全耗尽时才触发其实不对。内核的内存回收机制是持续在运行的只是频率和力度不同。在内存压力不高时内核也会通过 kswapd 内核线程持续地进行后台回收包括把一些冷页换出到 Swap以保持水位有足够的安全余量。这个机制可以从 /proc/vmstat 里的相关字段观察比如grep -E pgswapin|pgswapout /proc/vmstatpgswapout 增长很快说明系统正在频繁换出页面这时候要么内存不足要么 swappiness 设置不合适需要排查。理解这一层之后就能明白为什么有时候 Swap 显示 used 很大但 free 的物理内存还有不少。这其实是内核在做“主动缓存和冷页交换”不一定是故障信号。6. 常见问题与排查技巧我踩过的那些坑6.1 swap 分区在开机时找不到场景重启之后系统提示“Swap 分区找不到”或者直接进入 emergency mode。最常见的两个原因一是 /etc/fstab 里写的 UUID 不对二是磁盘顺序变了这在多磁盘机器上容易发生因为设备名 /dev/sda 可能变成 /dev/sdb。排查方式# 查看当前系统能识别的 Swap 设备 blkid | grep swap # 查看 fstab 内容 cat /etc/fstab如果 UUID 对不上要么更新 fstab要么用 swapoff 关掉旧的、 mkswap 重新生成 UUID。用 Swap 文件就没有这个烦恼因为路径是固定的。6.2 swap 文件创建成功了但 swapon 失败现象创建了 /swapfilemkswap 也成功但 swapon 报错 “swapon failed: Invalid argument”。常见原因之一是文件没有设置好 600 权限或者 mkswap 之后又被别的操作修改了文件属性。我实际遇到最多的是使用了不支持某些特性的文件系统比如原本系统是 Btrfs它的 CoW写时复制特性会干扰 Swap 文件机制。解决方案# 如果是 Btrfs先关闭 CoW chattr C /swapfile # 或者干脆换到 XFS/ext4 上创建至于 Btrfs 上的 Swap 文件要确保在创建前就设置 chattr C创建之后再设置是不生效的。6.3 swapoff 时提示 Cannot allocate memory这个我之前说过很经典的坑。swapoff 要把 Swap 里的数据全部搬回 RAM如果物理内存不足内核给哪个进程分配空间都失败自然就报错了。处理方法优先腾出物理内存用 ps aux --sort-%mem 找出内存大户考虑重启或迁移下调 swappiness 避免换出继续增长如果有多个 Swap可以逐个释放而不是一次性全关在极端情况下可以考虑临时加大物理内存比如迁移到更大规格的实例6.4 Swap 使用率高但物理内存还有余量这个现象就是之前说的内核在做“主动回收”。不一定有问题但也不一定完全正常。排查思路cat /proc/meminfo | grep -E Dirty|Writeback如果 Dirty 和 Writeback 值很低说明回收的部分主要是缓存和冷页这是健康的。如果回收的都是匿名页且有持续增长的趋势就得考虑是不是某个进程正在吃内存。另外很多容器云环境的系统工程师建议裸金属机器要保留一点 Swap容器环境反而要关掉 Swap主要是考虑到 Kubernetes 早期版本对 Swap 支持不好会导致 Pod 的 QoS 判断异常。在新版本 Kubernetes 里可以通过配置 Node Swap 来启用部分支持但多数生产环境仍然选择关闭。这块要结合自己所在的运维团队策略来定不用盲目跟风。# 查看具体进程的 Swap 使用量 for file in /proc/*/status; do awk /VmSwap/{swaptotal$2} END{if(swaptotal0) print swaptotal, FILENAME} $file; done | sort -rn | head这个脚本能一次性找出 Swap 占用最高的那几个进程。对定位问题特别有用建议收藏。6.5 Swap 分区和 Swap 文件可以同时用吗可以。只要系统里有空闲的块设备或磁盘空间你可以同时启用一个 Swap 分区和一个 Swap 文件。设置好优先级之后内核会按优先级顺序把 Swap 页面填到不同介质上。这种场景我常用在混合存储的测试环境里比如 SSD 上的 Swap 文件做主力机械盘上的 Swap 分区做冷备。注意优先级高的会被先用满再轮到优先级低的。7. 针对典型场景的 Swap 方案建议7.1 开发测试机怎么配开发机一般不追求极致性能但经常要跑编译、启动多个应用Swap 配 2G 到 4G 即可。主要目的是避免内存偶尔不够的时候 SSH 都连不上。开发机我习惯用 Swap 文件而不是分区方便随时删除重来。7.2 稳定运行的生产服务器怎么配生产服务器的原则是能不 Swap 就不 Swap但一定要有兜底。推荐方案4G 到 8G 的 Swap 文件swappiness 设置为 10 到 20结合监控工具关注 Swap 使用趋势而不是只看当前值当 Swap 使用持续增长时说明内存规模已经不适配业务考虑扩容内存或优化应用内存占用7.3 数据库服务器怎么配数据库场景比较特殊频繁的 Swap 会直接导致查询延迟飙升。我的配置建议Swap 可以配小一点比如 2G 到 4G纯粹兜底swappiness 设为 0 或 10关闭 THPTransparent Huge Pages以减少内存分配时的抖动这个和 Swap 虽然没有直接关系但在内存管理层面配合起来效果好echo never /sys/kernel/mm/transparent_hugepage/enabled echo never /sys/kernel/mm/transparent_hugepage/defrag7.4 内存受限的容器/虚拟化小机器小内存机器是真离不开 Swap。比如一台 1G 内存的云主机跑 Nginx PHP-FPM如果不配 Swap访问量稍微上来一点就可能 OOM。这种情况下 Swap 配 2G配合合理的 swappiness40 到 60能保证服务的可用性。虽然会引入一定性能损耗但相比服务全挂这是值得的取舍。8. 最后再说几句实操心得这篇内容写下来核心想表达一个理念Swap 是工具不是目的。监控和调优的目标不是“把 Swap 清空”或者“把 Swap 用满”而是让系统在所有负载情况下都能维持一个稳定可预测的表现。实测的经验里值得记住的几条是每次调整 Swap 相关配置前先备份 /etc/fstab 和 /etc/sysctl.conf不要嫌麻烦。一次配置错误导致机器重启进不了系统恢复成本远高于备份的这点操作。线上变更 Swap 配置时选择业务低峰期。尤其 swapoff 这种操作哪怕内存再充足也会产生短暂的 IO 波动。把 /proc/vmstat 里的 pgswapin/pgswapout 加入监控图表。这比单纯看 Swap 使用量更能反映系统真实的内存压力。半年清理一次 Swap 配置。业务量变化了内存需求可能早就不一样了Swap 的容量和参数也该跟着调整每次业务版本大变更的时候顺手检查一下。我在实际操作中还有一个很深的体会对于大多数中等规格服务器与其纠结 Swap 配多大不如认真观察应用真实的内存占用曲线结合监控数据做决策。盲目套用“物理内存 2 倍”的旧经验往往会让 Swap 变成一个藏在角落里、只在关键时刻给你带来惊喜的隐患。
RELATED READING

延伸阅读

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