☰
vmstat命令实战:从系统快照到性能瓶颈定位的完整指南
2026/10/13 3:44:17 网站建设 项目流程

1. 从"虚拟内存统计"说起:为什么需要一张系统运行快照

前几天处理一个客户的服务器问题,现象非常典型:白天业务正常,一到晚上跑批任务就卡顿,top上看CPU和内存都正常,但就是慢。现场同事折腾了半天没头绪,我远程上去先敲了一条命令:

vmstat 2 5

输出里wa列的数字让我立刻锁定了方向——CPU大量时间在等待I/O,结合跑批任务的写入特征,判断是磁盘队列拥塞。后来确认是某些批处理脚本产生了严重的随机写放大。最终的修复其实不复杂,但如果没有vmstat这张"系统运行快照",排查还得绕好几个小时。

这就是我写这篇文章的动机。很多运维同行习惯把top当作第一排查工具,但在定位"系统整体是否健康"这类问题上,vmstat提供的是完全不同的视角——它把CPU、内存、I/O、中断、上下文切换、交换分区等关键指标压缩到一张表里,几秒钟就能判断病根在哪个子系统。

这篇文章不是抄man page,而是从实际使用角度把vmstat讲透:每条输出代表什么、哪些指标组合能定位问题、最优参数怎么敲、常见误读怎么避开,以及它和类似工具(free、top、iostat、sar等)如何配合。无论你是刚接手服务器的运维新手,还是想加深系统调优理解的后端开发,读完应该能把这工具用得比绝大多数同事更专业。

2. 先弄明白vmstat的设计逻辑:一屏数字背后的内核数据源

vmstat全称是Virtual Memory Statistics,名字里带"virtual memory"是因为它的历史渊源——早期版本是专门统计虚拟内存子系统行为的。但随着Linux内核的发展,它逐渐演变成一台"系统健康状态监视器",虚拟内存相关指标只是其中一部分。

它的工作原理非常简单:vmstat通过读取/proc/vmstat、/proc/meminfo、/proc/stat这几个内核维护的计数器文件,把原始计数换算成可读的指标,再格式化成表格打印。你甚至可以不用vmstat命令,直接看这几份文件也能得到同样信息,但人肉换算太痛苦,工具存在的意义就是把这些枯燥的计数器变成一眼能看懂的数值。

2.1 三条命令区分使用场景

# 一次性快照,适合快速看一眼系统是否健康 vmstat # 每隔2秒采样一次,共采集5次,适合观察波动和短期趋势 vmstat 2 5 # 持续采样,直到手动Ctrl+C终止,适合长时间观察 vmstat 2

注意第一和第二条的区别:第一条输出的是"自系统启动以来到当前时刻"的平均值,这个数据意义不大——毕竟它把昨天乃至上个月的负载都平均进去了;第二条才是真正有用的实时采样。

vmstat 2 5是我日常使用频率最高的一条命令,它构建了两层信息:第一条(表头下方第一行)依然是从开机到现在的平均值,而后续每行则是上一个采样周期内的增量值。

2.2 procs、memory、swap、io、system、cpu六大区域的完整解读

vmstat输出分六个区域,很多人记住表头就完事了,但表头缩写背后对应的内核计数器你最好也搞清楚,这样遇到异常指标时才能快速判断是内核哪个子系统出了状况。

区域字段含义背后数据源
procsr运行队列中的进程数(含正在运行和等待CPU的)/proc/stat中的procs_running
procsb不可中断睡眠进程数(典型是等I/O)/proc/stat中的procs_blocked
memoryswpd已使用的交换空间总量(KB)/proc/meminfo
memoryfree空闲物理内存(KB)/proc/meminfo
memorybuff用作块设备缓存的物理内存(KB)/proc/meminfo
memorycache用作页缓存的文件缓存(KB)/proc/meminfo
swapsi从磁盘交换入内存的速率(KB/s)/proc/vmstat中的pswpin
swapso从内存交换出到磁盘的速率(KB/s)/proc/vmstat中的pswpout
iobi从块设备接收的块数(每秒)/proc/vmstat中的pgpgin
iobo发送到块设备的块数(每秒)/proc/vmstat中的pgpgout
systemin每秒中断数(时钟中断+硬件中断)/proc/stat中的intr增量
systemcs每秒上下文切换次数/proc/stat中的ctxt增量
cpuus用户态CPU时间占比/proc/stat中的cpu逐项计算
cpusy内核态CPU时间占比/proc/stat中的cpu逐项计算
cpuid空闲时间占比/proc/stat中的cpu逐项计算
cpuwa等待I/O完成的时间占比/proc/stat中的cpu逐项计算
cpust被虚拟机管理程序偷走的时间占比/proc/stat中的cpu逐项计算

