摘要:生产环境接口变慢、机器负载高,但瓶颈究竟在 CPU、内存还是 IO?本文把 top/free/iostat/ss 基础四件套与 perf(采样剖析)、strace(系统调用追踪)、火焰图(可视化)串成一套可复用的排查方法论:先粗判方向,再选工具,读图定位根因,最后交叉验证。全文命令均可直接复现,建议收藏。
一、背景:为什么需要 perf、strace 与火焰图
1.1 生产排障的真实困境:"慢"不等于"CPU 满"
一个接口 P99 从 50ms 涨到 800ms,登上去 top 一看:%CPU 可能只有 30%,iowait 却飙到 40%;或者 CPU 看着正常,但 free -h 显示可用内存被吃光、开始 swap。三种典型瓶颈表现完全不同:
- CPU 饱和:用户态或内核态占满 CPU,需要定位热点函数;
- 内存压力:缺页风暴、缓存未命中率偏高、swap 换入换出;
- IO 阻塞:磁盘读写等待、或进程卡在某个网络/文件 syscall。
三者解法完全不同,所以第一步永远是"定方向",而不是上来就盲调。
1.2 三大工具的分工边界
+----------------+ +----------------+ +------------------+
| perf | | strace | | 火焰图 |
+----------------+ +----------------+ +------------------+
| 基于 PMU 的 | | 系统调用级 | | 把 perf 采样 |
| 采样剖析 | | 追踪 | | 结果可视化 |
| 定位 CPU 热点 | | 看进程卡在 | | 调用栈耗费 |
| 与内核态开销 | | 哪个 syscall | | 一目了然 |
| (on-CPU) | | (IO/锁/信号) | | |
+----------------+ +----------------+ +------------------+
- perf:基于 Linux perf_events,通过 PMU 硬件计数器与软件事件做采样,擅长定位 CPU 热点与内核态开销(on-CPU 时间)。
- strace:系统调用级追踪,擅长看进程"卡在哪个 syscall"——文件 IO、网络 IO、锁、信号都能看到。
- 火焰图:不是采集工具,而是把 perf 的采样结果可视化,直观看出时间花在哪条调用栈。
三者关系:perf / strace 负责"采",火焰图负责"看"。
二、工具链准备
perf 随 linux-tools 提供,最好与运行内核版本一致,否则部分硬件事件可能不可用。
```bash
# Debian/Ubuntu:perf 版本需与当前内核对应
apt install -y linux-tools-common linux-tools-$(uname -r) strace
# 校验
perf --version && strace -V && uname -r
```
火焰图由 FlameGraph 脚本集(stackcollapse-perf.pl 与 flamegraph.pl)生成,加入 PATH 即可调用。
端到端数据流:
```
perf record (采样 → perf.data)
→ perf script (导出带调用栈事件流)
→ stackcollapse-perf.pl (折叠相同调用栈)
→ flamegraph.pl (生成 SVG)
→ perf.svg (浏览器打开)
```
容器 / 虚拟化注意点:perf 在容器内需 CAP_PERFMON 或特权,否则多数事件被内核拒绝;strace 同样受 ptrace 权限限制。K8s 环境先确认 Pod 的 securityContext 是否放开相关能力。
三、基础四件套:先定方向(5 秒出结论)
```bash
top -b -n 1 | head -20 # CPU / 负载
mpstat 1 3 # 每核,重点 %iowait
free -h && vmstat 1 5 # 内存(看 available、si/so)
iostat -x 1 5 # 磁盘 %util、await
ss -s # 网络连数
ss -ant | awk '{print $1}' | sort | uniq -c | sort -rn
```
判定要点:
load / CPU核数 < 0.7 才健康;
free -h 看 available 列,不是 free;
vmstat 的 si/so > 0 或 %wa > 20%,基本锁定内存/磁盘方向。
四、CPU 瓶颈定位(perf + 火焰图)
```bash
# -F 99:每秒采样 99 次(社区惯例,平衡开销与精度)
perf record -F 99 -ag -- sleep 30
perf record -F 99 -p $PID -g -- sleep 30
perf report
perf top -p $PID
# 生成火焰图
perf script | stackcollapse-perf.pl | flamegraph.pl > cpu.svg
```
火焰图读法:横轴是采样总量(越宽越占 CPU),纵轴是调用栈深度,最宽的栈就是最耗 CPU 的路径。
验证要点:采样时间要覆盖业务高峰;-F 过高(-F 999)开销大、污染结果,惯例用 99。
五、内存瓶颈定位
perf stat -e cache-misses,cache-references,page-faults,major-faults \
-p $PID -- sleep 10
perf record -e page-faults -ag -p $PID -- sleep 10
free -h && vmstat 1 5
cat /proc/meminfo
major-faults(需从磁盘换入的缺页)显著偏高,往往意味着内存压力已逼出 IO;cache-misses 高说明热点数据没留在 CPU 缓存。深度泄漏分析需 jemalloc/jeprof、Valgrind 等。
六、IO 瓶颈定位(strace)
```bash
strace -Ttt -e trace=file,network -f -p $PID # 逐条看耗时
strace -c -f -p $PID -- sleep 5 # 汇总统计
iostat -x 1 && pidstat -d 1 # 系统级印证
```
-T 标出的高耗时 read/write/connect 就是阻塞点。某 connect 每次几百毫秒 → 问题大概率在下游/网络。
七、综合实战:接口变慢决策树
```bash
# 1) 定方向
top -b -n 1 | head -20 && mpstat 1 3
# 2) CPU 热点 + 火焰图
perf record -F 99 -ag -p $PID -- sleep 20
perf script | stackcollapse-perf.pl | flamegraph.pl > cpu.svg
# 3) syscall 层
strace -Ttt -e trace=file,network -f -p $PID -- sleep 5
# 4) 内存 / 缓存
perf stat -e cache-misses,page-faults -p $PID -- sleep 10
free -h && vmstat 1 5
```
典型结论:火焰图最宽栈是序列化函数 → 改代码;strace 显示 connect 高耗时 → 查下游/网络;vmstat 的 si/so 不为 0 → 加内存或查泄漏。
八、避坑与最佳实践
- strace 通过 ptrace 显著拖慢目标进程:生产慎用、避免长时间 attach;统计优先用 -c,拿完立刻退出。
- perf 采样频率并非越高越好:-F 99 是惯例。
- 火焰图只看 on-CPU 时间:进程卡在 IO/锁(off-CPU)时火焰图会"看起来很干净",需 off-CPU 火焰图(perf sched / eBPF),否则漏判。
- 环境约束:cat /proc/sys/kernel/perf_event_paranoid 默认多为 2~4,内核态/整机数据需 CAP_PERFMON/CAP_SYS_ADMIN。
- 采样要覆盖真实业务高峰,别把偶发抖动当稳定根因。
九、一页速查表(建议收藏)
|
方向 |
工具 |
关键命令 |
判读 |
|
CPU |
perf |
|
火焰图最宽栈 |
|
内存 |
free/vmstat |
|
available<10%、si/so>0 |
|
内存 |
perf |
|
major-faults 高 |
|
磁盘 |
iostat |
|
%util>70%、await>10ms |
|
网络 |
ss |
|
TIME-WAIT/CLOSE-WAIT 过多 |
|
syscall |
strace |
|
高耗时 read/write/connect |
总结:排查"慢"的核心不是工具多熟,而是先定方向、再选工具、读图定位、交叉验证这条链路走稳。把本文命令与决策树收进自己的排查剧本,下次告警来了就能少绕弯路。
2454



被折叠的 条评论
为什么被折叠?



