ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux虚拟内存配置指南:Swap大小、swappiness调优与实战排障

Linux虚拟内存配置指南:Swap大小、swappiness调优与实战排障 搞过几年Linux运维和开发环境的人基本都绕不开一件事跑着跑着内存不足了进程被OOM Killer干掉数据库突然断开或者编译大项目的时候系统直接卡死。这就是典型的虚拟内存没配置好。虚拟内存在Linux里就是Swap交换空间它的作用是在物理内存不够的时候把一部分磁盘空间当作内存来用帮系统撑过内存峰值压力。很多人以为Swap是老旧概念机器内存大了就没必要实际上无论是裸机部署还是容器环境Swap都是Linux虚拟内存体系中不可或缺的一环。这篇内容就围绕Linux虚拟内存的配置展开覆盖从查看现状、确定大小、创建Swap文件、调优内核参数到故障排查的完整流程适合刚接触Linux的新手也适合需要在生产环境重新规划内存资源的运维同学。1. 内存不够用之前先把虚拟内存的思路理清1.1 虚拟内存到底是什么虚拟内存这个概念在Linux里实际上包含了两层意思。一层是系统给每个进程提供的独立虚拟地址空间靠CPU的MMU内存管理单元加上页表映射来实现这一层是现代操作系统的基础设计另一层就是我们日常说的Swap也就是把物理内存里暂时用不上的数据页换到磁盘上腾出内存给更需要的进程。我们这篇文章谈论的虚拟内存配置指的就是后者。理解Swap可以打个比方你的办公桌物理内存不够用了文件堆得到处都是这时候你会把不常用的资料放到旁边的文件柜磁盘里需要用的时候再拿出来。Swap就是这个文件柜。它的核心价值不是为了让系统运行更快而是避免内存耗尽时系统直接崩溃或者滥杀无辜进程。Linux在物理内存不足时会有个OOM Killer机制去杀掉占用内存大的进程来自救这个机制虽然有效但杀错了进程往往比内存不足本身更让人头疼。配置好Swap就是给系统一个缓冲空间让它能先通过换页来缓解压力而不是一上来就动刀子。实际使用中你会发现Swap在两种场景下特别有用。一种是内存突发高峰比如编译大型软件、启动多个虚拟机、跑大数据分析任务内存使用量短时间内冲上去Swap能帮你扛过去另一种是内存虽然够用但有很多冷数据长期占用着物理内存比如某些后台服务启动后会缓存一大堆数据但很少再用这时候系统可以把这些冷数据换出到Swap给页面缓存留出更多空间来加速文件读写。1.2 哪些场景必须配置哪些场景可以少配甚至不配说到Swap配置我见过两种极端。一种是什么机器都习惯性加个8G Swap不管这台机器是干嘛的另一种是听说过Swap性能差这个说法于是所有机器都不配Swap。这两种都不可取。先说不配Swap的风险。比如你跑着MySQL或者Redis内存突然被打满OOM Killer直接把数据库进程杀了那就是实打实的生产事故。如果有一块Swap顶着哪怕性能差一点起码进程还在你能争取到时间排查问题、加内存或者优化应用。再比如Kubernetes节点很多云厂商的镜像默认不配Swap但如果你跑的是Java系应用JVM启动时预留堆内存或者有内存突发需求的批处理任务没Swap的话Node的Pressure很高Pod容易被驱逐。再说Swap的适用场景。数据库服务这种对延迟敏感的应用确实不应该依赖Swap来撑性能——该配的是足够大的物理内存。但作为安全阀哪怕只是很小的Swap也能避免底层的内存回收机制频繁触发高代价的direct reclaim。简单说Swap是保险而不是性能方案这个定位要清楚。给个经验参考桌面环境、测试机、开发机建议配置Swap大小可以按物理内存的1到2倍来生产服务器建议保留一个相对较小的Swap比如4G到8G作为兜底如果是大规模分布式存储或者高性能计算节点物理内存规划得比较满Swap可以配小一点甚至不配但前提是你对业务内存画像很了解并且监控告警完善。1.3 关于Swap性能低这个说法的真相很多人张口就说Swap慢这个说法本身没错但要看你具体怎么用。Swap的读写确实比内存慢几个数量级内存是纳秒级磁盘哪怕是NVMe SSD也是微秒到毫秒级。但关键在于Swap的触发条件是什么。系统并不会等到内存完全满了才用Swap而是由内核的内存回收机制根据水位线watermark来决策的。这里有第一个需要纠正的认知Linux里Swap的占用率高并不代表系统性能一定差也不代表内存不够。很多时候系统只是把很久没有被访问过的内存页换出去了这些页本身留着也是占着地方。你去看一台空闲机器的free -hSwap显示用了几个G以为是内存泄漏实际上很可能是内核为了腾出页面缓存而换出的冷数据而已。真正需要警觉的是持续的、明显的内存压力导致的Swap读写波动那才是性能瓶颈的信号。另外一个关键点是Swap和物理内存共同构成了系统的虚拟内存总量。在分配内存时Linux会同时考虑物理空闲内存和Swap可用空间调优vm.swappiness这个参数就能控制内核倾向于使用Swap还是回收页面缓存后面我会专门出一节来说这个参数的用法。2. 动手之前先看清楚你的内存和Swap现状2.1 用几条命令摸清家底配置虚拟内存之前先要搞清楚当前机器是什么状态。很多人的习惯是一上来就直接创建Swap结果在配置过程中才发现系统里原本就有一块Swap分区只是没挂载或者之前的swapfile还残留着导致后续出现各种冲突。先做一次摸底检查很值得。查看内存整体情况的命令是free -h这也是最常用的。它的输出分两行Mem行显示物理内存Swap行显示交换空间。重点看Swap行的total、used和free以及Mem行的available这一列。available是内核估算的还能分给谁用的可用内存这个数比used列更真实因为它考虑了页面缓存可以回收的部分。swapon --show这个命令能列出当前激活的Swap设备或文件包括类型partition或file、大小、使用的优先级。cat /proc/swaps也能看到类似的输出区别是/proc/swaps不依赖lsblk这类额外工具在最小化系统里也能用。如果你有多个Swap设备还想知道具体是哪个在用swapon --show是首选。查看磁盘空间是创建Swap文件前的必要步骤。用df -h看根分区和你想放置swapfile目录的剩余空间再用手动lsblk看一下有没有独立的磁盘分区可以用来做swap分区。创建swapfile时有个细节容易踩坑默认的fallocate命令在某些文件系统比如旧版XFS上创建的文件的连续性没有保证建议用dd来创建更稳妥关于这一点我在第三节实际演示时会特别说明。2.2 Swap大小到底该设为多少Swap大小的选择没有绝对正确的公式但有几个常用的参考口径我这里整理出来供你参考。红帽官方有个推荐表格内存小于2G时Swap设为内存的2倍2G到8G之间时Swap与内存等大8G到64G之间时Swap设为4G到8G内存超过64G时则可以根据工作负载灵活调整。这套推荐本质上是越大的内存机器Swap占比越低。还有一个经验值是结合内存压测来定的观察你机器上最重负载时的内存峰值以这个峰值再留出20%到30%的余量作为物理内存需求如果物理内存小于这个需求量Swap就按差额的1.5倍左右来配。比如你的服务高峰期内存占用约12G物理内存只有8G那Swap至少给到6G-8G。另外要考虑睡眠休眠的需求。如果你使用Linux笔记本且需要休眠suspend-to-diskSwap的大小至少不能低于物理内存大小因为休眠的本质是把内存中的所有数据写入Swap。这一点针对桌面用户比较重要服务器用户一般用不到。我的个人建议是如果你拿不准就按如下方式决策开发机默认给物理内存的1倍大小最低4G生产服务器如果内存小于等于16GSwap给4G到8G如果内存大于16GSwap给8G同时开启vm.swappiness调低到10左右让系统优先使用物理内存。这组配置在大多数场景下都能兼顾安全性和性能。2.3 选Swap分区还是Swap文件Swap的实现方式主要有两种独立的分区和普通的文件。分区方式在企业环境里很常见因为它在系统安装阶段就能规划好性能上也相对稳定文件方式则更灵活不用重新分区调整大小也方便适合云服务器和容器场景。这里我需要给新手一个明确的建议用Swap文件原因有三点。第一现在很多云主机购买后系统盘就是根分区没有额外空闲分区可以分给Swap用文件不需要动分区表第二Swap文件调整大小很容易先swapoff再删除文件重建一个就完事了而分区方式要调整大小就得折腾分区工具第三在LVM和Btrfs等文件系统上swap文件也支持得很好性能差别在多数场景下可以忽略。那什么情况下还是用Swap分区呢如果你的系统盘是机械硬盘或者你部署的是对IO延迟极其敏感的关键应用可以尝试把Swap放在独立的磁盘分区甚至单独的物理盘上尽量减少对系统盘IO的影响。另外如果系统盘使用了一些swap文件支持有缺陷的文件系统老版本Btrfs的某些特性分区方式会更省心。不过就绝大多数Linux发行版而言swapfile方案完全够用。3. 从零开始配置虚拟内存的完整实操3.1 第一步创建Swap文件我以最通用的/swapfile路径为例演示。首先用dd命令分配一块指定大小的磁盘空间。例如我要创建一个4G的Swap文件dd if/dev/zero of/swapfile bs1M count4096 statusprogress解释一下这个命令。if/dev/zero表示从零设备读取数据of/swapfile指定输出文件bs1M是每次读写1MBcount4096就是4096次总共就是4G。statusprogress可以实时显示写入进度。前面我提到过创建Swap文件除了dd还可以用fallocate命令fallocate -l 4G /swapfile。这个命令速度极快因为它只是在文件系统层直接分配空间不需要逐字节写入。但为什么我建议用dd因为fallocate在部分文件系统上创建的文件存在洞holes这些洞在mkswap之后会被内核识别为非法swap signature导致无法正常使用。用dd创建的文件一直要等到真正填充数据才算分配完成虽然慢一些但可靠。如果你的磁盘是SSD4G的dd也就十几秒的事完全值得。文件创建好之后要做权限收紧chmod 600 /swapfile这个步骤不能省。Swap文件里在某个时刻会包含用户进程的内存数据如果权限是644系统随便一个普通用户都能读取那就是严重的信息泄露风险。另外内核在加载swap文件时如果发现权限过宽松会直接拒绝启用并提示insecure permissions。3.2 第二步格式化为Swap并启用创建好文件后把它格式化为Swap格式mkswap /swapfile执行后会输出类似Setting up swapspace version 1, size 4 GiB的提示表示格式化成功。如果之前这个文件有残留的swap签名mkswap也会自动覆盖并给出提示不用额外处理。启用Swapswapon /swapfile执行完用swapon --show确认一下能看到Type为fileSize为4G。再用free -h检查Swap这一行的total应该已经变成了4G。如果你在启用时遇到提示swapon: /swapfile: insecure permissions说明第3.1节的权限没设置好回头执行chmod 600再重新swapon即可。注意这时候可能需要先swapoff /swapfile再重新执行否则报错的状态不会自己恢复。这里顺便提一下关于swap优先级的参数。如果你有多个swap设备可以用swapon -p priority /dev/xxx来设置优先级。优先级数值越大的设备会被优先使用。这在多块磁盘场景下很有用把Swap放在更快的NVMe磁盘上并设置更高优先级慢速磁盘作为后备内核会优先用快的那个。3.3 第三步开机自动挂载上面执行完的这些操作重启之后就失效了。要开机自动启用Swap需要把它写入/etc/fstab文件。编辑fstabecho /swapfile none swap sw 0 0 /etc/fstab解释一下这一行的字段第一列是设备或文件路径第二列是挂载点swap的挂载点固定为none第三列是文件系统类型swap第四列是挂载选项sw表示swap第五列和第六列是dump和fsck顺序swap不需要参与均为0。这里有一个很重要的操作细节/etc/fstab如果写错了系统开机会进入emergency模式或者直接启动失败。所以写完fstab之后建议执行mount -a先测试一遍。这个命令会重新读取fstab并尝试挂载所有条目虽然无法完整模拟开机时的swap激活流程但至少能发现格式层面的错误。还有一种情况是系统里已经有系统盘自带的swap分区了你在fstab里又加了一行开机后会出现两个swap。这不一定是坏事系统会把两个都激活再根据优先级策略来决定使用顺序。如果你想让系统只使用这个swapfile就需要把原有swap分区的条目注释掉同时用swapoff停用现有的分区。3.4 第四步调整swappiness参数配置好Swap之后默认情况下内核的vm.swappiness是60部分新发行版是30这意味着系统会积极地把内存页换出到Swap即使物理内存还很充裕。这个行为在桌面环境下影响不大但在服务器上可能会导致性能波动。查看当前值cat /proc/sys/vm/swappiness临时修改重启失效sysctl -w vm.swappiness10永久修改echo vm.swappiness10 /etc/sysctl.conf sysctl -pvm.swappiness的取值范围是0到100。数值越高内核越倾向于使用Swap数值越低系统越倾向于回收页面缓存page cache而不是换出内存页。调成0并不代表禁用Swap而是让系统在物理内存极度紧张的时候才使用Swap同时尽量保留文件缓存。适合数据库服务器、Java应用等对响应延迟敏感的场景。我个人在部署MySQL、Redis这类缓存型服务时习惯把swappiness设为10。如果是普通的Nginx反向代理或者静态文件服务器文件缓存本身就是性能所在可以把swappiness保持在默认值甚至更高让页面缓存更充裕。4. 虚拟内存调优不仅仅是swap大小这么简单4.1 理解内存水位线、kswapd与direct reclaim调优Swap之前有必要先理解内核是怎么决定何时开始换页的。Linux内核的内存管理为每个内存区域zone维护了三个水位线high、low和min。当空闲内存低于low水位线时内核的守护进程kswapd会被唤醒开始异步地回收内存页回收的目标是让空闲内存回升到high水位线。如果内存消耗速度太快kswapd来不及回收系统会进入direct reclaim路径也就是分配内存的进程自己直接参与回收这是最危险的因为它会导致进程阻塞表现为卡顿和延迟飙升。Swap在这里面扮演的角色是当页面缓存回收已经不足以满足内存需求时内核选择把一些匿名内存页进程堆、栈等写入Swap以空出物理内存。所以Swap的作用不仅仅是内存不够用时的后备空间它对内核整个内存回收策略的平滑性都有影响。没有Swap的系统在内存压力下只能靠回收页面缓存和杀掉进程来释放内存很容易进入direct reclaim的恶性循环。这也是为什么我建议即使内存足够大的机器也保留一个较小的Swap——它不是用来真正存多少数据的而是给内存回收机制一个额外的缓冲手段。从内核的角度看没有Swap的系统里匿名页无法换出内存压力的处理路径更短也更脆弱。4.2 vfs_cache_pressure与内存回收倾向与虚拟内存表现密切相关的另一个内核参数是vm.vfs_cache_pressure。这个参数控制内核回收目录项缓存dentry和索引节点缓存inode cache的倾向性。默认值是100数值越大内核越积极地回收这两类缓存数值越小越倾向于保留。在虚拟内存配置这个主题下这个参数常被放在一起调优因为它影响着内存的整体回收策略。如果你运行的业务会频繁创建和删除大量小文件比如git仓库操作频繁的CI节点、对象存储元数据服务可以适当调低该值比如vm.vfs_cache_pressure50这样目录缓存能保留更久减少磁盘IO开销。要注意的是调这个参数并不会直接改变Swap的使用量它更像是配合swappiness一起做整体内存回收策略的微调。很多优化脚本喜欢把这两个参数一起改也不是没有道理但你要明白每个参数各自在干什么。4.3 监控Swap的实际使用和压力配置完成之后需要知道怎么监控它的运行状况。日常查看就是free -h但更深入一点的监控建议用以下手段。第一是vmstat 1每秒钟打印一次系统的进程、内存、分页、IO等统计。重点看siswap in从Swap换入内存和soswap out从内存换出到Swap两列。正常情况下这两个值都应该是0或者很低如果持续出现比较大的值说明系统确实在经历内存压力性能正在下降这时候需要排查是什么进程在大量占用内存。第二是sar -S 1sysstat工具包中的Swap监控能记录到swap空间的使用量和换页速率适合事后查看历史趋势。如果你已经配置了sysstat的定时采集这个数据很有价值。第三是/proc/meminfo里的SwapTotal、SwapFree和CommitLimit、Committed_AS。后面两个值很多人不看其实很有用。Committed_AS表示系统当前承诺分配给进程的内存总量包括未实际使用的虚拟内存CommitLimit通常是物理内存Swap的某个百分比默认是overcommit_memory0时的启发式规则。如果Committed_AS长时间接近CommitLimit说明系统内存超卖严重即使物理内存还有空闲也随时可能发生内存分配失败。我自己的习惯是给服务器配一个简单的内存监控脚本每60秒检查一次/proc/meminfo、si和so的数据超过阈值就告警。有了Swap之后你更需要关注的是换页速率而不是Swap的占用百分比。4.4 推荐的生产环境参数基线基于我在几类常见生产负载上的经验整理一组我认为稳妥的虚拟内存相关参数基线。注意这不是通解具体调整还要结合你的业务实测。数据库类服务MySQL、PostgreSQLvm.swappiness10vm.vfs_cache_pressure50保留8G Swap用于内存峰值兜底Java应用服务器vm.swappiness5到10保留4G到8G Swap注意JVM在启动时会保留heap大小尽量让heap加上线程栈等开销之和在物理内存内文件缓存型服务Nginx、CDN边缘节点vm.swappiness30左右vm.vfs_cache_pressure100甚至更高Swap可以配小一点因为页面缓存回收比Swap换页开销更小内存密集型数据处理Spark、Flink的TaskManager这类任务本身内存规划要紧一些建议物理内存充足Swap作为保险配4G即可swappiness可以设低一些避免任务过程中的GC停顿增大参数配置完之后用sysctl -p加载再观察一两个业务周期确认没有异常波动。5. 配置过程中最容易踩的坑和排查实录5.1 常见问题速查表我把实际配置Linux虚拟内存时经常遇到的现象、原因和解决办法整理成了表格方便你对照排查。现象可能原因解决办法创建swapfile时提示No space left on device根分区空间不足或者inode耗尽检查df -h和df -i清理无用文件或换到其他分区创建swapon报insecure permissionsswapfile权限不是600执行chmod 600 /swapfile后重新swaponswapon报Invalid argumentswapfile是从fallocate创建文件系统可能不支持映射洞改用dd命令重建文件开机后Swap没有生效/etc/fstab的配置格式错误或设备路径错误检查fstab条目用mount -a测试语法free -h中Swap显示为0但swap分区存在分区没有被swapon激活执行swapon /dev/分区名确认对应fstab条目Swap使用缓慢增加且si/so持续波动内存压力真实存在业务内存需求超规划优先加物理内存同时排查内存泄漏或异常进程swapoff时提示内存不足无法完成要释放的Swap数据量超过物理内存可用空间先调整swappiness并释放部分缓存或分多次逐步压缩Swap数据量5.2 一起真实踩坑现场swapfile大小和内存冲突说一个我自己遇到过的案例。有一台装有16G内存的测试服务器最初创建了20G的swapfile想着反正磁盘空间大。结果运行一个内存需求大约12G的Java应用时系统频繁出现GC停顿vmstat显示si和so每秒几万块。原因很简单Swap太大且swappiness是默认的60导致JVM的堆内存页被频繁换出换入形成了一个糟糕的换页循环。解决方式是这样的先用sysctl -w vm.swappiness10降低了换页倾向再停用现有swap重新创建一个4G的swapfile作为纯保险用途。swapoff /swapfile时要小心如果当前内存已被大量占用swapoff操作会尝试把所有swap数据搬回物理内存发现空间不足就会报错。我这台机器当时实际上已经使用了6G的swap而物理内存空闲只有3G左右直接swapoff确实报错了。处理方法是先临时调高swappiness让系统积极换出部分页面缓存等到物理内存有足够余量后再做swapoff操作。那次的教训有三点一是Swap不是越大越好过大且Swap参与度过高会让Linux频繁把进程的物理页面踢出去反而拉低性能二是调整Swap大小是有顺序讲究的先停用、再调整、再启用停用前要确保物理内存容得下当前swap中的数据三是生产环境改动swap前最好先看业务当前的内存和swap占用趋势避免在两三周后swap使用量很高的时候做这个操作。5.3 关于zram和zswap现代内核的虚拟内存新玩法这一节算是延伸内容。如果你用的是现代Linux内核5.0以上还可以考虑zram和zswap这两项技术本质上是把Swap的数据先压缩放在内存里减少对磁盘的访问。zram是把一部分物理内存划分出来做成一个压缩的块设备作为Swap设备。数据在写入Swap前先压缩因此同样的物理内存容量能装下更多数据。它特别适合内存较小的嵌入式设备、低配置的云主机或者浏览器打开大量标签页的桌面环境。配置方式也很简单modprobe zram # 创建一个1G的zram设备 echo 1G /sys/block/zram0/disksize mkswap /dev/zram0 swapon /dev/zram0zswap则不同它是内核里的压缩缓存机制。当页面要被换出到Swap时zswap先把它压缩缓存起来只有在缓存压力大的时候才真正写入磁盘Swap设备。zswap对内核透明配置上只需要在启动参数里加zswap.enabled1或者在运行时通过sysfs接口启用它前提是系统已经配置了一个真实的Swap后备设备。要不要用这些我的观点是在服务器上以稳定优先的原则先不要急着开zram或zswap但在内存捉襟见肘的个人电脑上开启zram能明显改善卡顿。它们的共同缺点是压缩和解压需要消耗CPU所以性能和场景的取舍要看你的具体配置。5.4 配置之后还要做的一件事压测验证配置完了、参数调完了最好顺手验证一下效果。方法很简单用一个小工具stress-ng来人为制造内存压力。比如stress-ng --vm 2 --vm-bytes 80% -t 120这个命令会启动两个vm压力进程总共占用量约为当前可用内存的80%。观察在这120秒内系统的行为free -h看Swap是否按预期被使用vmstat 1看si/so是否在可控范围内同时确认没有任何进程被OOM Killer杀死。如果一切正常说明你的虚拟内存配置是健康的。压测时还有一点要注意OOM Killer也是有善后的它杀掉进程后会记录到内核日志里。用dmesg | tail -50可以看到Out of memory: Killed process ...这样的记录。如果你在压测中发现有进程被杀了说明Swap容量不足或者swappiness设置不合理需要再做调整。反过来如果压测过程中Swap完全没被使用也正常说明你的物理内存在当前压力下够用配置的Swap纯属保险这本身就是件好事。写到最后的一些实操体会从刚开始接触Linux到现在我在虚拟内存配置上确实是踩过不少坑才逐渐摸清楚的。回头看关键的认知其实就三条Swap是保险不是性能方案配置之前先看清内存和磁盘现状调优时要同时关注swappiness和swap大小这两个杠杆而不是只盯着其中一边。如果你正在配置一台新的Linux服务器我的建议是至少保留4G的Swap把swappiness设为10左右并且养成一个习惯每次配置完swap后在fstab里写入持久化条目然后重启验证一次。这些动作花不了几分钟但能让系统在未来很长一段时间里少很多内存层面的麻烦。
返回列表