这里我重点说几个容易被忽略的字段。

procs下的b字段:很多人只看r(运行队列),却不看b(阻塞在I/O上的进程数)。当b持续大于0,尤其是耦合着cpu的wa偏高,说明系统存在明显的I/O瓶颈。有一次排查数据库性能问题,vmstat 1采样里b列长期在5以上,wa在30%左右,系统响应缓慢。那时top里看到的进程CPU占用并不高,但大量线程在等磁盘。如果不看b和wa,单纯优化SQL可能完全不解决问题。

swap下的si和so:这两个字段一出现非零值,基本可以判定物理内存吃紧。特别是so(换出)持续大于0时,说明内存压力已经很严重,内核在不停地把匿名页写回交换分区。我见过不少服务器内存加到64G甚至128G,但应用层存在内存泄漏,导致si/so依然频繁跳动。

system下的cs:上下文切换次数是判断系统"忙得有没有效率"的关键指标。如果cs数值很高(比如每秒几万甚至数十万),但cpu的us和sy都不高,说明系统可能出现了锁竞争或者过度调度,大量CPU时间消耗在线程切换上。多线程应用优化时,这个字段是衡量"线程数量是否合理"的一种参考。

cpu下的st:只有虚拟机或容器环境才会有明显数值,st高意味着宿主机CPU资源被抢占。假如你在云主机上发现st长期超过10%,应用再慢也别急着调优自己的代码,先考虑是不是宿主机超卖太严重。

2.3 一次输出实例的完整解读示范

我在一台测试机上跑vmstat 2 3,得到如下输出:

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 2 0 0 6248620 86544 3114216 0 0 12 23 7 12 4 4 92 0 0 5 0 0 6243284 86544 3114268 0 0 912 5406 1102 2334 31 14 43 12 0 3 0 0 6239988 86544 3114300 0 0 724 4021 989 2102 28 13 50 9 0

第一行是系统启动以来的平均值,参考意义有限。从第二行开始才是真实采样:r从2涨到5,cs从12跳到2334,说明系统并发负载明显上升;io的bi和bo突然出现数百到数千的量级,cpu的wa从0跳到12%,明显在等I/O。此时如果鼠标再敲一条iostat -x 1,大概率能抓到具体的磁盘设备利用率到瓶颈。这就是vmstat真正的用法——它告诉你"哪里可能有问题",再由更精细的工具去确认。

3. 六类指标组合定位:按场景拆解而不是孤立看数字

vmstat的每个字段单独看价值有限,真正值钱的是字段之间的组合关系。这就像看体检报告,单一指标超标的信号和几个指标一起超标的信号,诊断方向完全不同。我把常见场景拆成几类,按这套思路去套,排查效率会高很多。

3.1 CPU瓶颈:r和us/sy的组合解读

当procs下的r持续大于CPU核数的2倍以上,但us和sy都接近饱和(合计接近100%),基本可以认定是CPU计算资源不足。注意r不是"正在运行的进程数",而是"正在运行+等待运行的进程数",所以r远大于核数意味着大量进程在排队。

举个例子,一台4核机器,vmstat采样中r稳定在8左右,us在70%以上。虽然sy不高,但CPU已经明显超载。此时优化方向有两个:先看看应用层有没有死循环或者无效计算,如果没有,那就得扩容。这里不要被id=0欺骗——id为0说明CPU一点空闲都没有,但这不等于"所有核都在干活",只是"所有核都在排队干活"。

3.2 内存压力:free、si、so三者联动

很多人看到free剩下几百MB就开始紧张,其实没必要。Linux对物理内存的使用策略是"尽量多用",free数值低恰恰说明缓存策略生效,磁盘数据尽量缓存在内存里。真正需要紧张的是si和so连续出现非零值,尤其是so。

