Linux 诊断利器 strace:解析系统调用,定位进程瓶颈与故障
在 Linux 系统的运维 & 测试与故障排查中,我们常常需要一个能透视程序行为的“翻译官”。strace 正是这样一款强大的诊断和调试工具,它通过追踪进程执行期间的系统调用与信号,为开发者、运维工程师提供了洞察应用程序与操作系统内核交互的窗口,是分析性能瓶颈、调试程序异常和网络问题的利器。
什么是 strace?
strace 的核心功能是跟踪系统调用。系统调用是应用程序请求内核服务的唯一方式,例如打开文件、读写数据、申请内存、建立网络连接等。通过 strace,我们可以清晰地看到一个程序在运行时究竟调用了哪些内核服务,以及这些调用的参数、返回值和耗时,这对于理解程序行为和定位根因至关重要。
基本语法与常用选项
strace 的基本命令格式为:
strace [选项] 命令 [命令参数]
基础示例:追踪 ls 命令
执行 strace ls 可以查看 ls 命令在执行过程中发起的全部系统调用。以下是一个简化的输出片段:
execve("/usr/bin/ls", ["ls"], 0x7ffcbefaef00 /* 22 vars */) = 0
brk(NULL) = 0x146d000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (没有那个文件或目录)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=21799, ...}) = 0
mmap(NULL, 21799, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f3e2344c000
close(3) = 0
open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\205\0\0\0\0\0\0"..., 832) = 832
...
openat(AT_FDCWD, "/", O_RDONLY|O_NONBLOCK|O_DIRECTORY) = 3
getdents(3, /* 3 entries */, 32768) = 96
getdents(3, /* 0 entries */, 32768) = 0
close(3) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_dev=makedev(136, 0), ...}) = 0
write(1, "1.txt txtbak20251221.tar.gz\n", 28) = 28
exit_group(0) = ?
从输出中我们可以解读几个关键的系统调用:
execve: 加载并执行 /usr/bin/ls 程序。
openat / getdents: 打开当前目录并读取目录项。
write: 将结果(文件列表)输出到标准输出(终端)。
close: 关闭文件描述符。
exit_group: 进程退出。
统计系统调用:-c 选项
如果你只关心调用频次和耗时统计,可以使用 -c 选项。它会运行命令并汇总所有系统调用的开销。
strace -c ls
执行后输出的统计表示例如下:
| % time |
seconds |
usecs/call |
calls |
errors |
syscall |
| 23.46 |
0.003464 |
123 |
28 |
|
mmap |
| 16.03 |
0.002367 |
131 |
18 |
|
mprotect |
| 12.43 |
0.001835 |
166 |
11 |
|
open |
| 11.40 |
0.001683 |
120 |
14 |
|
close |
| 10.36 |
0.001529 |
152 |
10 |
|
read |
| ... |
... |
... |
... |
... |
... |
| 100.00 |
0.014763 |
118 |
118 |
|
total |
这张表清晰地展示了 ls 命令执行过程中,哪些系统调用占用了最多时间,为性能分析提供了量化依据。
附加到运行中的进程:-p 选项
对于已经在运行的服务或进程,无需重启,直接使用 -p 选项附加即可进行追踪。首先,我们可能需要用 lsof 或 ps 找到目标进程的 PID(进程 ID)。例如,查看谁在监听 SSH 端口:
# lsof -i:22
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 6883 root 3u IPv4 38234 0t0 TCP *:ssh (LISTEN)
sshd 7193 root 3u IPv4 39787 0t0 TCP localhost.localdomain:ssh->192.168.2.10:ep-nsP (ESTABLISHED)
找到 PID 后(例如 7193),使用 strace 附加:
strace -p 7193
输出会实时显示该进程正在进行的系统调用,如 select、read、write、clock_gettime 等。
核心功能选项详解
1. 输出重定向:-o 选项
追踪产生的日志量可能很大,将其保存到文件便于后续分析。
strace -o 1.txt -p 7193
此命令会将追踪 PID 为 7193 的进程的日志,持续写入到 1.txt 文件中。
2. 按调用类型过滤:-e trace= 选项
有时我们只关心特定类型的系统调用,比如只查看文件相关的操作。
# 只追踪 read 调用
strace -e read ls
# 只追踪文件相关调用
strace -e trace=file -p 7193
# 只追踪网络相关调用
strace -e trace=network -p 7193
例如,strace -e read ls 的输出会过滤掉其他调用,只显示 read 系统调用的详情,这对于分析程序读取了哪些文件非常有用。
3. 时间追踪选项
strace 提供了多个选项来分析每个系统调用的耗时,这对性能诊断至关重要。
-t: 在每行输出前加上时间(时分秒)。
strace -t ls
-tt: 在每行输出前加上更精确的时间(时分秒.微秒)。
strace -tt ls
# 输出示例
# 11:17:38.434466 execve("/usr/bin/ls", ["ls"], 0xfffc586ec588 /* 22 vars */) = 0
# 11:17:38.436638 brk(NULL) = 0xaf7000
-ttt: 使用时间戳(自纪元以来的秒数.微秒)。
-T: 在每行调用的末尾显示本次调用花费的时间。
strace -T ls
# 输出示例
# execve("/usr/bin/ls", ["ls"], 0x7ffdd87a698 /* 22 vars */) = 0 <0.000338>
# brk(NULL) = 0x158e000 <0.000020>
4. 追踪子进程:-f 选项
默认情况下,strace 只追踪指定的主进程。如果目标进程会 fork() 出子进程,并且你也需要追踪子进程的行为,就需要加上 -f 选项。
strace -f -o log.log -p 7193
实战场景应用
掌握了基本用法后,我们来看 strace 在真实运维/DevOps/SRE场景中如何解决具体问题。
场景一:进程卡死或无响应
- 保存完整调用日志:将卡死进程的所有调用保存下来,留作深入分析。
strace -o trace.log -p <PID>
- 定位耗时瓶颈:使用
-T 选项直接查看每个系统调用的耗时,快速定位是哪个环节(如read/write/connect)消耗了异常多的时间。
strace -T -p <PID>
- 分析程序启动慢:对启动缓慢的程序,可以用以下命令组合找出启动过程中最耗时的几个调用。
strace -T -tt -o app_start.log ./myapp
grep “<[0-9]\.“ app_start.log | sort -t ‘<’ -k2 -nr | head -5
场景二:文件找不到或权限拒绝
- 追踪文件操作:当程序报错“No such file or directory”或“Permission denied”时,使用
trace=file 或 trace=access 进行过滤。
strace -e trace=file ./myapp 2>&1 | grep -E “ENOENT|EACCES”
strace -e trace=access -p <PID>
ENOENT 错误通常意味着文件不存在,EACCES 错误则意味着权限不足。
场景三:网络连接失败
- 追踪网络调用:当进程网络连接异常时,可以只追踪网络相关的系统调用(如
socket, connect, sendto, recvfrom)。
strace -T -e trace=network -p <PID>
- 分析具体请求:也可以用它来分析一个具体的网络客户端命令,例如
curl。
strace -e trace=network curl www.baidu.com
输出会显示 socket 创建、connect 连接、sendto 发送 HTTP 请求、recvfrom 接收响应等完整过程。
场景四:分析资源占用过高
当某个进程 CPU 或 I/O 占用异常时,可以使用统计模式 -c 并结合时间选项,分析是哪些系统调用导致了高负载。
strace -c -p <PID>
# 或者,附加一段时间后按 Ctrl+C 中断,会输出统计报表
报表会清晰地列出调用次数和总耗时排名,帮助我们定位资源消耗点。
注意事项
strace 虽然强大,但它通过 ptrace 系统调用工作,会给被追踪的进程带来显著性能开销,并可能改变其时序行为。因此:
- 避免长时间在生产环境使用:仅在短时间内用于故障诊断。
- 谨慎附加到关键业务进程:可能会影响服务响应。
- 输出可能非常冗长:记得使用
-o 选项将输出重定向到文件,并使用过滤选项 (-e) 来聚焦问题。
通过将 strace 融入你的诊断工具箱,你就能像拥有“X光透视”能力一样,深入理解 Linux 上任何“行为异常”进程的内在逻辑,高效地解决从性能瓶颈到神秘崩溃的各类难题。更多深入的系统和网络知识,可以在 yunpan.plus 的技术社区中交流探讨。
参考资料
[1] linux中系统调用的核心工具strace, 微信公众号:https://mp.weixin.qq.com/s/b92mj4SFfGkfNGd4-KQlag
版权声明:本文由 云栈社区 整理发布,版权归原作者所有。