3. strace 实战:追踪特定进程的系统调用、统计系统调用次数与耗时(-c)、过滤特定系统调用(-e)

strace 是 Linux 系统调用级性能分析的起点。它能够拦截并记录目标进程发起的每一次系统调用,包括调用名称、参数、返回值以及执行耗时。本章将围绕三个核心实战场景展开:追踪特定进程、统计系统调用次数与耗时、过滤特定系统调用。

实战前提:确保目标系统已安装 strace(通常位于 strace 包中)。若未安装,可使用 sudo apt install strace(Debian/Ubuntu)或 sudo yum install strace(RHEL/CentOS)快速安装。

3.1 追踪特定进程的系统调用

strace 支持两种方式追踪特定进程:附加到正在运行的进程(-p)和启动并追踪新进程(直接后跟命令)。

方式 命令示例 适用场景
附加到运行中进程 strace -p <PID> 追踪已启动的服务(如 nginx、mysqld)
启动并追踪新进程 strace <command> 追踪一次性命令或脚本
追踪多线程进程 strace -f -p <PID> 追踪所有子线程和子进程
关键参数:-f 跟踪由 fork/vfork/clone 创建的子进程;-ff 将每个进程的输出分离到独立文件(需配合 -o 指定输出前缀)。

以下 SVG 展示了 strace 附加到运行中进程的数据流:

strace -p 追踪运行中进程 strace 进程 (用户态) 目标进程 (PID) (用户态) Linux 内核 (系统调用处理 + ptrace 拦截) strace 通过 ptrace 系统调用附加到目标进程,拦截所有系统调用入口和返回

3.1.1 实战:追踪 nginx worker 进程

# 查找 nginx worker 进程 PID
$ ps aux | grep 'nginx: worker'
www-data  12345  0.0  0.1   ...   nginx: worker process

# 附加追踪,输出到文件
$ sudo strace -p 12345 -o /tmp/nginx_strace.log

# 若 nginx 使用多进程,追踪所有 worker
$ sudo strace -f -p $(pgrep -d',' -f 'nginx: worker') -o /tmp/nginx_all_workers.log
注意:使用 -p 附加到运行中进程需要 root 权限或与目标进程相同的用户权限。追踪生产环境服务时,建议先使用 -c 统计模式评估开销,再决定是否开启详细追踪。

3.2 统计系统调用次数与耗时(-c)

-c 参数是 strace 性能分析的核心开关。它不会逐行打印每次系统调用,而是在程序退出或用户中断时,汇总输出一份统计报告,包含每个系统调用的次数、总耗时、平均耗时、错误次数等信息。

统计列 含义 性能分析价值
% time 该系统调用耗时占总耗时的百分比 快速定位最耗时的系统调用
seconds 该系统调用累计耗时(秒) 量化性能瓶颈的绝对时间
usecs/call 每次调用的平均耗时(微秒) 判断单次调用是否异常
calls 调用次数 识别高频调用路径
errors 返回错误的次数 发现异常或资源耗尽问题

3.2.1 实战:统计 ls 命令的系统调用

$ strace -c ls /tmp
... (ls 正常输出) ...

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 35.21    0.000412          68         6           getdents64
 22.65    0.000265          44         6           newfstatat
 18.80    0.000220          36         6           write
  8.55    0.000100          50         2           openat
  5.98    0.000070          35         2           close
  4.27    0.000050          25         2           mmap
  2.56    0.000030          15         2           munmap
  1.71    0.000020          20         1           brk
  0.27    0.000003           3         1           read
------ ----------- ----------- --------- --------- ----------------
100.00    0.001170                    28           total

从统计结果可以清晰看到:getdents64(读取目录项)耗时占比最高(35.21%),newfstatat(获取文件状态)紧随其后。对于 ls 这种目录遍历命令,这两个系统调用是核心瓶颈。

性能分析技巧:当 usecs/call 值异常偏高时(例如 read 平均耗时超过 1000 微秒),通常意味着磁盘 I/O 延迟或锁竞争。此时应结合 perf 进一步采样内核事件。

以下 SVG 展示了 -c 统计模式的数据处理流程:

strace -c 统计模式工作流程 拦截系统调用 ptrace 捕获入口/出口 记录时间戳 入口 T1 / 出口 T2 累加统计 次数 + 耗时 + 错误 程序退出 / Ctrl+C 触发 输出汇总统计表 输出示例(部分) syscall calls errors usecs/call getdents64 6 0 68 newfstatat 6 0 44 write 6 0 36

