当前位置:首页>Linux>Linux 排障神器:strace命令使用指南

Linux 排障神器:strace命令使用指南

  • 2026-10-11 06:10:12
Linux 排障神器:strace命令使用指南
程序运行慢?找不到配置文件?网络连不上?别猜了,用 strace 看看它到底在干什么——一追便知。

作为 Linux 运维工程师,你一定遇到过这样的场景:

  • 程序启动失败,日志里只有一句 segmentation fault
  • 服务响应变慢,但 CPU 和内存都正常
  • 程序明明应该读取某个配置文件,却报 "No such file or directory"
  • 线上进程莫名卡住,strace 一看,卡在了某个锁上

面对这些「黑盒」问题,strace 就是你透视程序行为的X光机。它能实时追踪程序发起的每一个系统调用,让你看到程序「到底在和内核聊什么」。

今天这篇文章,我们从底层原理到实战案例,彻底搞懂 strace。

✦ ✦ ✦

一、先搞清楚:什么是「系统调用」?

要理解 strace,首先要理解系统调用(System Call)。

Linux 的设计哲学是:用户程序不能直接访问硬件资源。所有的文件读写、网络通信、进程管理等操作,都必须通过内核来完成。用户程序向内核发起请求的这个「接口」,就是系统调用。

类比:
你可以把内核想象成银行柜台,系统调用就是你递给柜员的「业务单」。你不能直接进柜台操作,必须通过窗口提交请求。strace 就是一个「监控摄像头」,把每一张业务单都拍下来给你看。

常见的系统调用包括:

分类
常见系统调用
作用
文件操作
open, read, write, close, stat
文件的打开、读取、写入、关闭、状态查询
网络通信
socket, connect, sendto, recvfrom, bind, listen, accept
建立连接、收发数据
进程管理
fork, execve, exit, wait4, kill
创建/终止进程
内存管理
mmap, brk, munmap, mprotect
内存分配、映射、保护
设备I/O
ioctl, poll, select, epoll
设备控制、I/O多路复用

Linux 内核的系统调用号定义在 arch/x86/entry/syscalls/syscall_64.tbl(x86_64 架构),目前已有 400+ 个系统调用。

二、strace 是什么?为什么能「看到」系统调用?

strace 是一个用户态调试工具,它能跟踪一个进程执行时产生的系统调用,以及进程接收到的信号。

那么问题来了:strace 是怎么做到的?

核心武器:ptrace 系统调用

strace 的底层依赖一个更底层的系统调用——ptrace(Process Trace)。它是 Linux 内核提供给调试器(如 gdb、strace)的「官方后门」。

ptrace 的核心能力:✅ 访问另一个进程的内存空间✅ 读取/修改寄存器状态✅ 控制目标进程的执行(暂停、单步、继续)✅ 在系统调用入口和出口处获得通知

strace 的工作流程

strace 利用 ptrace 完成了一套精密的「夹心饼干」操作:

┌─────────────────────────────────────────────┐│            strace 的追踪流程                  │├─────────────────────────────────────────────┤│                                             ││  ① ptrace(PTRACE_TRACEME, child)           ││     子进程主动请求被追踪                      ││                     ↓                       ││  ② 执行 execve()(系统调用入口)              ││     内核触发 SIGTRAP → strace 收到信号        ││                     ↓                       ││  ③ strace 读取寄存器,获取系统调用号和参数     ││     查询 syscall_64.tbl → 得到调用名          ││                     ↓                       ││  ④ ptrace(PTRACE_SYSCALL) → 让进程继续执行   ││                     ↓                       ││  ⑤ 系统调用返回,再次触发 SIGTRAP             ││     strace 读取返回值,打印一行日志           ││                     ↓                       ││  ⑥ 重复 ④⑤,直到进程退出                     ││                                             │└─────────────────────────────────────────────┘

用一句话总结:strace = ptrace + 系统调用号翻译表。每次系统调用的「进」和「出」都会触发信号,strace 在信号处理函数中读取寄存器信息,翻译成人类可读的格式输出。

一张图看懂用户态与内核态的关系