还是看组合:free持续下降且si/so持续走高,说明进程的匿名页开始被换到磁盘。此时top看单个进程的RES也许并不突出,但系统的整体性能已经在下滑。我处理过一起案例,Java应用因堆外内存增长过快,内存逐渐被耗光,swap活动频繁。当时vmstat 1里so已经到每秒几百KB,但free还剩下几个G(因为cache会先释放),如果不看si/so很难发现内存已经告急,后来加了一行内存监控告警才彻底解决。

3.3 I/O瓶颈:wa和bi/bo的组合

wa持续偏高是典型I/O瓶颈信号。但wa高也可能是CPU在等待锁或磁盘控制器响应慢,所以要看io区域的bi/bo是否真有大量数据传输。如果wa高但bi/bo都很低,说明CPU阻塞在等待上而不是真正有I/O在跑,这时要考虑是不是设备控制器卡了或者存在I/O路径上的锁竞争。

有次现场环境让我印象很深:某系统vmstat 1显示wa高达40%,但bi/bo都不过百。我下意识以为是磁盘慢,后来排查发现是存储适配器驱动有bug,导致I/O请求经常超时。换驱动后wa立刻从40%掉到2%以下。这就是为什么不能只看wa,必须把io字段组合着看。

3.4 上下文切换风暴:cs高但CPU空闲

这个场景最迷惑人。你看到cs每秒几万次,系统却像死了一样,但us/sy都不高,id还有余量。出现这种组合,通常是线程数量过多导致的调度风暴,或者是有大量锁竞争。

怎么定位?先用pidstat -w 1看哪个进程贡献了最多的上下文切换,再用perf sched统计调度事件。如果确认是锁竞争,最直接的缓解办法是减少锁粒度,或者用无锁数据结构替代;如果是线程池线程数配置过高,调低线程数量往往立竿见影。这个场景我建议你特别留意cs的绝对值——超过CPU核数乘以5000就可疑,乘以10000基本就是风暴了。

3.5 虚拟化环境:st字段的警钟

云主机的vmstat里如果st长期不为0,说明宿主机CPU超卖严重,你的虚拟机在"偷时间"。这种情况下应用慢不一定是你自身代码的问题,不要盲目扩容纵向资源,而是要考虑换一台宿主负载更低的主机,或者干脆加副本做横向伸缩。

4. 实际排查案例:一次数据库变慢的完整定位链

理论讲完了,用一个真实排查案例把整个思路串起来。有一回线上MySQL实例响应明显变慢,慢查询日志却空空如也,无法通过SQL维度定位。

我第一反应就是先看系统层面有没有变化。连接服务器后执行:

vmstat 1 10

输出里r从平常的1-2涨到了6-8,wa(I/O等待)在25%-30%之间波动,si/so都为零。r偏高有一定CPU压力,但wa也高说明I/O也在拖后腿。这种组合意味着"CPU想干活,但在等磁盘",所以我重点排查磁盘。

接着用iostat -x 1看具体盘符,发现sda的%util接近100%而await到了200ms以上,确实磁盘接近饱和。再往下看是哪些进程在产生大量I/O,用iotop一抓,发现是个夜间批处理任务在同时跑多条全表扫描的UPDATE语句。

最后的处理手段并不复杂:一是把批处理任务的并发度调低,二是把部分查询从主库切到只读从库。改动后再次用vmstat 1 5验证,r回落到2,wa掉到5%以内。整个排查链路大概半小时,其中vmstat花了不到10秒就给出了方向。

这个案例最能说明vmstat的定位:它不直接告诉你答案,但它能大幅缩小问题范围,让你知道该往CPU、内存还是I/O方向去查,后续的精细化定位工具才能派上用场。

5. 高频参数和进阶用法:不要只会敲vmstat

vmstat默认输出已经很有用,但很多参数能让它适配更多场景。挑几个高频用法分享一下。

5.1 采样次数和间隔的组合规则

# 每个2秒采样1次,共采集3次 vmstat 2 3 # 持续采样,不限制次数 vmstat 2

第一行永远是系统启动以来的平均值,想跳过这一行可以用-a,它会显示活跃和非活跃内存的信息,输出布局稍有不同。不过实际使用中我一般不去掉第一行,原因很简单:第一行可以作为"这台机器历史负载"的参考,特别是接手别人环境时,第一行的r和wa大致能反映这台机器长期的健康程度。

