Linux 服务器性能监控命令速查与结果解读

适用场景:在 Linux 服务器(物理机 / 虚拟机 / Docker 宿主机)上排查 CPU、内存、磁盘、负载问题;
也适用于共享 / 生产服务器——判断"我跑的任务是否影响了别人、机器还扛不扛得住"。
本文不绑定任何具体业务,命令与解读均可通用。


目录

  1. 命令速查表
  2. 总体体检:uptime 与负载 load average
  3. CPU 使用:mpstat / top / ps / pidstat
  4. 内存与 Swap:free / vmstat
  5. 综合快照:vmstat 全列逐项解读
  6. 磁盘 I/O:iostat
  7. 容器视角:docker stats
  8. 历史回溯:sar(可选)
  9. 常用命令组合与持续记录
  10. 判断基准表与常见误区
  11. 实战排查套路
  12. 参考来源

一、命令速查表

命令 看什么 一句话要点
uptime 整机负载 看 load,但要除以 CPU 核数才有意义
free -h 内存 只看 available,别被 used 吓到
vmstat 1 5 综合 CPU/内存/Swap/IO/中断 一屏看全
mpstat -P ALL 1 3 CPU 每核占用、iowait、steal
top 进程/线程 CPU、内存 交互式,P 按 CPU 排、1 看每核
ps -eLf 线程级 查一个进程到底开了多少线程
pidstat 1 单进程 CPU 精确到进程/线程的 CPU 占用
iostat -x 1 磁盘 %util、await 判断磁盘是否瓶颈
sar -u -r 1 3 历史/当前 回溯过去任意时刻的状态(需 sysstat)
docker stats 容器 每个容器的 CPU/内存/PIDS,LIMIT 判是否限内存
nproc / lscpu 核数 解读 load、线程数前的必查项
watch -n 2 <cmd> 持续观察 每 2 秒刷新一次,盯变化

二、总体体检:uptime 与负载

命令

uptime

示例输出

 13:53:44 up 598 days, 23:30,  3 users,  load average: 48.15, 37.76, 28.08

输出逐段解释

字段 含义
13:53:44 当前系统时间
up 598 days, 23:30 系统已连续开机 598 天 23 小时(没重启过)
3 users 当前有 3 个会话登录
load average: 48.15, 37.76, 28.08 最近 1 / 5 / 15 分钟的平均负载

load average 怎么理解

  • 负载 = 平均有多少个任务"正在用 CPU 或在排队等 CPU"(还包括少量不可中断的磁盘等待任务)。可粗略理解为"收银台前的排队人数"。
  • 关键:负载没有按核数归一化。N 核机器上 load = N 表示"每个核刚好一直有人用"。
  • 判断方法:负载 ÷ 核数
    • load < 核数(如 128 核机 load=48):还很空,CPU 只用了约 3 成;
    • load ≈ 核数:CPU 已被占满,开始排队;
    • load 持续 > 核数:任务在排队等 CPU,系统过载。

先查核数再解读:

nproc            # 逻辑核数(最直接)
lscpu | grep -E '^CPU\(s\)|Core|Thread|Socket'   # 更详细的核数信息

三个时间点的含义

48.15, 37.76, 28.081 分钟 > 5 分钟 > 15 分钟 = 负载正在上升(刚才有任务启动或流量变大);
反之 1 分钟 < 15 分钟 = 负载在回落。这能帮你判断"是刚发生的还是长期现象"。


三、CPU 使用:mpstat / top / ps / pidstat

3.1 mpstat —— 每个核都在干什么

来自 sysstat 包,CentOS/RHEL:yum install sysstat;Ubuntu:apt install sysstat

mpstat 1 5              # 每 1 秒采样 1 次,共 5 次,看"全部核平均"
mpstat -P ALL 1 3       # 逐核看(-P ALL = 所有 CPU)

示例输出

13时53分45秒  all   36.29   0.00   2.45   0.00   0.46   0.20   0.00   0.00   0.00  60.61
13时53分46秒  all   33.97   0.00   3.09   0.00   0.56   0.23   0.00   0.00   0.00  62.16
平均时间:     all   34.05   0.00   2.43   0.00   0.49   0.22   0.00   0.00   0.00  62.79

