strace 和 perf:Linux 进程调试和性能分析深度指南
当线上服务出现莫名的性能下降、神秘的"文件未找到"错误或奇怪的网络超时,常规的日志分析往往无法给出答案。这时候需要深入内核层面,观察进程的真实行为。
strace 和 perf 是 Linux 系统性能诊断的两把利刃:strace 追踪进程的系统调用,揭示进程与内核的每次交互;perf 是 Linux 内核内置的性能分析器,能够捕获 CPU 级别的性能事件,生成直观的火焰图。掌握这两个工具,能够解决 80% 以上的难以排查的线上问题。
服务器配置
strace 和 perf 是通用的 Linux 诊断工具,适用于任意服务器。推荐使用 雨云服务器 rainyun-com 的2 核 4GB 机型 作为学习和实验环境,注册填优惠码 2026off 领 5 折,以最低成本掌握 Linux 性能分析技能。
本文环境:
- 操作系统:Ubuntu 22.04 LTS(内核 5.15+)
- strace:5.16
- perf:5.15(随内核版本提供)
安装工具
安装 strace
Ubuntu/Debian:
bash
apt install strace -y
strace --version
# strace -- version 5.16
安装 perf
perf 工具与内核版本绑定,需要安装对应版本:
bash
# 查看内核版本
uname -r
# 例如:5.15.0-106-generic
# 安装对应版本的 perf
apt install linux-tools-$(uname -r) linux-tools-generic -y
# 验证安装
perf --version
# perf version 5.15.168
如果出现 "WARNING: perf not found for kernel" 错误,说明内核版本对应的包不在仓库中,可以使用通用包:
bash
apt install linux-tools-generic -y
strace 基础:追踪系统调用
基本用法
追踪一个命令的所有系统调用:
bash
strace ls /tmp
输出中每行是一次系统调用,格式为:
syscall_name(args...) = return_value
execve("/usr/bin/ls", ["ls", "/tmp"], ...) = 0
brk(NULL) = 0x5610a8c3b000
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
...
附加到运行中的进程
bash
# 获取进程 PID
pgrep nginx
# 例如:1234
# 附加追踪
strace -p 1234
过滤特定类别的系统调用
bash
# 只追踪网络相关系统调用
strace -e trace=network nginx
# 只追踪文件 I/O
strace -e trace=open,read,write,close -p 1234
# 追踪进程与文件系统的交互
strace -e trace=file -p 1234
常用过滤类别:
network:socket、connect、send、recv 等file:open、read、write、stat 等process:fork、exec、exit 等memory:mmap、brk、munmap 等signal:kill、sigaction 等
实战一:诊断"文件未找到"错误
应用报告无法找到配置文件,但文件明明存在。使用 strace 追踪文件打开操作:
bash
strace -e trace=openat,stat -p $(pgrep my-app) 2>&1 | grep -E "(ENOENT|config)"
典型输出:
openat(AT_FDCWD, "/etc/my-app/config.yaml", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/app/.config/my-app.yaml", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/local/etc/my-app.yaml", O_RDONLY) = 5
从输出可以清晰看出:进程按顺序查找多个路径,前两个返回 ENOENT,第三个成功。如果三个都失败,就能知道应用实际在哪些路径寻找配置文件,而不是猜测。
实战二:调试网络连接超时
服务偶发性地无法连接数据库,使用 strace 分析网络行为:
bash
# -T 显示每次系统调用的耗时
strace -T -e trace=network -p $(pgrep my-service) 2>&1 | grep -E "(connect|poll|select)"
输出:
connect(5, {sa_family=AF_INET, sin_port=htons(5432), sin_addr=inet_addr("10.0.0.5")}, 16) = -1 EINPROGRESS (Operation now in progress)
poll([{fd=5, events=POLLOUT|POLLERR}], 1, 5000) = 0 (Timeout) <5.000342>
poll 返回 0 (Timeout) 且耗时 5 秒,说明连接超时。结合 connect 显示的目标 IP 和端口,可以确认是否网络路由或防火墙问题。
实战三:统计系统调用热点
分析某个进程在 30 秒内最频繁调用的系统调用:
bash
# -c 统计系统调用次数,-p 附加进程
timeout 30 strace -c -p $(pgrep nginx) 2>&1
输出:
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
45.23 0.234567 5 46914 epoll_wait
25.11 0.130234 4 32558 156 read
18.45 0.095672 3 31891 write
8.32 0.043156 12 3596 sendfile
...
epoll_wait 占 45% 的时间是正常的(Nginx 事件循环),但如果 futex(锁等待)或 nanosleep(主动等待)占比过高,则说明程序存在竞争或轮询问题。
perf 基础:硬件性能计数器
perf stat:分析 CPU 效率
bash
# 分析运行命令的性能计数器
perf stat ls /tmp
# 附加到运行中的进程(收集 10 秒)
perf stat -p $(pgrep nginx) sleep 10
输出:
Performance counter stats for process id '1234':
10,234.56 msec task-clock # 1.000 CPUs utilized
45 context-switches # 4.398 /sec
8 cpu-migrations # 0.781 /sec
234 page-faults # 22.863 /sec
28,456,789,012 cycles # 2.781 GHz
18,234,567,890 instructions # 0.64 insn per cycle
456,789,012 branches # 44.635 M/sec
12,345,678 branch-misses # 2.70% of all branches
关键指标解读:
- insn per cycle(IPC):每时钟周期执行的指令数。低于 1.0 说明存在大量等待(缓存缺失、分支预测失败等)
- branch-misses:分支预测失误率,超过 5% 需要关注
- cache-misses :添加
-e cache-references,cache-misses查看缓存命中率
perf top:实时 CPU 热点
bash
# 查看全系统的 CPU 热点函数(类似 htop 但到函数级别)
perf top
# 只关注特定进程
perf top -p $(pgrep nginx)
输出类似:
Samples: 50K of event 'cpu-cycles', 4000 Hz, Event count
Overhead Shared Object Symbol
18.23% nginx [.] ngx_http_process_request
12.45% libc-2.35.so [.] __memcpy_avx_unaligned
8.91% nginx [.] ngx_regex_exec
6.78% [kernel] [k] copy_user_generic_string
Overhead 列显示函数占总 CPU 时间的百分比,可快速定位性能热点函数。
实战四:perf record 生成调用图
perf top 只能看到单个函数,无法知道调用链。使用 perf record 录制带调用图的性能数据:
bash
# 录制 30 秒的调用图(-g 启用 call graph)
perf record -g -p $(pgrep my-service) sleep 30
# 生成报告
perf report --call-graph=graph
交互式报告中可以展开调用链,查看函数的调用者和被调用者。
实战五:生成火焰图(Flame Graph)
火焰图由 Brendan Gregg 发明,是可视化 CPU 性能热点的最佳工具。X 轴表示 CPU 时间占比,Y 轴表示调用栈深度。
步骤一:安装 FlameGraph 工具
bash
git clone https://github.com/brendangregg/FlameGraph.git /opt/flamegraph
步骤二:录制性能数据
bash
# 录制 60 秒,采样频率 99Hz
perf record -F 99 -g -p $(pgrep my-service) sleep 60
步骤三:生成火焰图
bash
# 将 perf.data 转换为折叠格式
perf script | /opt/flamegraph/stackcollapse-perf.pl > out.folded
# 生成 SVG 火焰图
/opt/flamegraph/flamegraph.pl out.folded > flamegraph.svg
步骤四:下载并查看
bash
# 用 scp 下载到本地(在本地终端执行)
scp root@server-ip:/root/flamegraph.svg ~/Desktop/
# 用浏览器打开 SVG 文件,可以点击放大
解读火焰图
- 宽块:CPU 时间集中的函数,是优化重点
- 平顶:表示该函数本身消耗大量 CPU(非其调用的子函数)
- 高塔:深层调用栈,通常是递归或复杂库调用
- 颜色:随机分配,没有特别含义(红/黄不代表问题)
perf sched:分析调度延迟
系统响应延迟但 CPU 利用率不高?可能是调度延迟问题:
bash
# 录制调度事件
perf sched record sleep 10
# 生成延迟报告
perf sched latency
输出会显示各任务的最大调度延迟和平均延迟,帮助识别 RT 任务或 I/O 密集型任务导致的调度不公平问题。
strace 与 perf 的使用场景对比
| 场景 | 推荐工具 | 原因 |
|---|---|---|
| 文件找不到 | strace | 追踪 openat 系统调用 |
| 网络连接失败 | strace | 追踪 connect/poll 行为 |
| CPU 使用率高 | perf top + 火焰图 | 定位热点函数 |
| 响应延迟高但 CPU 不高 | strace -T + perf sched | 找出耗时的系统调用或调度延迟 |
| 缓存命中率低 | perf stat | 查看硬件缓存计数器 |
strace 和 perf 是每位 Linux 工程师必须掌握的核心工具。strace 让你看到进程与内核的每次对话,解决"为什么失败"的问题;perf 和火焰图让你看到 CPU 时间的分布,解决"为什么慢"的问题。两者结合,几乎没有无法排查的性能问题。