
当服务器变慢时,首先要问的问题就是它在等待什么。是 CPU 饱和了吗?内存耗尽、系统正在交换吗?是磁盘 I/O 拖住了进程吗?vmstat 命令把每种资源的线索集中在一张紧凑的表格里,是在你转向更专业的监控工具之前很有用的第一步检查。
vmstat 是 virtual memory statistics(虚拟内存统计)的缩写,由 procps-ng 提供。大多数完整的 Linux 安装都会通过一个名为 procps 或 procps-ng 的包包含它。
本指南讲解如何阅读 vmstat 的输出,以及使用它最实用的选项。
语法
vmstat [OPTIONS] [delay [count]]
- delay - 报告之间的间隔秒数。不指定时,vmstat 打印一份报告后退出。
- count - 要打印的报告数量。设置了 delay 但没设 count 时,vmstat 会一直运行到按下 Ctrl+C。
解读默认输出
不带参数运行 vmstat 会打印一份报告:
vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu------- r b swpd free buff cache si so bi bo in cs us sy id wa st gu 1 0 0 362824 94368 1207160 0 0 12 5 48 112 1 0 99 0 0 0
进程列和内存列显示的是命令运行时刻的值。在第一份报告中,交换、I/O、系统和 CPU 活动是自上次启动以来的平均值。输出分为六个部分。
procs(进程)
- r - 可运行进程数,包括正在运行或等待 CPU 时间的进程。将持续偏高的值与 nproc 得到的逻辑 CPU 数比较;繁忙的运行队列加上很少的空闲 CPU 暗示 CPU 争用。
- b - 等待 I/O 完成而被阻塞的进程数。
memory(内存,默认 KiB)
- swpd - 当前已使用的交换空间。
- free - 当前未被使用的空闲内存。
- buff - 用作缓冲区的内存。
- cache - 用作缓存的内存。Linux 会用原本空闲的 RAM 缓存数据,因此数值较大是正常的。
仅看 free 列并不能说明应用程序可以立即使用多少内存。需要这个数字时,请用 free 命令查看 available 值。
swap(交换,KiB/s)
- si - 每秒从磁盘换入的内存(KiB/s)。
- so - 每秒换出到磁盘的内存(KiB/s)。
偶尔的交换活动不足以诊断问题。持续的 si 或 so 活动,伴随着 free 和 cache 内存下降,才是内存压力更强的信号。
io(输入/输出,KiB/s)
- bi - 每秒从块设备接收的 KiB 数。
- bo - 每秒发送到块设备的 KiB 数。
system(系统)
- in - 每秒中断次数,包括时钟中断。
- cs - 每秒上下文切换次数。将该值与系统的正常负载比较,而不是用固定阈值。
cpu(占总 CPU 时间的百分比)
- us - 运行用户空间代码(含 nice 时间)所占的时间。
- sy - 运行内核代码所占的时间。
- id - 空闲时间。
- wa - CPU 因等待 I/O 而空闲的时间。持续上升是排查 I/O 的线索,但它不能指出具体设备,也不能证明存储就是瓶颈。
- st - 被 hypervisor 从虚拟机拿走的时间。
- gu - 运行 KVM 客户机代码(含客户机 nice 时间)所占的时间。
较旧的 procps-ng 版本可能在 st 列处结束 CPU 列。前面各列的含义不变。
持续监控
单份报告对实时问题的信息有限。传入一个延迟参数,可以观察连续间隔内的活动:
vmstat 2
这会每两秒打印一个新行,直到你按下 Ctrl+C。第一行仍然包含自启动以来的活动平均值,而后面的行覆盖每个两秒间隔。加上 -y 可以省略第一份报告:
vmstat -y 2
要采集十次间隔报告后停止,加上一个计数:
vmstat -y 2 10
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu------- r b swpd free buff cache si so bi bo in cs us sy id wa st gu 0 0 0 360988 94504 1208068 0 0 0 0 92 198 0 0 100 0 0 0 1 0 0 360744 94504 1208068 0 0 0 16 104 231 1 0 99 0 0 0 0 0 0 360720 94504 1208080 0 0 0 0 89 190 0 0 100 0 0 0
这里只显示前三行。因为 -y 跳过了即时的启动平均值报告,命令会等待并记录十个两秒间隔,耗时约 20 秒。
当你想稍后复查时,可以添加时间戳并把报告重定向到文件:
vmstat -y -t 2 10 > vmstat.log
活跃与非活跃内存
-a 标志会用 inact(非活跃内存)和 active(活跃内存)两列替换 buff 和 cache 列:
vmstat -a
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu------- r b swpd free inact active si so bi bo in cs us sy id wa st gu 0 0 0 358900 921048 490836 0 0 12 5 48 112 1 0 99 0 0 0
活跃内存包含最近使用、很可能再次被引用的页面。非活跃内存最近未被访问,在系统需要空间时包含可回收的候选页。当多个工作负载竞争内存时,这种视图很有用。
添加时间戳
-t 标志会在每行后面追加一个时间戳列,在把输出捕获到日志文件时很有用:
vmstat -y -t 2 5
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu------- -----timestamp----- r b swpd free buff cache si so bi bo in cs us sy id wa st gu EEST 0 0 0 362824 94368 1207160 0 0 0 0 88 195 0 0 100 0 0 0 2026-09-07 10:30:02 0 0 0 362700 94368 1207160 0 0 0 12 94 207 1 0 99 0 0 0 2026-09-07 10:30:04
时间戳使用系统的本地时区。示例只显示了所请求五次报告中的前两次。
宽输出模式
在拥有很多 CPU 核心或计数器值很高的系统上,默认的列宽可能导致数字被截断或列之间重叠。-w 标志切换到更宽的格式,避免截断:
vmstat -w 2
内存事件计数器
-s 标志会打印当前内存总量,后跟自启动以来累计的 CPU 和事件计数器:
vmstat -s
2023560 K total memory
417148 K used memory
493280 K active memory
921048 K inactive memory
362824 K free memory
94368 K buffer memory
1207160 K swap cache
2097148 K total swap
0 K used swap
2097148 K free swap
48712 non-nice user cpu ticks
952 nice user cpu ticks
12836 system cpu ticks
5181148 idle cpu ticks
5984 IO-wait cpu ticks
0 IRQ cpu ticks
3268 softirq cpu ticks
0 stolen cpu ticks
0 non-nice guest cpu ticks
0 nice guest cpu ticks
621264 K paged in
247908 K paged out
0 pages swapped in
0 pages swapped out
2518704 interrupts
5884112 CPU context switches
1788713671 boot time
52364 forks
确切的列表随内核和 procps-ng 版本而不同。这种视图对检查当前交换总量和累计分页活动很有用。事件计数器和 CPU 滴答在重启后会重新计数。
磁盘统计
-d 标志显示按磁盘设备拆分的累计读、写统计:
vmstat -d
disk- ------------reads------------ ------------writes----------- -----IO------
total merged sectors ms total merged sectors ms cur sec
sda 12486 983 956342 34208 18402 4682 920612 142104 0 42
sdb 142 0 9168 252 0 0 0 0 0 0
- total - 已完成的读或写操作总数。
- merged - 被合并为单个 I/O 操作的相邻请求数。
- sectors - 读写的扇区总数。
- ms - 读或写耗费的总毫秒数。
- cur - 当前正在进行的 I/O 操作数。
- sec - 做 I/O 耗费的总秒数。
要查看特定分区的统计而非整个磁盘:
vmstat -p /dev/sda1
sda1 reads read sectors writes requested writes
12384 948812 18320 910484
更改输出单位
默认情况下,内存和交换值使用 1024 字节的 kibibyte(KiB)。-S 标志改变它们的显示单位:
vmstat -S M 2
可接受的值是 k(1000 字节)、K(1024 字节)、m(1,000,000 字节)和 M(1,048,576 字节)。该选项不会改变交换(si、so)或 I/O(bi、bo)字段,它们仍以 KiB/s 为单位。
选项参考
- -a - 显示活跃与非活跃内存,而不是缓冲和缓存值。
- -d - 显示每个设备的磁盘统计。
- -D - 显示磁盘统计汇总。
- -f - 显示自启动以来的 fork 次数。
- -m - 显示 slab 内存信息。
- -n - 只打印一次表头。
- -p device - 显示分区级别的磁盘统计。
- -s - 显示内存统计和事件计数器。
- -S unit - 将内存和交换输出单位设为 k、K、m 或 M。
- -t - 在每行追加时间戳。
- -w - 使用更宽的列,避免不想要的列断裂。
- -y - 省略包含自启动以来活动平均值的第一份报告。
速查表
| 任务 | 命令 |
|---|---|
| 单次快照 | vmstat |
| 每 2 秒刷新 | vmstat 2 |
| 跳过启动平均值报告 | vmstat -y 2 |
| 10 次间隔报告,间隔 2 秒 | vmstat -y 2 10 |
| 活跃/非活跃内存视图 | vmstat -a 2 |
| 带时间戳的输出 | vmstat -t 2 |
| 宽输出 | vmstat -w 2 |
| 内存事件计数器 | vmstat -s |
| 磁盘统计 | vmstat -d |
| 分区统计 | vmstat -p /dev/sda1 |
| 以兆字节输出 | vmstat -S M 2 |
故障排查
为何所有数值看起来都像平均值而不是实时活动? 第一行包含自启动以来的活动平均值,不过其进程和内存字段是当前值。运行 vmstat -y 2 可跳过该行,只显示两秒间隔的报告。
为何 shell 报错 vmstat: command not found? 在 Ubuntu 和 Debian 上用 sudo apt install procps 安装 procps 包。Fedora 和 RHEL 用 sudo dnf install procps-ng,Arch Linux 用 sudo pacman -S procps-ng。
为何 vmstat 无法读取 /proc 下的数据? 命令需要访问 /proc 下的文件。以限制性 /proc 选项挂载的容器和系统可能隐藏部分统计信息。vmstat -m 视图还需要访问 /proc/slabinfo,普通用户可能无权访问。
结语
当系统变慢时,先运行 vmstat -y 2 做第一步检查,然后顺着信号深入:用 top 或 htop 查看每个进程的 CPU 和内存占用,或用 iostat -xz 2 查看设备延迟和队列。