列含义

含义 正常 异常信号
%usr 用户程序(业务/应用/脚本)的时间占比 看业务 持续很高 = 应用在算
%sys 内核代码(系统调用、内存管理等)占比 < 10% 很高 = 内核忙(如大量中断/调度)
%iowait CPU 空等磁盘 I/O 的时间占比 持续高 = 磁盘是瓶颈(应用在等读盘/写盘)
%irq / %soft 硬件 / 软件中断处理占比 高 = 网卡/磁盘中断风暴
%steal 虚拟机的 CPU 时间被宿主机抢走的占比 0~1% 持续 > 5% = 宿主机超卖,性能被邻居拖累
%idle 空闲占比 越高越好 长期为 0 = CPU 满负荷

这些百分比是相对全部核的总时间all 行),不是"占满几个核"。
例如 128 核机 %usr=34%、%idle=62% ≈ 128×0.38 ≈ 48 核在忙,其余空闲。

3.2 top —— 进程级别找"谁在吃 CPU"

top                  # 进入交互界面
top -bn1             # 非交互,只输出一次就退出(适合脚本/日志)

示例输出(头部)

top - 03:12:38 up 1:53, 3 users,  load average: 1.72, 0.62, 0.25
Tasks: 198 total, 1 running, 197 sleeping, 0 stopped, 0 zombie
%Cpu(s): 29.2 us, 22.0 sy, 0.0 ni, 48.5 id, 0.0 wa, 0.0 hi, 0.3 si, 0.0 st
MiB Mem :  7697.8 total,  3672.6 free,  576.6 used,  3448.5 buff/cache
MiB Swap:    0.0 total,    0.0 free,    0.0 used. 6838.4 avail Mem

 PID USER  PR NI   VIRT   RES  SHR S  %CPU %MEM TIME+   COMMAND
17038 root  20  0   8476  2984 1984 D   3.7  0.0 0:00.77 dd
16979 root  20  0      0     0    0 D   1.3  0.0 0:00.14 kworker...

关键行解释

行/列 含义
第 1 行 同 uptime(时间 / 运行时长 / 负载)
Tasks: 进程总数;running 正在跑、sleeping 睡眠、zombie 僵尸进程(应警惕)
%Cpu(s): 整机 CPU 分布,列含义同 mpstat(us=用户、sy=内核、wa=等磁盘、st=被抢)
MiB Mem/Swap: free,末尾 avail Mem 就是 available
PID USER PR NI 进程号 / 用户 / 优先级
VIRT RES SHR 虚拟内存 / 实际占用的物理内存 RES / 共享内存
S 状态:R运行、S睡眠、D不可中断(常在等磁盘)、Z僵尸
%CPU 该进程相对"1 个核"的占用:100% = 占满 1 核;多线程进程可 >100%(如 400% = 4 核)
%MEM 占物理内存百分比(按 RES 算)
TIME+ 累计消耗的 CPU 时间(可识别偷跑的常驻任务)
COMMAND 命令名

top 常用交互键

作用
P 按 CPU 降序(默认就是)
M 按内存降序
1 展开 / 收起每个核的占用
H 切换线程级视图(看多线程进程内部)
c 显示完整命令行
q 退出

注意 %CPU 的意义:是相对 1 个核的百分比。容器监控里 docker stats 也沿用这个口径,
所以一台 128 核机器上出现 4000% 表示"用了约 40 个核",不是占了机器 4000%。

3.3 ps —— 线程级 / 内存大户排查

ps -eLf                  # 每个进程的每一行是一个"线程"(可数线程数)
ps -eLf | wc -l          # 系统总线程数
ps aux --sort=-%mem | head -n 15      # 内存占用最高的 15 个进程
ps aux --sort=-%cpu | head -n 15      # CPU 占用最高的 15 个进程

