2. 性能检测工具链:Linux perf、top、htop、iostat、vmstat 实战

说实话,很多做性能优化的同学,一上来就盯着代码看。我当年也犯过这个错。后来带我的老大哥说了一句话,我一直记着:「先看系统,再看代码,最后看算法。」

什么意思呢?就是你的程序跑在操作系统上,系统资源就是它的「土壤」。土壤不行,苗再好也长不高。所以这一章,咱们就把 Linux 下最常用的几把「锄头」摸清楚。

2.1 先搭个「全景图」

工欲善其事,必先利其器。下面这张图,是我自己梳理的 Linux 性能检测工具全景。你把它存脑子里,以后排查问题就有方向了。

Linux 性能检测工具全景图 性能瓶颈定位 CPU 检测 top / htop perf 内存检测 vmstat 磁盘 IO 检测 iostat 💡 排查顺序建议 先看 CPU 是否跑满(top)→ 再看内存是否够用(vmstat)→ 最后看磁盘 IO 是否瓶颈(iostat) 如果 CPU 没跑满但性能差,用 perf 采样看热点函数

2.2 top / htop:第一眼诊断

我个人习惯,登录服务器第一件事就是敲 top。它就像医院的「生命体征监测仪」,看一眼就知道病人还有没有救。

2.2.1 top 核心指标解读

指标 含义 警戒线
%us 用户态 CPU 占用 > 70% 说明应用在忙
%sy 内核态 CPU 占用 > 30% 可能有系统调用瓶颈
%wa 等待 IO 的 CPU 占比 > 20% 磁盘大概率是瓶颈
%id 空闲 CPU < 10% 说明 CPU 吃紧
load average 1/5/15 分钟平均负载 超过 CPU 核数说明排队
小技巧: top 里按 1 可以看每个 CPU 核的使用情况。我曾经遇到一个 Java 服务,整体 CPU 才 40%,但有一个核跑到了 100%。这就是典型的「单线程瓶颈」。

2.2.2 htop:top 的「可视化升级版」

htop 说白了就是 top 的图形化版本。它支持鼠标操作、彩色显示、树形进程视图。我个人更喜欢 htop,因为一眼就能看到哪个进程在「吃」资源。

# 安装 htop
sudo apt install htop -y

# 直接运行
htop

htop 的几个常用快捷键:

  • F6:按 CPU/内存/IO 排序
  • F9:直接杀掉进程
  • F5:树形视图,看父子进程关系
注意: htop 默认不显示线程。如果你要排查多线程应用的问题,记得按 H 键切换线程视图。我曾经排查过一个 Nginx 性能问题,就是因为没开线程视图,找了半天才发现是某个 worker 线程卡住了。

2.3 vmstat:内存与进程的「X 光机」

vmstat 是我最常用的内存分析工具。它不仅能看内存,还能看进程状态、CPU 上下文切换、IO 等待。你想想看,一个命令能看这么多东西,是不是很划算?

# 每隔 1 秒输出一次,共输出 5 次
vmstat 1 5

输出示例:

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 1623452  1234 567890    0    0    12    34  456  789 12  3 85  0  0

2.3.1 关键字段解读

字段 含义 实战经验
r 正在运行的进程数(就绪队列) 如果持续 > CPU 核数,说明 CPU 不够用
b 不可中断睡眠的进程数 数值大说明 IO 有瓶颈
si / so swap 换入/换出 只要不是 0,内存就不够了
cs 上下文切换次数/秒 超过 10 万次要考虑优化
核心判断逻辑:
  • 如果 r 很大但 b 很小 → CPU 瓶颈
  • 如果 b 很大且 wa 很高 → IO 瓶颈
  • 如果 si/so 不为 0 → 内存不足,赶紧加内存或优化内存使用

2.4 iostat:磁盘 IO 的「听诊器」

我记得有一次线上告警,数据库查询特别慢。我第一反应是 SQL 写得烂,结果用 iostat 一看,磁盘利用率才 30%,但 await 高达 200 毫秒。嗯,这里要注意,不是磁盘满了才叫瓶颈,响应时间长了也是问题。

# 安装 sysstat 包(包含 iostat)
sudo apt install sysstat -y

# 每隔 2 秒输出一次,监控 sda 磁盘
iostat -x sda 2

2.4.1 核心指标

指标 含义 正常范围
%util 磁盘忙碌时间百分比 < 80% 算正常
await IO 请求平均等待时间(ms) SSD < 10ms,机械盘 < 50ms
svctm IO 请求平均服务时间(ms) 越接近 await 说明排队少
r/s / w/s 每秒读写次数 SSD 通常能到几万次
避坑指南: 我曾经遇到一个案例,%util 只有 30%,但业务方说磁盘很慢。后来发现是磁盘做了 RAID 5,写操作有校验开销。所以看 iostat 不能只看 %util,要结合 await 和 svctm 一起看。

2.5 perf:CPU 热点函数的「显微镜」

前面几个工具都是「宏观」的,告诉你哪里有问题。但具体是哪一行代码导致的?这时候就要请出 perf 了。

# 采样 10 秒,记录 CPU 事件
sudo perf record -a -g -- sleep 10

# 生成火焰图数据
sudo perf script > out.perf

# 用 FlameGraph 工具生成 SVG 火焰图
git clone https://github.com/brendangregg/FlameGraph
cd FlameGraph
./stackcollapse-perf.pl ../out.perf > out.folded
./flamegraph.pl out.folded > flame.svg

2.5.1 perf 常用场景

  • CPU 热点:perf top 实时查看当前 CPU 占用最高的函数
  • 缓存 miss:perf stat -e cache-misses ./your_app
  • 上下文切换:perf stat -e context-switches ./your_app
实战案例: 我之前优化一个 Redis 集群,发现 CPU 使用率很高但 QPS 上不去。用 perf 采样后发现,热点函数是 dictFind,说明哈希冲突严重。调整了哈希表大小后,QPS 提升了 30%。

2.6 工具选择速查表

场景 首选工具 辅助工具
CPU 跑满 top / htop perf(找热点函数)
内存不足 vmstat free -m
磁盘慢 iostat -x iotop(看哪个进程在读写)
上下文切换高 vmstat (cs 字段) perf stat -e context-switches
不知道哪里慢 perf top 火焰图

2.7 实战:一次完整的排查流程

最后,我带你走一遍真实场景。假设你的 Java 服务响应变慢了:

  1. 第一步:top 看全局
    • 发现 CPU 使用率 90%,其中 %wa 占 40%
    • 初步判断:磁盘 IO 可能是瓶颈
  2. 第二步:iostat 确认
    • iostat -x 1 看到 %util 95%,await 150ms
    • 确认:磁盘确实扛不住了
  3. 第三步:vmstat 看内存
    • 发现 si/so 不为 0,说明内存也在 swap
    • 嗯,这里要注意,内存不足会导致磁盘 IO 增加
  4. 第四步:perf 定位代码
    • perf top -p <pid> 看到热点在日志写入函数
    • 原来是日志框架配置了同步刷盘
  5. 第五步:优化
    • 改成异步日志,加内存,问题解决
重要提醒: 性能排查最忌讳「猜」。不要觉得「可能是网络问题」就去调网络参数。先用工具看数据,让数据告诉你答案。我见过太多人凭感觉改配置,越改越糟。

好了,这一章的工具链你掌握了,以后遇到性能问题就不会慌了。记住那个排查顺序:top → vmstat → iostat → perf。从宏观到微观,从现象到本质。