3.3 过滤特定系统调用(-e)

当系统调用数量庞大时(例如数据库服务每秒数万次调用),全量追踪会产生海量数据,干扰分析。strace 的 -e 参数允许按系统调用名称、系统调用类别或文件描述符进行过滤。

过滤方式 语法 示例
按名称包含 -e trace=<syscall> -e trace=read,write
按名称排除 -e trace=!<syscall> -e trace=!futex
按类别过滤 -e trace=<category> -e trace=file(文件相关)
按文件描述符 -e read=<fd> -e read=3(仅追踪 fd=3 的读取)

3.4.1 常用系统调用类别

类别名 包含的系统调用 分析场景
file open, close, read, write, stat, unlink 等 文件 I/O 性能分析
process fork, execve, wait, exit 等 进程创建与销毁分析
network socket, connect, send, recv, accept 等 网络 I/O 性能分析
ipc shmget, semop, msgrcv 等 进程间通信分析
desc 所有与文件描述符相关的系统调用 文件描述符泄漏排查

3.4.2 实战:过滤 MySQL 的磁盘 I/O 系统调用

# 仅追踪 MySQL 的 read/write/pwrite/pread 系统调用
$ sudo strace -p $(pidof mysqld) -e trace=read,write,pwrite64,pread64 -o /tmp/mysql_io.log

# 排除 futex(锁相关),减少噪声
$ sudo strace -p $(pidof mysqld) -e trace=!futex -o /tmp/mysql_no_futex.log

# 按类别过滤:仅追踪网络相关系统调用
$ sudo strace -p $(pidof mysqld) -e trace=network -o /tmp/mysql_network.log
组合使用:-e 可以与 -c 联合使用,实现“只统计特定系统调用的性能数据”。例如:strace -c -e trace=read,write -p <PID> 将只统计 read 和 write 的调用次数与耗时。

以下 SVG 展示了 -e 过滤机制在 strace 内部的处理逻辑:

strace -e 过滤机制 所有系统调用 ptrace 捕获原始事件 过滤引擎 匹配 -e trace= 规则 / 排除 ! 规则 匹配 → 记录输出 写入日志 / 统计累加 不匹配 → 丢弃 不记录,减少开销 合理使用 -e 过滤可降低 strace 自身开销 50%~90%,减少分析噪声

3.4 实战组合:过滤 + 统计 + 输出到文件

将 -e、-c 和 -o 组合使用,可以实现低开销、高精度的系统调用级性能分析:

# 组合示例:仅统计文件 I/O 系统调用,输出到文件
$ sudo strace -c -e trace=file -p $(pidof mysqld) -o /tmp/mysql_file_stat.log

# 组合示例:排除 futex,统计所有其他系统调用
$ sudo strace -c -e trace=!futex -p $(pidof mysqld) -o /tmp/mysql_no_futex_stat.log

# 组合示例:仅追踪 read/write,并输出详细日志
$ sudo strace -e trace=read,write -p $(pidof mysqld) -o /tmp/mysql_rw_detail.log
性能分析工作流建议:
  1. 先使用 -c -e trace=!futex 快速获取全局统计,识别热点系统调用。
  2. 针对热点系统调用(如 read、write、poll),使用 -e trace=<hot_syscall> 输出详细日志。
  3. 结合 perf 对热点系统调用的内核路径进行采样,定位具体瓶颈函数。

3.5 常见问题与避坑

问题 原因 解决方案
strace 输出为空 目标进程已退出或权限不足 使用 sudo;确认 PID 存在
strace 导致目标进程变慢 ptrace 拦截引入巨大开销 使用 -c 统计模式;使用 -e 过滤;减少追踪时间
输出文件过大 未使用过滤,全量追踪 使用 -e 限制范围;使用 -c 替代详细输出
多线程进程追踪混乱 未使用 -f 参数 添加 -f 追踪所有线程;使用 -ff 分离输出
生产环境警告:strace 的 ptrace 机制会大幅降低目标进程性能(通常 10x~100x 减速)。在生产服务器上,建议仅在低峰期使用 -c 统计模式,且追踪时间不超过 30 秒。如需长时间追踪,优先考虑 perf trace 或 eBPF 方案。

通过本章实战,你已经掌握了 strace 的三个核心能力:追踪特定进程、统计系统调用次数与耗时、过滤特定系统调用。这些技能是后续与 perf 联用进行深度性能分析的基础。