ps -eLf 输出的 NLWP 列 = 该进程的线程数;LWP = 线程 ID。
常用于确认"一个进程为什么占了很多 CPU/内存"或"线程是否异常增多(泄漏)"。

3.4 pidstat —— 精确到进程/线程的 CPU

pidstat 1 5              # 每秒一次,看每个进程的 CPU
pidstat -t 1 3           # -t 看每个线程(同 top 的 H 视图)
pidstat -r 1 3           # -r 看内存

四、内存与 Swap:free / vmstat

4.1 free —— 内存体检表

free -h        # -h 人类可读单位(G/M);-m 按 MB 显示更精确

示例输出

              total        used        free      shared  buff/cache   available
Mem:           251Gi       198Gi        17Gi       8.1Gi        35Gi       42Gi
Swap:           63Gi        40Gi        23Gi

列含义

含义 要点
total 物理内存总量
used 已被程序占用的 别被它吓到,见下方误区
free 完全没人用的 Linux 会尽量把它拿来当缓存,所以通常很小
shared 共享内存(tmpfs 等)
buff/cache 磁盘读写缓存 需要时可随时让出给程序
available 真正还能给新程序用的内存 只看这一列 ≈ free + 可回收 cache
Swap 行 硬盘当内存的"备用内存" used 大 = 历史/当前内存吃紧过

结论口诀used 大 ≠ 内存不足;available 持续下降才是警报。
Swap 的 used 很大会拖慢性能(硬盘比内存慢几个数量级),但只要"此刻没有在换入换出"(见 vmstat 的 si/so),影响可控。

4.2 vmstat —— 内存与 Swap 是否在折腾

vmstat 1 5

见下一节的完整解读;内存相关的关键列是:

含义 判断
swpd 当前被换到 swap 的量(KB) 存量高但稳定通常无害
si / so 每秒从磁盘换入内存 / 从内存换出磁盘的量 长期 > 0 = 内存不足,在疯狂 swap,性能暴跌

si/so 都是 0 = 内存虽然紧但没有活跃交换,属于"紧张但不恶化"。


五、综合快照:vmstat 全列逐项解读

vmstat 一条命令覆盖 进程/内存/Swap/IO/中断/CPU,适合第一眼定位"瓶颈在 CPU 还是磁盘还是内存"。

vmstat 1 5        # 每 1 秒输出 1 次,共 5 次(次数可改)
vmstat 2          # 每 2 秒一次,Ctrl+C 退出

示例输出

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd    free   buff  cache   si   so    bi    bo   in    cs us sy id wa st
43  0  42386452 18717224  1068 37089000  0    0     0     0   530 456231 32  3 65  0  0
45  0  42386452 18717724  1068 37087680  0    0     0     0   530  37043 34  6 60  0  0

分组解读

procs(进程/线程队列)

含义 判断
r 正在跑 + 排队等 CPU 的任务数 结合核数看:r ≈ 忙碌核数 → 平衡;r 持续远超核数 → CPU 排队超订
b 阻塞在磁盘 I/O 上的任务数 长期 > 0 = 磁盘瓶颈,任务都在等读盘/写盘

经验:r > 核数 + 3 偏高、r > 核数 + 5 很高、r > 核数 + 10 异常(参考社区经验)。
但 128 核大机器上 r=45 若忙核约 48,二者匹配,属正常并行,不是过载。

memory(内存)

含义
swpd 换出到 swap 的量(KB)
free 空闲内存(不含缓存)
buff / cache 缓冲区 / 文件缓存(可回收)

swap(换页) —— 最重要的一对

含义 判断
si 每秒从磁盘换入内存(KB/s) 长期 > 0 = 物理内存不够
so 每秒从内存换出到磁盘(KB/s) 同上

io(块设备读写)

含义 判断
bi / bo 每秒从磁盘读/写的块数(1 块 ≈ 1KB 量级) 结合 CPU 的 wa 看磁盘压力

system(系统)

含义 判断
in 每秒中断次数 异常飙高查网卡/磁盘中断
cs 每秒上下文切换次数(线程之间切来切去) 高 = 线程多/并行活跃;异常高(如几十万)可能锁竞争过度