5.2 -s参数:查看内存事件汇总

vmstat -s

这个参数会把大量内存相关的统计事件打印出来,包括总内存、已用内存、活跃页、非活跃页、换入换出总量、页错误数等。因为全部是累计值,适合用来和当前采样做对比,比如想知道开机以来总共发生了多少次主缺页中断,这个参数是最直接的。

注意:缺页中断分为主缺页(需要磁盘I/O读入)和次缺页(直接从内存页表分配),前者对性能影响大,后者基本可以忽略。vmstat -s输出的major fault就是主缺页,如果你发现它持续快速增长,说明应用的内存访问模式可能存在问题,或者内存配置偏小。

5.3 -d和-p参数:磁盘维度的补充

# 各磁盘的读写统计 vmstat -d # 指定分区的读写统计 vmstat -p /dev/sda1

这两个参数可以在不额外安装工具的情况下,快速查看磁盘粒度的I/O统计。虽然精细程度不如iostat,但胜在系统自带,在没有额外软件包的环境里应急排查很管用。

5.4 -a参数:活跃与非活跃内存

vmstat -a

输出会增加act和inact两列,分别展示活跃和非活跃内存的大小。Linux回收内存时会优先回收非活跃页,因此inact偏高说明有大量"冷数据"躺在内存里,如果要给应用程序腾内存空间,这些非活跃页是可以被回收的。不过现实中我更常用cat /proc/meminfo里的Active和Inactive,内存维度更细。

6. 和其他工具配合:vmstat、top、free、iostat、sar如何分工

不少运维新手有个误区:以为top能代替vmstat。确实top上面几行也显示负载、CPU、内存,但top的核心价值是"进程视角",它把单个进程的CPU和内存消耗列得清清楚楚;vmstat则是"系统视角",它整体告诉你哪个子系统有问题。两者定位完全不同,严格来说是互补关系。

工具核心视角最擅长的场景不足
vmstat系统整体快速定位CPU、内存、I/O瓶颈方向无法定位到具体进程
top进程个体看哪个进程吃CPU/内存最多系统整体健康度弱化
free内存详细看内存总量、可用量、缓存构成只看内存,不涉及CPU和I/O
iostat磁盘设备看块设备的利用率、队列长度、服务时间不包含内存和CPU
sar历史趋势回溯历史性能数据,定位"昨天发生了什么"需要提前部署并开启采集

我的习惯打法是这样的:

  1. 接到问题反馈,先敲vmstat 1 5,判断方向是CPU、内存还是I/O。
  2. 方向是CPU,用top -Hp看具体是哪个线程在消耗CPU。
  3. 方向是内存,用free -h和cat /proc/meminfo看内存构成;如果si/so异常,再用top按RES排序找进程。
  4. 方向是I/O,用iostat -x 1看具体磁盘设备,用iotop找I/O大户。
  5. 需要回溯,用sar查看历史负载趋势,判断问题是突发的还是渐进的。

这套打法虽然简单,但效率极高。绝大多数性能问题在vmstat阶段就能确认方向,后面几步只是进一步坐实,避免白忙一场。

7. vmstat常见误读:这些数字陷阱你踩过几个

vmstat虽然命令简单,但输出里藏了不少坑。我把这些年见到的误读场景集中说一下。

7.1 free小就等于内存不足

新手看到free显示几百MB就恐慌,实际上Linux的cache会按需释放给应用程序。看内存是否充足,正确指标是free命令里available一列,它才是"在不触发swap的情况下还能分配多少内存"。vmstat的free列只是"完全空闲的物理页",忽略cache的存在。

7.2 wa高就一定是磁盘故障

wa高只能说明CPU在等I/O,但不一定是磁盘坏了。前面说过,可能是驱动bug、存储链路拥堵、锁等待。先看bi/bo确认是否真有I/O流量,再看iostat的await和%util,如果流量不大但等待时间长,问题大概率在设备或驱动,不在磁盘本身。

7.3 r高就等于CPU不够

