strace 和 perf:Linux 进程调试和性能分析深度指南

strace 和 perf:Linux 进程调试和性能分析深度指南

当线上服务出现莫名的性能下降、神秘的"文件未找到"错误或奇怪的网络超时,常规的日志分析往往无法给出答案。这时候需要深入内核层面,观察进程的真实行为。

straceperf 是 Linux 系统性能诊断的两把利刃:strace 追踪进程的系统调用,揭示进程与内核的每次交互;perf 是 Linux 内核内置的性能分析器,能够捕获 CPU 级别的性能事件,生成直观的火焰图。掌握这两个工具,能够解决 80% 以上的难以排查的线上问题。

服务器配置

straceperf 是通用的 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 查看硬件缓存计数器

straceperf 是每位 Linux 工程师必须掌握的核心工具。strace 让你看到进程与内核的每次对话,解决"为什么失败"的问题;perf 和火焰图让你看到 CPU 时间的分布,解决"为什么慢"的问题。两者结合,几乎没有无法排查的性能问题。

相关推荐
AlfredZhao1 小时前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao16 小时前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户30745969820718 小时前
PHP 扩展——从入门到理解
php
用户9718356334661 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪1 天前
linux 拷贝文件或目录到指定的位置
linux
鹏仔先生1 天前
拷贝漫画APP下载页PHP程序,后台带免费AI写作
php
大树882 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质2 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush42 天前
嵌入式linux学习记录十四、术语
linux·嵌入式