cs 高不一定坏:多进程多线程的并行任务(如大数据计算)自然切换频繁。
只有当"cs 极高 + us 却不高"时才要怀疑线程空转/锁竞争。

cpu(最后 5 列,含义同 mpstat)

含义
us 用户程序占比
sy 内核占比
id 空闲占比
wa 空等磁盘 I/O 占比
st 被虚拟机管理程序偷走占比

第一个坑vmstat 1 5第一行是"开机以来的平均值",不代表当前状态,要看从第二行起的数据
第二个坑wa 高且 bi/bo 也高 → 磁盘在忙;wa 高但 bi/bo 低 → 可能是大量进程同时争抢、或外接存储(网络盘)延迟。


六、磁盘 I/O:iostat

iostat -x 1 5        # -x 扩展模式;每 1 秒 1 次共 5 次
iostat -x -d sda 1   # 只看指定盘

示例输出

Device            r/s     w/s   rkB/s   wkB/s  await  %util
sda              12.50   45.60  1024.0  4096.0   8.20  45.30

关键列

含义 判断
r/s w/s 每秒读写请求数
rkB/s wkB/s 每秒读写数据量
await 每个请求平均等待时间(毫秒) 高 = 盘慢或排队
%util 磁盘忙碌占比 接近 100% = 磁盘已到吞吐上限,是瓶颈

注意:%util 对机械盘/SSD/阵列/云盘的"饱和点"不同,需结合 await 一起看。


七、容器视角:docker stats

共享 Docker 宿主机上,除了看整机,还要看每个容器占了什么、有没有设限制。

docker stats                      # 实时刷新所有容器
docker stats --no-stream          # 只看当前一屏就退出(适合脚本)
docker stats --no-stream ocr-extract   # 只看某个容器
docker stats --no-stream --format "{{.Name}} CPU={{.CPUPerc}} MEM={{.MemUsage}} PIDS={{.PIDs}}"

示例输出

CONTAINER ID   NAME                    CPU %     MEM USAGE / LIMIT    MEM %    PIDS
347bd454f4bd   my-app                  2924.40%  3.782GiB / 251.8GiB  1.50%    61

列含义

含义 要点
CPU % 相对 1 个核 = 100% 400% = 用了 4 个核;要占整机几成需 ÷ 宿主机核数
MEM USAGE / LIMIT 已用 / 上限 LIMIT = 宿主机总内存 = 该容器没设内存上限(危险);LIMIT 是 10GiB 之类 = 设了限制
MEM % 已用占上限比例
PIDS 该容器内进程 + 线程总数 可快速判断"容器里到底开了多少线程"

判断"我的容器是否影响别人"三步法

  1. 跑之前记基线uptimefree -hdocker stats --no-stream
  2. 跑的时候对比mpstat 1 5(整机 idle 别掉到太低)、free -h(available 别持续下降)、vmstat 1 5(si/so 别起来)、再 docker stats 看邻居容器 CPU 有无异常变化;
  3. 收尾:确认机器恢复了基线水平。

CPU 层面 Docker 用配额(--cpus/compose 的 cpus:)设"时间上限",超了只会节流自己(变慢),一般不会抢别人;
真正会波及全机的是内存——不设 mem_limit 的容器可以吃满宿主机内存、触发全局 swap/OOM,这才是共享机大忌。


八、历史回溯:sar(可选)

sar 属于 sysstat 包,默认每 10 分钟自动记录一次历史,可回溯"当时发生了什么"。

sar -u 1 3           # CPU:每秒 1 次共 3 次
sar -u -f /var/log/sa/sa15   # 回看 15 号那天的 CPU(文件名对应当天日期)
sar -r 1 3           # 内存
sar -S 1 3           # Swap
sar -b 1 3           # 磁盘 I/O
sar -q               # 负载队列
sar -n DEV 1 3       # 网卡流量

列含义与 vmstat/mpstat 一致,只是多带时间戳,方便对齐故障时间点。


九、常用命令组合与持续记录