┌─────────────────────────────────────────────────┐│                 用户空间                         ││                                                 ││   ┌──────────┐          ┌──────────┐            ││   │  目标程序  │          │  strace  │            ││   └────┬─────┘          └────┬─────┘            ││        │                      │                 ││  ┌─────┴─────┐          ptrace│                 ││  │  libc库    │          系统调用│                 ││  └─────┬─────┘                │                 │├────────┼──────────────────────┼─────────────────┤│   ═════╪══════════════════════╪══════ 系统调用界面│├────────┼──────────────────────┼─────────────────┤│                 内核空间                         ││        ↓                      │                 ││   ┌────┴─────┐                │                 ││   │ 系统调用表 │←───────────────┘                 ││   │ sys_read  │                                 ││   │ sys_write │  ...                             ││   └──────────┘                                  ││        ↓                                        ││   ┌──────────┐                                  ││   │ 硬件资源  │                                  ││   └──────────┘                                  │└─────────────────────────────────────────────────┘

三、strace 常用参数速查

strace 的参数很多,但掌握了这几个常用的,就能覆盖 80% 的场景:

参数
说明
使用场景
-e trace=xxx
过滤特定类型的系统调用
只看文件操作 / 网络连接
-p PID
附加到已运行的进程
调试线上服务
-f
跟踪子进程
程序 fork 了子进程
-t / -tt / -ttt
显示时间戳(秒/微秒/Unix时间戳)
分析耗时
-o file
输出到文件
日志量大时避免刷屏
-c
统计汇总
快速看哪类调用最频繁/最慢
-s N
设置字符串截断长度
需要看完整路径/数据时
-T
显示每个调用的耗时
定位慢系统调用
-e read=fd
显示读操作的完整内容
分析网络/管道数据
-e write=fd
显示写操作的完整内容
分析程序输出

💡 参数组合技:-e trace=network -tt -T = 追踪网络调用 + 显示微秒时间戳 + 显示耗时-e trace=file -s 500 = 追踪文件操作 + 显示最多 500 字符-p PID -e signal=none = 附加进程 + 过滤掉信号只看系统调用

四、实战案例:5 个场景让你上手即用

案例 1:程序启动失败——到底在读哪个配置文件?

程序报错 configuration file not found,但你确定文件存在。用 strace 追踪一下:

strace -e trace=open,openat,stat,access ./myapp 2>&1 | grep -i conf

输出:

openat(AT_FDCWD, "/etc/myapp/config.yml", O_RDONLY) = -1 ENOENT (No such file or directory)openat(AT_FDCWD, "/usr/local/etc/myapp/config.yml", O_RDONLY) = -1 ENOENT (No such file or directory)openat(AT_FDCWD, "/home/app/config.yml", O_RDONLY) = 3    ← 成功读到了!

原来程序会按优先级依次查找 3 个路径。虽然你在 /etc 下放了配置文件,但程序真正读的是 /home/app/。一目了然。

案例 2:程序卡住了——到底阻塞在哪?

线上进程突然不响应,CPU 使用率极低,用 strace 附加看一下:

strace -p 12345 -e trace=all -T

输出:

futex(0x7f8b2c001234, FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, 0, NULL, NULL, 0, FUTEX_BITSET_MATCH_ANY) = 0 <35.892341>

一眼看出:进程卡在了 futex(快速用户互斥锁)上,等待了 35 秒!这说明程序在等待某个锁,很可能是死锁或锁竞争激烈。

案例 3:程序运行慢——时间花在哪了?

用 -c 统计汇总,快速定位瓶颈:

strace -c ./slow-query.sh

输出:

% time     seconds  usecs/call     calls    errors syscall------ ----------- ----------- --------- --------- -------- 68.32    2.150000       53750        40           read 15.78    0.497000          49     10143           epoll_wait  8.45    0.266000          53      5000           write  4.12    0.130000          13     10000           close  1.23    0.039000          39      1000           openat  ...

真相大白:68% 的时间花在了 read 上,且每次 read 平均耗时 53ms。说明是网络读取慢,而不是程序本身逻辑慢。配合 -tt -T 可以进一步定位到具体哪个 fd 读取慢。

案例 4:DNS 解析异常——到底在查什么域名?

strace -e trace=connect,sendto,recvfrom -s 500 -f curl https://api.example.com 2>&1 | grep -v ECONNREFUSED

从输出中可以清晰看到 curl 发起了哪些 DNS 查询、连接了哪个 IP,帮助排查 DNS 劫持或解析错误。

案例 5:权限问题——到底在访问哪个文件?