r高说明有大量进程在排队,但排队也可能是锁竞争导致的调度停滞。之前遇到一个Java应用疯狂创建线程的场景,r高达30但CPU的us只有20%,系统响应极慢。后来排查发现是线程池参数配置错误,导致任务不断创建新线程,加剧了上下文切换,形成了调度风暴。这种情况下加CPU核数毫无意义,反而可能让问题更严重。

7.4 第一行的数值被误当作实时状态

这是最隐蔽的坑。vmstat不带参数时输出的是"系统启动以来的平均值",你用它来判断当下状态完全可能得出错误结论。我见过有人看着第一行的r=0.2,就说"系统很空闲",但实际上此刻服务器已经被压垮了——因为开机时间很长,平均值被稀释了。养成好习惯:vmstat永远跟采样间隔和次数一起用。

7.5 st高被误以为是CPU耗尽

st是虚拟机被宿主机抢占的CPU时间,云服务器里如果st高,意味着宿主机资源超卖或邻居虚拟机太嘈杂。这时你不要急着优化自己系统的代码,而是考虑调整部署位置或换宿主机,优化自己代码解决不了宿主机抢占问题。

8. 几个可以立刻用起来的小技巧和扩展

最后分享几个我在实际使用中总结的小技巧,谈不上高深,但确实能省时间。

技巧一:结合watch命令动态刷新

watch -n 2 'vmstat 1 3'

watch会把vmstat的输出定时刷新在同一屏,适合长时间观察变化趋势。注意外层watch -n 2控制每2秒刷新一次,内层vmstat 1 3则是每次刷新前采集3次每隔1秒的数据,这样实际看到的是约3秒窗口内的平均状态,比单纯每秒刷一次更平滑。

技巧二:脚本里用vmstat做简单告警

如果不想引入复杂的监控平台,写个简单的shell脚本就能实现基础告警:采样vmstat 1 3,判断最后一行输出的wa如果连续多次超过80,就通过邮件或消息接口报警。内核自带的监控方案虽然简陋,但很多轻量场景够用。

技巧三:把vmstat和性能压测配合使用

做压测时,终端开着一路vmstat 1,压测脚本跑完后再看日志,能清晰记录每一秒的系统状态。这个做法比压测结束后再看汇总数据有价值得多——你能看到瓶颈是何时出现的、哪项指标先报警,这对调优方向极有指导意义。

技巧四:处理大量输出时用日志记录

如果系统性能是间歇性出现问题,人肉盯屏幕不现实。可以这样记录一段时间内的采样,比如每5秒一次,记录10分钟:

vmstat 5 120 > /tmp/vmstat_$(date +%Y%m%d_%H%M%S).log

等下次问题复现时,这份日志能帮你重建"故障前后系统状态的变化过程"。我排查一些偶发性卡顿时,经常靠这类历史日志找规律。

9. 从vmstat看Linux整体调优思想

工具讲得差不多了,我想从方法论层面做个总结。很多人学了一堆命令却还是不会排查问题,本质原因是没有理解Linux性能调优的核心思想。

vmstat的六个区域(procs、memory、swap、io、system、cpu)不是孤立设计的,它们构成了一个循环模型:运行队列长度(procs.r)反映CPU供需关系,内存和交换(memory、swap)反映资源的下层供给,I/O(io)反映磁盘链路,system反映中断和调度,cpu则汇总时间片去向。任何性能问题,在这个循环里一定能找到断裂点。

回到最开始的数据库变慢案例:r升高说明任务在排队,wa升高说明排队等的是I/O,bi/bo升高说明I/O确实繁忙,于是问题锁定在磁盘链路。整个推理链路如果走对了,基本一次到位。

所以我的建议是:不要孤立地记命令参数,而是建立"系统是一条流水线"的心智模型。CPU是工人,内存是工位旁的临时堆放区,磁盘是原料仓库,I/O是传送带,上下文切换是工人换岗。哪一环堵了,哪一环的指标就会异常。vmstat不过是把每一环的状态都搬到你面前而已。

模型建立之后,vmstat在你的工具箱里就不再是一条生硬的命令,而是一张系统健康仪表盘。配合top、iostat、sar,你完全可以在不借助商业监控软件的情况下,独立完成绝大多数性能问题的定位。这套方法论,是我这些年排查各类诡异性能问题最值钱的积累。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询