盯一段时间的负载、跑完看峰值,推荐把输出落到文件:

# 每 5 秒记一次 CPU/内存快照,Ctrl+C 停止后查看
while true; do date +%F\ %T; mpstat 1 1 | tail -1; free -h | sed -n '2p'; done | tee perf.log

# 每 10 秒记一次某容器的 CPU/内存
while true; do date +%T; docker stats --no-stream --format "CPU={{.CPUPerc}} MEM={{.MemUsage}} PIDS={{.PIDs}}" my-app; sleep 10; done | tee container.log

实时刷新用 watch

watch -n 2 'free -h && uptime'          # 每 2 秒刷新内存与负载
watch -n 5 'docker stats --no-stream'   # 每 5 秒刷新容器

十、判断基准表与常见误区

判断基准速查(经验值,按需微调)

指标 正常 注意 危险
load ÷ 核数 < 0.7 0.7 ~ 1.0 持续 > 1.0
%usr + %sys < 70% 70 ~ 90% 接近 100% 且持续
%iowait / 磁盘 %util < 30% 30 ~ 60% > 60% 持续(磁盘瓶颈)
%steal(虚拟机) 0~1% 2~5% 持续 > 5%(宿主机超卖)
available 内存 > 30% total 10~30% < 10% 且持续下降
si / so 0 偶发 长期 > 0(在 swap,性能暴跌)
r(运行队列) ≤ 核数 核数~核数+5 持续 > 核数+10
b(阻塞任务) 0 少量 持续 > 0(等磁盘)
僵尸进程 0 少量 持续增长(父进程没回收)

常见误区

  1. "free 的 used 198G,内存爆了!"
    → 错。要缓存能吐出来,看 available 才准。
  2. "load 48 太高了!"
    → 错。48 核机器 load 48 = 满载;128 核机器 load 48 = 只用了 3 成。必须除以核数
  3. "docker stats 显示 2924%,占满机器了!"
    → 错。那是"占了 29 个核",128 核机器才用了 2 成多。CPU% 是相对 1 核的
  4. "多线程进程 400%,机器要冒烟了"
    → 400% = 4 个核同时算,先看机器总共几核再说。
  5. "%iowait 高 = CPU 不行"
    → 相反,wa 高说明 CPU 在空等磁盘,瓶颈是磁盘。
  6. "si/so 大数字可怕" —— 看的是"每秒速率",持续为 0 就没事;swpd 存量高只是历史。
  7. "vmstat 第一行就是当前状态"
    → 第一行是开机累计平均,看第二行起的数据。

十一、实战排查套路

场景 A:CPU 高,找"谁在吃"

top -bn1 | head -n 20          # 找大 %CPU 进程
ps -eLf | grep <PID>           # 看该进程开了多少线程
pidstat -t 1 5 | grep <PID>    # 看具体哪个线程在烧 CPU

场景 B:内存不足 / 疯狂 swap

free -h                        # available 是否告急
vmstat 1 5                     # si/so 是否长期 > 0
ps aux --sort=-%mem | head     # 谁占内存最多

场景 C:慢得像卡死,分不清瓶颈

vmstat 1 5     # 一屏定方向:
#  b>0 或 wa 高  → 磁盘问题 → iostat -x 1
#  r 远大于核数   → CPU 排队 → top 找进程
#  si/so > 0     → 内存不足 → free -h + 找大内存进程

场景 D:共享/生产机上,确认自己没影响别人

# 跑前基线
uptime; mpstat 1 3 | tail -1; free -h; docker stats --no-stream

# 跑中(自己 + 邻居)
while true; do date +%T; mpstat 1 1 | tail -1; docker stats --no-stream --format "{{.Name}} {{.CPUPerc}} {{.MemUsage}}"; sleep 5; done

# 观察重点:整机 idle 别掉太低;available 别持续跌;邻居容器 CPU 无明显突增;
# si/so 保持 0;docker stats 里邻居 LIMIT=宿主机内存的裸奔容器尤其要留意(你的内存上涨会挤到它们)。

十二、参考来源