带宽跑满的时候页面转圈,这个大家都认。可带宽才用了三成、机器照样卡得像放幻灯片,那就该把视线从网卡挪到内存上去。页面调度算法这东西平时没人提,出问题的时候它天天在后台忙活——物理内存不够,系统就得把一部分页挪到磁盘上腾地方,用的时候再搬回来。搬出去、搬回来,每一趟都走磁盘,网站的响应时间就是这么一点点被拉长的。这不是哪个参数配错了,是内存和实际负载对不上号。

页面调度算法到底在调度谁
操作系统眼里的内存不是一整块,是按页切开的,一页通常 4KB。谁待在内存里、谁被赶出去、赶出去以后放哪儿,这一套规则合起来就是它。程序访问到一个不在内存里的页,CPU 会抛个缺页中断,系统得把这一页找回来。这个过程如果必须读磁盘,叫 major fault;页其实还在内存里、只是映射没建立,叫 minor fault,快得多。这两种故障的差距,比”带宽够不够”的差距大得多,只是大部分人从来没在监控里区分过。分配出去的页还分两类:文件页对应磁盘上的文件,丢了还能再读回来;匿名页是进程自己申请出来的,没地方可回,只能塞进 swap。
换页为什么比带宽更能把站拖死
带宽不够是什么体验?请求都发出去了,就是慢半拍,升带宽往往立刻见效。换页不是这个路子,更像你正写得顺手,笔被人抽走,得跑一趟仓库再拿一支回来。磁盘的随机读延迟比内存访问慢好几个数量级,一次 major fault 的工夫,内存能干很多事。更麻烦的是它连锁:一个进程疯狂换页,磁盘队列被占住,别的进程想读个配置文件也得排队,整台机器一起变慢。带宽是管子粗细的问题,换页是管子被堵住的问题,处理思路完全是两码事。带宽监控图看着平平整整,是因为它本来就不是瓶颈。
几种淘汰规则,脾气都不一样
教科书上那几个名字应该都见过。FIFO 先进先出,实现最省事,也最容易出洋相,Belady 异常就是它贡献的——内存给多了,缺页反而更多。LRU 按最近使用时间淘汰,理论上最贴直觉,但精确实现要给每次访问记账,开销不小,真系统里基本都是近似版:Clock(也叫二次机会)用环形队列转指针,Linux 则用 active/inactive 两条链去近似,还顺手把文件页和匿名页分开管。Windows 那边讲的是 working set。选哪种规则,跟业务访问的局部性强不强关系很大。某家内核到底怎么实现、参数叫什么,以官方文档为准,别照着一篇好几年前的教程硬套。
怎么确认是换页在闹,不是带宽
几个命令就够看个大概。free -h 看 available 和 swap 用了多少;vmstat 1 盯 si 和 so 两列,那是每秒换入换出的页数,长时间不是零就别安慰自己了;sar -B 看 majflt/s;iostat -x 1 看 %util 和 await。三条曲线摆一起,画面很清楚:带宽曲线温吞水,内存占用贴着天花板,磁盘 %util 常年高位不下来,这就是换页在打架,不是网卡不够。想定位到具体进程,ps -o maj_flt,min_flt -p 进程号,或者 top 里按内存排序,谁最胖一目了然。有条件的把这三样摆进同一张图、时间轴对齐,比看一堆孤立指标有用得多。
内存被 cache 占满,反而是好事
顺便说个经常被误会的:Linux 会把空闲内存拿去做 page cache,free 输出里 buff/cache 那一列数字很大很正常,available 才是能用的估计。有人一看内存快满了就慌,上去手动清缓存,结果读写全变慢。文件页随时可以丢,丢了不心疼;真正要担心的是匿名页被逼着换出去。所以判断内存够不够,看的是有没有持续的 si/so 和 major fault 增长,不是看 free 那一行的空闲值。缓存和内存不是一回事,别混着算。
参数能调,但别指望它救急
能拧的旋钮确实有。vm.swappiness 控制内核往外换页的积极程度,0 到 100,临时改 echo 10 > /proc/sys/vm/swappiness,想持久就写进 /etc/sysctl.d/99-swap.conf 再 sysctl -p。vm.min_free_kbytes 是给系统留的余粮,设太大反而压掉可用内存。不过这些参数的收益,远不如把内存配够:PHP-FPM 的 pm.max_children 开太大,进程数一上来就把机器挤到换页;MySQL 的 innodb_buffer_pool_size 给得过猛,系统自己就没地方站了;Redis 不设 maxmemory 更是个无底洞。把服务的用量框住,比抠 swappiness 有效得多。还有一点,swappiness 设成 0 不等于禁用 swap,它只是降低倾向,真缺内存该换还是换。
云主机和容器里几处容易踩的坑
容器里敲 free,看到的基本是宿主机的内存,跟自己那份限制没关系,得看 /sys/fs/cgroup/memory.max 和 memory.stat 才准。cgroup 内存到顶的顺序一般是:先回收 page cache,再换匿名页,实在顶不住就 OOM killer 挑个进程干掉——容器”莫名其妙重启”有时候就是这么来的,重启前先翻翻 dmesg 里有没有 oom 字样,能省不少排查时间。另外 swap 往往落在云盘上,云盘的 IOPS 有上限,一到换页高峰直接打满,表现就是整机像死机。各家控制台的内存使用率口径也不完全一样,有的算 cache 有的不算,看监控之前先弄清定义,以服务商的页面说明为准。
顺序别搞反:先量数据——vmstat 的 si/so、iostat 的 %util、free 的 available;再揪进程——谁内存最大、谁的 major fault 涨得快;最后才谈限额度和调参数。能加内存就加,加不动就把吃内存的服务限量或者拆开跑。等你把换页按住,回头再看带宽那条曲线,多半会发现它根本不忙。
【版权声明】:本站内容若无意侵犯到您的权利,请及时与我们联系将尽快删除相关内容!