程序报 Permission denied,但你不知道它在访问什么文件:

strace -e trace=file -f ./myapp 2>&1 | grep -i denied

输出:

openat(AT_FDCWD, "/var/run/nginx.pid", O_WRONLY|O_CREAT|O_TRUNC, 0644) = -1 EACCES (Permission denied)

定位到具体文件和操作模式,修复权限即可。

五、进阶技巧:让 strace 更好用

1. 只看感兴趣的系统调用

# 只看文件操作strace -e trace=file ./myapp# 只看网络操作strace -e trace=network ./myapp# 只看进程管理strace -e trace=process ./myapp# 排除信号相关strace -e signal=none -p PID

2. 配合 grep 精准定位

# 找出所有打开失败的文件strace -e trace=openat -f ./myapp 2>&1 | grep -i "ENOENT\|EACCES"# 找出所有网络连接目标strace -e trace=connect -f ./myapp 2>&1 | grep "sockaddr"# 找出耗时超过 1 秒的系统调用strace -T -p PID 2>&1 | awk -F'<' '{if($2+0 > 1.0) print}'

3. 输出到文件后分析

# 输出到文件(避免刷屏)strace -o /tmp/trace.log -f -tt ./myapp# 分析:统计各系统调用次数awk '{print $NF}' /tmp/trace.log | sort | uniq -c | sort -rn | head -20

4. 追踪正在运行的进程(不重启)

# 找到目标进程pidof nginx# 附加 strace(不影响进程运行)strace -p $(pidof nginx | awk '{print $1}') -e trace=network -T -tt# 按 Ctrl+C 停止追踪,进程继续运行

⚠️ 线上使用注意:strace 会让被追踪进程变慢!ptrace 每次系统调用都会触发两次上下文切换(进入/退出),性能损耗大约 5-15%。生产环境建议:① 仅在排障时短时间使用② 优先用 -e 过滤,避免全量追踪③ 用 -o 输出到文件,避免大量输出影响性能④ 如果需要长期监控,考虑用 bpftrace 或 perf trace

六、strace vs ltrace:别搞混了

很多同学分不清 strace 和 ltrace,一张表说清楚:

对比项
strace
ltrace
追踪对象
系统调用
(内核接口)
库函数调用
(如 printf, malloc)
底层原理
ptrace + syscall 表
PLT/GOT 动态链接拦截
典型用途
排查文件/网络/权限问题
排查内存泄漏、库调用逻辑
开销
中等
较大(函数调用频繁)
使用频率
⭐⭐⭐⭐⭐ 运维必备
⭐⭐⭐ 开发调试偶尔用
一句话总结:
strace 看的是「程序怎么跟内核打交道」,ltrace 看的是「程序怎么调用库函数」。日常排障用 strace 更多。

七、strace 背后的哲学

Linux 的设计哲学中有一条:"Everything is a file"。文件、网络、设备、进程……一切资源都通过文件描述符来操作。而所有的文件操作,最终都收敛到那一组系统调用上。

这意味着:只要你能追踪系统调用,就能还原程序的完整行为轨迹。

这就是 strace 的强大之处——它不需要程序的源代码,不需要特殊的编译选项,不需要重新部署。只要能 attach 上去,程序的一切秘密都无所遁形。

✦ ✦ ✦

总结:strace 速记口诀

程序行为看不清,strace 一开全透明ptrace 是原理,信号打断来读取-e 过滤选类型,-p 附加到进程-c 统计看瓶颈,-T 耗时来分析线上慎用别贪心,短时精准是关键

下次遇到程序「不听话」的时候,别急着改代码,先 strace 看看它到底在干什么——也许答案就藏在那一行行系统调用日志里。

延伸阅读:

  • 《Linux 性能优化实战》—— 铁蕾 · 极客时间
  • Brendan Gregg BPF Performance Tools
  • man strace / man ptrace
最后提一句:
如果你想在生产环境做更轻量的系统调用追踪,可以关注 perf trace 和 bpftrace,它们基于 eBPF 实现,性能开销比 strace 小得多,但使用门槛也更高。strace 是入门,也是日常利器;eBPF 是进阶,是性能分析的未来。

— END —

👆 觉得有用?点个「在看」让更多人看到 👇

关注「运维之美」获取更多技术干货

最新文章

随机文章