strace 可以解决什么问题?
| 2021-04-05 09:48:36 评论: 0
昨天我 在 Twitter 上询问大家用 strace 解决了什么问题?,和往常一样,大家真的是给出了自己的答案! 我收到了大约 200 个答案,然后花了很多时间手动将它们归为 9 类。
这些解决的问题都是关于寻找程序依赖的文件、找出程序卡住或慢的原因、或者找出程序失败的原因。这些总体上与我自己使用 strace
的内容相吻合,但也有一些我没有想到的东西!
我不打算在这篇文章里解释什么是 strace
,但我有一本 关于它的免费杂志 和 一个讲座 以及 很多博文。
问题 1:配置文件在哪里?
最受欢迎的问题是“这个程序有一个配置文件,但我不知道它在哪里”。这可能也是我最常使用 strace
解决的问题,因为这是个很简单的问题。
这很好,因为一个程序有一百万种方法来记录它的配置文件在哪里(在手册页、网站上、--help
等),但只有一种方法可以让它真正打开它(用系统调用!)。
问题 2:这个程序还依赖什么文件?
你也可以使用 strace
来查找程序依赖的其他类型的文件,比如:
- 动态链接库(“为什么我的程序加载了这个错误版本的
.so
文件?"),比如 我在 2014 年调试的这个 ruby 问题 - 它在哪里寻找它的 Ruby gem(Ruby 出现了几次这种情况!)
- SSL 根证书
- 游戏的存档文件
- 一个闭源程序的数据文件
- 哪些 node_modules 文件没有被使用
问题 3:为什么这个程序会挂掉?
你有一个程序,它只是坐在那里什么都不做,这是怎么回事?这个问题特别容易回答,因为很多时候你只需要运行 strace -p PID
,看看当前运行的是什么系统调用。你甚至不需要看几百行的输出。
答案通常是“正在等待某种 I/O”。“为什么会卡住”的一些可能的答案(虽然还有很多!):
- 它一直在轮询
select()
- 正在
wait()
等待一个子进程完成 - 它在向某个没有响应的东西发出网络请求
- 正在进行
write()
,但由于缓冲区已满而被阻止。 - 它在 stdin 上做
read()
,等待输入。
有人还举了一个很好的例子,用 strace
调试一个卡住的 df
命令:“用 strace df -h
你可以找到卡住的挂载,然后卸载它”。
问题 4:这个程序卡住了吗?
这是上一个问题的变种:有时一个程序运行的时间比你预期的要长,你只是想知道它是否卡住了,或者它是否还在继续进行。
只要程序在运行过程中进行系统调用,用 strace
就可以超简单地回答这个问题:只需 strace
它,看看它是否在进行新的系统调用!
问题 5:为什么这个程序很慢?
你可以使用 strace
作为一种粗略的剖析工具:strace -t
会显示每次系统调用的时间戳,这样你就可以寻找大的漏洞,找到罪魁祸首。
以下是 Twitter 上 9 个人使用 strace
调试“为什么这个程序很慢?”的小故事。
- 早在 2000 年,我帮助支持的一个基于 Java 的网站在适度的负载下奄奄一息:页面加载缓慢,甚至完全加载不出来。我们对 J2EE 应用服务器进行了测试,发现它每次只读取一个类文件。开发人员没有使用 BufferedReader,这是典型的 Java 错误。
- 优化应用程序的启动时间……运行
strace
可以让人大开眼界,因为有大量不必要的文件系统交互在进行(例如,在同一个配置文件上反复打开/读取/关闭;在一个缓慢的 NFS 挂载上加载大量的字体文件,等等)。 - 问自己为什么在 PHP 中从会话文件中读取(通常是小于 100 字节)非常慢。结果发现一些
flock
系统调用花了大约 60 秒。 - 一个程序表现得异常缓慢。使用
strace
找出它在每次请求时,通过从/dev/random
读取数据并耗尽熵来重新初始化其内部伪随机数发生器。 - 我记得最近一件事是连接到一个任务处理程序,看到它有多少网络调用(这是意想不到的)。
strace
显示它打开/读取同一个配置文件数千次。- 服务器随机使用 100% 的 CPU 时间,实际流量很低。原来是碰到打开文件数限制,接受一个套接字时,得到 EMFILE 错误而没有报告,然后一直重试。
- 一个工作流运行超慢,但是没有日志,结果它做一个 POST 请求花了 30 秒而超时,然后重试了 5 次……结果后台服务不堪重负,但是也没有可视性。
- 使用
strace
注意到gethostbyname()
需要很长时间才能返回(你不能直接看到gethostbyname
,但你可以看到strace
中的 DNS 数据包)
问题 6:隐藏的权限错误
有时候程序因为一个神秘的原因而失败,但问题只是有一些它没有权限打开的文件。在理想的世界里,程序会报告这些错误(“Error opening file /dev/whatever: permission denied”),当然这个世界并不完美,所以 strace
真的可以帮助解决这个问题!
这其实是我最近使用 strace
做的事情。我使用了一台 AxiDraw 绘图仪,当我试图启动它时,它打印出了一个难以理解的错误信息。我 strace
它,结果发现我的用户没有权限打开 USB 设备。
问题 7:正在使用什么命令行参数?
有时候,一个脚本正在运行另一个程序,你想知道它传递的是什么命令行标志!
几个来自 Twitter 的例子。
- 找出实际上是用来编译代码的编译器标志
- 由于命令行太长,命令失败了
问题 8:为什么这个网络连接失败?
基本上,这里的目标是找到网络连接的域名 / IP 地址。你可以通过 DNS 请求来查找域名,或者通过 connect
系统调用来查找 IP。
一般来说,当 tcpdump
因为某些原因不能使用或者只是因为比较熟悉 strace
时,就经常会使用 strace
调试网络问题。
问题 9:为什么这个程序以一种方式运行时成功,以另一种方式运行时失败?
例如:
- 同样的二进制程序在一台机器上可以运行,在另一台机器上却失败了
- 可以运行,但被 systemd 单元文件生成时失败
- 可以运行,但以
su - user /some/script
的方式运行时失败 - 可以运行,作为 cron 作业运行时失败
能够比较两种情况下的 strace
输出是非常有用的。虽然我在调试“以我的用户身份工作,而在同一台计算机上以不同方式运行时却失败了”时,第一步是“看看我的环境变量”。
我在做什么:慢慢地建立一些挑战
我之所以会想到这个问题,是因为我一直在慢慢地进行一些挑战,以帮助人们练习使用 strace
和其他命令行工具。我的想法是,给你一个问题,一个终端,你可以自由地以任何方式解决它。
所以我的目标是用它来建立一些你可以用 strace
解决的练习题,这些练习题反映了人们在现实生活中实际使用它解决的问题。
就是这样!
可能还有更多的问题可以用 strace
解决,我在这里还没有讲到,我很乐意听到我错过了什么!
我真的很喜欢看到很多相同的用法一次又一次地出现:至少有 20 个不同的人回答说他们使用 strace
来查找配置文件。而且和以往一样,我觉得这样一个简单的工具(“跟踪系统调用!”)可以用来解决这么多不同类型的问题,真的很令人高兴。