外观
性能四件套:vmstat / iostat / sar / pidstat
top 只能告诉你"谁吃 CPU"。判断瓶颈在 CPU、内存、磁盘还是网络,靠这四个工具联读。
场景
"服务器很慢"是无效描述。要变成"CPU 打满"、"磁盘 IO 等待高"、"内存不足在换页"或"网络丢包",才能动手。
一、起手式
bash
uptime
vmstat 1 5
iostat -xz 1 3
free -h
ss -stext
22:30:11 up 1 day, 4:10, 2 users, load average: 8.41, 7.88, 7.62load 8.41 在 4 核机器上是 2 倍过载。接下来看是什么导致的。
二、vmstat:一眼看四类资源
bash
vmstat 1 5text
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
6 2 0 184320 12800 512000 0 0 120 2048 12000 18000 38 6 50 6 0
5 2 0 180112 12800 508800 0 0 240 4096 13200 19100 41 7 46 6 0字段分组记忆:
| 列 | 含义 | 异常判断 |
|---|---|---|
r | 等待运行的任务数 | 持续 > 核数 = CPU 排队 |
b | 不可中断睡眠(等 IO) | 持续 > 0 = IO 或锁 |
swpd | 已用 swap | > 0 且持续增长要警惕 |
free | 空闲内存(不含缓存) | 小是正常的 |
buff/cache | 内核缓冲/页缓存 | 大是好事 |
si / so | 每秒换入/换出 | 非 0 就是内存不足 |
bi / bo | 每秒块读/写 | 与磁盘能力对比 |
in / cs | 中断/上下文切换 | cs 极高 = 线程争抢或频繁切换 |
us / sy | 用户/系统态 | sy 高 = 系统调用多 |
id | 空闲 | — |
wa | 等 IO | > 20% 磁盘瓶颈 |
st | 被虚拟化偷走 | 云主机超卖 |
free 显示内存少不等于有问题
Linux 会尽量用内存做页缓存(buff/cache)。真正的可用内存是 available:
bash
free -htext
total used free shared buff/cache available
Mem: 15Gi 13Gi 512Mi 1.0Gi 1.8Gi 900Miavailable 才会在需要时被回收给应用。free 小是正常设计。
联读判断
| 组合 | 结论 |
|---|---|
r 高、us 高、id 低 | CPU 不够(计算密集) |
r 高、id 高、wa 高 | IO 等待,CPU 在空转 |
b > 0、wa 高 | 磁盘或 NFS 卡 |
si/so > 0 | 内存不足,在 swap |
cs 极高、sy 高 | 上下文切换/系统调用过多 |
st > 5 | 云主机被超卖,或宿主机争抢 |
三、iostat:哪块盘慢
bash
iostat -xz 1 3text
Device r/s rkB/s w/s wkB/s rrqm/s wrqm/s r_await w_await aqu-sz %util
vda 2.10 48.0 184.40 14721.6 0.00 12.40 0.82 8.42 1.24 98.40
vdb 0.00 0.0 0.20 1.6 0.00 0.00 0.20 0.42 0.00 0.12| 字段 | 含义 | 判断 |
|---|---|---|
r/s / w/s | 每秒读写次数(IOPS) | 与盘的能力对比 |
rkB/s / wkB/s | 吞吐 | — |
r_await / w_await | 平均等待时间(ms) | SSD < 1ms,HDD < 10ms |
aqu-sz | 平均队列长度 | 持续 > 2 说明排队 |
%util | 设备忙碌百分比 | > 80% 饱和 |
-x 显示扩展指标,-z 隐藏空闲设备。只看 %util 不够:机械盘 %util 100% 是饱和,但 NVMe 队列深时 %util 也能到 100% 而吞吐还很高。要结合 await 和 aqu-sz。
bash
iostat -x 1 3 vda # 只看某块盘
iostat -d -m 1 3 # 按 MB 显示四、sar:历史趋势
iostat/vmstat 只有当下。要复盘"昨天 3 点为什么慢",用 sar(需要 sysstat 服务在采集)。
bash
# CPU
sar -u 1 3
sar -u -f /var/log/sa/sa27 -s 03:00:00 -e 04:00:00
# 磁盘
sar -d 1 3
# 网络
sar -n DEV 1 3
sar -n EDEV 1 3 # 错误和丢包
# 内存
sar -r 1 3
# 队列与负载
sar -q 1 3text
22:30:00 LINUX RESTART
22:31:01 CPU %user %nice %system %iowait %steal %idle
22:32:01 all 38.21 0.00 6.12 5.04 0.00 50.63
22:32:01 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
22:32:01 eth0 12401.2 11892.4 1842.11 2104.88 0.00 0.00 0.00sar 的价值在于时间维度:%iowait 每天 3 点飙到 30%,就能对上备份任务。
bash
ls /var/log/sa/text
sa25 sa26 sa27 sar25 sar26 sar27sa* 是二进制,sar -f 读取;sar* 是文本报告。
五、pidstat:按进程拆
iostat 说的是"盘忙",pidstat 说的是"谁在忙"。
bash
pidstat 1 3
pidstat -d 1 3
pidstat -r 1 3
pidstat -w 1 3
pidstat -u -p 28441 1 3text
Average: UID PID %usr %system %guest %wait %CPU CPU Command
Average: 99 28441 38.21 2.10 0.00 0.12 40.31 2 java
Average: 27 29112 6.42 1.88 0.00 0.04 8.30 1 mysqld
Average: UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
Average: 99 28441 0.00 12288.00 0.00 42 java
Average: UID PID minflt/s majflt/s VSZ RSS %MEM Command
Average: 99 28441 0.00 0.00 4214320 2012340 12.40 java
Average: UID PID cswch/s nvcswch/s Command
Average: 99 28441 1842.10 42.10 java| 模式 | 看什么 |
|---|---|
| 默认 | %usr / %system / %wait |
-d | 读写 KB/s 和 iodelay(IO 阻塞时间) |
-r | minflt(缺页)、majflt(从磁盘换页,非 0 说明内存不足) |
-w | 自愿/非自愿上下文切换(锁竞争时非自愿切换高) |
%wait 是进程等 CPU 的时间。%CPU 不高但 %wait 高,说明 CPU 被别的进程占了。
六、完整判断流程
text
1. uptime 看 load 与核数
↓ load 高
2. vmstat 看 r / b / si / wa
↓
├─ r 高、us 高 → CPU 瓶颈 → pidstat 找进程 → top -Hp 找线程
├─ wa 高、b > 0 → IO 瓶颈 → iostat 找盘 → pidstat -d 找进程
├─ si/so > 0 → 内存不足 → free -h、pidstat -r、dmesg OOM
└─ cs 高、sy 高 → 系统调用/切换过多 → pidstat -w、strace -c
↓ 以上都正常
3. sar -n DEV 看网络,sar -n EDEV 看丢包七、一次完整案例
现象:接口 P99 从 50ms 涨到 800ms。
bash
uptimetext
22:40:11 up 1 day, 4:20, load average: 9.12, 8.44, 7.904 核机器 load 9,过载。
bash
vmstat 1 3text
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 6 0 120320 12800 512000 0 0 480 8192 14200 21000 12 4 22 62 0b=6、wa=62%、id=22% → IO 瓶颈,CPU 在等盘。
bash
iostat -xz 1 2text
Device r/s rkB/s w/s wkB/s r_await w_await aqu-sz %util
vda 12.40 1024.0 420.2 18432.0 18.42 42.10 8.24 99.8vda 的 w_await 42ms(SSD 应 < 2ms)、aqu-sz 8.24、%util 99.8% → 这块盘被打满了。
bash
pidstat -d 1 2text
UID PID kB_rd/s kB_wr/s iodelay Command
99 28441 0.00 16384.00 82 javajava 每秒写 16MB,iodelay 82 → 就是它。
结论:某个功能在疯狂写磁盘。继续查应用日志/慢查询,而不是去调 JVM 参数。
八、踩过的坑
| 现象 | 根因 | 处置 |
|---|---|---|
vmstat 的 free 很小就以为内存不足 | 页缓存占着 | 看 available 和 si/so |
wa 高但 iostat 看不出哪个盘 | 没加 -x,或看漏了挂载点 | iostat -xz,结合 df 定位盘 |
| load 高但 CPU 空闲 | b 列 / D 状态进程 | ps -eo stat,wchan |
sar 没数据 | sysstat 服务没启用 | systemctl enable --now sysstat |
%util 100% 但很快 | NVMe 队列深度特性 | 看 await 和吞吐,不只看 %util |
cs 极高 | 线程数过多、锁竞争 | pidstat -w,查线程池配置 |
st > 10 | 云主机争抢 | 换规格或提工单 |
| 指标都正常但业务慢 | 网络、下游、GC、连接池 | 继续查 sar -n、应用侧监控 |