第2章:性能分析工具链——你的“听诊器”和“手术刀”
性能优化这事儿,说白了就是“找瓶颈”和“解瓶颈”。但瓶颈在哪?怎么找?靠猜肯定不行。你得有一套趁手的工具。我个人习惯把Linux性能工具集比作医生的听诊器、CT机和手术刀——它们能帮你定位病灶,甚至直接切除问题。
这一章,我们就来聊聊这些工具怎么用。不是罗列命令参数,而是告诉你:什么场景下该用哪个,怎么看输出,以及常见的坑在哪。
2.1 经典工具:从top到vmstat
先说说最基础的几个。你可能会觉得“这些我早就会了”,但别急,我保证有些细节你未必注意过。
2.1.1 top / htop —— 系统概况的“第一眼”
我每次登录服务器,第一件事就是敲top。为什么?因为它能最快告诉我系统是不是“病了”。
- CPU使用率:看
%us(用户态)和%sy(内核态)。如果%wa(I/O等待)很高,说明磁盘可能是瓶颈。 - 内存:注意
available而不是free。Linux会把空闲内存用作缓存,free很小不代表内存不够。 - 负载:
load average的三个值。如果超过CPU核数,说明任务在排队。
top,而是用htop。它支持鼠标操作、颜色区分、树形视图,看起来更直观。你可以按F6按CPU或内存排序,快速找到“罪魁祸首”。
2.1.2 iostat —— 磁盘I/O的“照妖镜”
有一次,我发现数据库查询特别慢。用top一看,CPU的%wa高达30%。我立刻用iostat -x 1查看磁盘详情。
# 每秒刷新一次,显示扩展统计
iostat -x 1
输出里,我重点关注这几个字段:
| 字段 | 含义 | 警戒线 |
|---|---|---|
%util |
磁盘忙绿百分比 | 超过80%可能有问题 |
await |
I/O请求平均等待时间(ms) | 机械盘>10ms,SSD>2ms |
svctm |
I/O服务时间(ms) | 接近await说明队列不严重 |
那次我看到await到了50ms,而svctm只有5ms。说明磁盘本身不慢,是请求排队太严重了。后来发现是日志写得太频繁,合并写入后问题解决。
%util 100%不一定代表磁盘满负荷。对于SSD,高并发下%util很容易到100%,但实际吞吐量还有余量。要结合await和r/s、w/s综合判断。
2.1.3 vmstat —— 系统整体的“体检报告”
vmstat是我用来快速排查CPU、内存、I/O三板斧的工具。命令很简单:
# 每2秒输出一次,共输出5次
vmstat 2 5
输出里,我主要看这几列:
- procs:
r(运行队列)和b(阻塞进程)。r持续大于CPU核数,说明CPU不够用。 - memory:
swpd(交换分区使用量)。如果这个值一直在涨,说明物理内存不足。 - cpu:
us、sy、id、wa。和top类似,但更简洁。
嗯,这里要注意:vmstat的si和so(swap in/out)如果非零,说明内存真的紧张了。我曾经遇到一个Java应用,因为堆内存设置过大,导致频繁swap,性能一落千丈。
2.2 高级工具:perf 和 strace
基础工具能告诉你“哪里有问题”,但高级工具能告诉你“为什么有问题”。
2.2.1 perf —— CPU性能分析的“瑞士军刀”
perf可以采样CPU正在执行的指令,告诉你热点在哪。我最常用的两个子命令:
# 采样CPU事件,默认99Hz
perf record -a -g -- sleep 10
# 生成火焰图的数据源
perf script > out.perf
-g表示记录调用栈,这样你才能知道热点函数是被谁调用的。我个人习惯采样10-30秒,太短可能不准确,太长数据量太大。
2.2.2 strace —— 跟踪系统调用的“显微镜”
有一次,一个Nginx worker进程CPU飙高。用perf一看,热点在epoll_wait和sendfile。但我想知道具体在操作哪些文件。这时候strace就派上用场了。
# 跟踪指定PID的系统调用
strace -p 12345 -e trace=file,network -c
-c参数会统计每种系统调用的次数和时间。那次我发现stat调用特别多,每秒上千次。原来是应用在反复检查文件是否存在。加了一层缓存后,CPU直接降了20%。
strace -p一个高并发进程,结果进程变慢了10倍。因为strace会拦截每次系统调用,开销很大。建议先在测试环境验证,或者用-c做统计模式,不要用默认的打印模式。
2.3 火焰图:性能分析的“可视化利器”
说实话,看perf report的文本输出,有时候挺费劲的。火焰图就直观多了。它把CPU采样结果画成一张“火焰山”一样的图:
- X轴:采样次数(越宽越热)
- Y轴:调用栈深度(越往上越深)
- 颜色:随机分配,无特殊含义
怎么看?找“平顶山”——就是顶部很宽的函数。那通常是CPU真正干活的地方。如果顶部很窄,但中间很宽,说明调用开销在中间层。
生成火焰图需要两个步骤:
# 1. 用perf采集数据
perf record -a -g -- sleep 30
perf script > out.perf
# 2. 用FlameGraph工具生成SVG
git clone https://github.com/brendangregg/FlameGraph
./FlameGraph/stackcollapse-perf.pl out.perf > out.folded
./FlameGraph/flamegraph.pl out.folded > flame.svg
然后直接用浏览器打开flame.svg,可以交互式点击放大。我个人习惯先看顶部的“平顶”,再看中间有没有“尖刺”。
2.4 BPF/eBPF:新时代的“万能工具”
如果你觉得perf和strace还不够灵活,那eBPF就是终极方案。它允许你在内核中安全地运行沙箱程序,动态追踪任何内核函数或用户态函数。
常用的eBPF工具集是BCC(BPF Compiler Collection)。我挑几个最实用的:
| 工具 | 功能 | 典型场景 |
|---|---|---|
execsnoop |
追踪新进程创建 | 排查谁在频繁启动进程 |
biolatency |
磁盘I/O延迟分布 | 分析I/O延迟是否均匀 |
tcplife |
追踪TCP连接生命周期 | 排查短连接问题 |
profile |
CPU采样(类似perf) | 生成火焰图 |
举个例子,你想知道某个进程为什么频繁读磁盘:
# 追踪PID为12345的进程的文件系统调用
trace -p 12345 'do_sys_open "%s", arg2'
这比strace轻量得多,因为eBPF在内核中做过滤,不会把每次调用都拷贝到用户态。
bcc/examples里的Python代码,慢慢就能自己写定制工具了。
2.5 工具选择:什么时候用哪个?
你可能会问:“这么多工具,我到底该用哪个?”我一般按这个思路来:
- 先看全局:
top或htop,确认CPU、内存、I/O哪个是瓶颈。 - 再深入细节:
- CPU问题 →
perf+ 火焰图 - 磁盘I/O问题 →
iostat→biolatency(eBPF) - 系统调用问题 →
strace -c(统计模式) - 网络问题 →
tcplife(eBPF)或netstat
- CPU问题 →
- 最后定位根因:用eBPF写定制脚本,或者用
perf的-g看调用栈。
举个例子,有一次线上告警说“接口响应慢”。我按这个流程走:
top看到CPU的%wa很高 → 磁盘I/O问题iostat -x 1看到await很高 → 确认是磁盘biolatency看到延迟分布很散 → 不是单一进程问题execsnoop发现有个脚本在频繁写日志 → 找到元凶
整个过程不到10分钟。这就是工具链的价值——不是单个工具多强,而是组合起来能快速定位问题。
下一章,我们会聊聊如何把这些工具应用到实际案例中。到时候我会拿一个真实的性能优化项目,从头到尾走一遍流程。你准备好了吗?