用strace排查故障的5种简单方法(每日一译)
原文链接:5 simple ways to troubleshoot using Strace
我很意外大部分人都不知道如何使用strace。strace一直是我的首选debug工具,因为它非常的有效,很多问题都能够用它进行排查。
strace是什么?
Strace是一个用来跟踪系统调用的简易工具。它最简单的用途就是跟踪一个程序整个生命周期里所有的系统调用,并把调用参数和返回值以文本的方式输出。
当然它还可以做更多的事情:
strace可以过筛选出特定的系统调用。
strace可以记录系统调用的次数,时间,成功和失败的次数。
strace可以跟踪发给进程的信号。
strace可以通过pid附加到任何正在运行的进程上。
strace类似其他Unix系统上的truss,或者Sun's Dtrace
使用教程
以下这些只是些皮毛的用法:
1)查看初始化时程序读取的配置文件
你是否遇到过程序去错误的位置读取配置文件的情况?
简单的排查方式:
$ strace php 2>&1 | grep php.ini
open("/usr/local/bin/php.ini", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/local/lib/php.ini", O_RDONLY) = 4
lstat64("/usr/local/lib/php.ini", {st_mode=S_IFLNK|0777, st_size=27, ...}) = 0
readlink("/usr/local/lib/php.ini", "/usr/local/Zend/etc/php.ini", 4096) = 27
lstat64("/usr/local/Zend/etc/php.ini", {st_mode=S_IFREG|0664, st_size=40971, ...}) = 0
So this version of PHP reads php.ini from /usr/local/lib/php.ini (but it tries /usr/local/bin first).
如果只关心特定的系统调用可以使用以下略微复杂的使用方法:
$ strace -e open php 2>&1 | grep php.ini
open("/usr/local/bin/php.ini", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/local/lib/php.ini", O_RDONLY) = 4
如果安装多个版本的程序库,想搞清楚自己的程序加载的是哪个也可以如法炮制~。
2)为什么程序打不开这个文件?
是否有遇到过读取文件的时候被拒绝呢,你可以试试下面的命令:
$ strace -e open,access 2>&1 | grep your-filename
查看open()和access()系统调用是否有异常
3)进程现在在做啥?
是否有遇到过进程突然cpu占用率很高?又或者进程莫名其妙被挂起的情况?
找到这个进程的pid,然后执行下列命令:
root@dev:~# strace -p 15427
Process 15427 attached - interrupt to quit
futex(0x402f4900, FUTEX_WAIT, 2, NULL
Process 15427 detached
在这个示例里进程在调用futex的时候被挂起了。顺带一说,在这个例子里调用futex挂起可能有很多的原因(Futex是Linux的一种线程同步原语)。上述场景是个正常工作等待处理请求的apache子进程。
“strace -p”可以让你省去很多猜测,不需要重新编译,重启应用打log就能够找到问题。
4)统计程序的调用时间
要对程序进行性能分析往往需要重新编译程序,并打开跟踪选项。用strace可以很容易的附加到进程上查看实时的时间消耗。
如下:
root@dev:~# strace -c -p 11084
Process 11084 attached - interrupt to quit
Process 11084 detached
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
94.59 0.001014 48 21 select
2.89 0.000031 1 21 getppid
2.52 0.000027 1 21 time
------ ----------- ----------- --------- --------- ----------------
100.00 0.001072 63 total
root@dev:~#
启用strace -c -p命令后,在你按ctrl-c退出前程序的调用时间将会打印出来。
在上面的例子里。空闲的Postgres进程大部分时间都在安静的等待select()返回。在每个select()调用中调用getppid() 和time()。这是个标准的event loop方式。
也可以跟踪一次程序的开始和结束,比如下面的“ls”例子
root@dev:~# strace -c >/dev/null ls
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
23.62 0.000205 103 2 getdents64
18.78 0.000163 15 11 1 open
15.09 0.000131 19 7 read
12.79 0.000111 7 16 old_mmap
7.03 0.000061 6 11 close
4.84 0.000042 11 4 munmap
4.84 0.000042 11 4 mmap2
4.03 0.000035 6 6 6 access
3.80 0.000033 3 11 fstat64
1.38 0.000012 3 4 brk
0.92 0.000008 3 3 3 ioctl
0.69 0.000006 6 1 uname
0.58 0.000005 5 1 set_thread_area
0.35 0.000003 3 1 write
0.35 0.000003 3 1 rt_sigaction
0.35 0.000003 3 1 fcntl64
0.23 0.000002 2 1 getrlimit
0.23 0.000002 2 1 set_tid_address
0.12 0.000001 1 1 rt_sigprocmask
------ ----------- ----------- --------- --------- ----------------
100.00 0.000868 87 10 total
如你所料,这个命令花费两个调用用于读取目录实体。
5)为什么连不上服务器?
调试某些进程为什么连不上远程的服务器是个很让人头疼的事情。DNS可能挂了,连接可能断了,服务器可能返回什么无法识别的东西。。。你可以使用tcpdump去分析这些问题,tcpdump是个很棒的工具,但是很多情况下,strace可以给你提供更简洁的信息。如果你的程序里有很多进程连接到某台服务器,用tcpdump来处理就是很蛋疼的事情,因为你会看到太多的信息,没法抓到重点。
以下是一个跟踪“nc”命令连接到www.news.com的80端口的例子:
$ strace -e poll,select,connect,recvfrom,sendto nc www.news.com 80
sendto(3, "\\24\\0\\0\\0\\26\\0\\1\\3\\255\\373NH\\0\\0\\0\\0\\0\\0\\0\\0", 20, 0, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 20
connect(3, {sa_family=AF_FILE, path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
connect(3, {sa_family=AF_FILE, path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("62.30.112.39")}, 28) = 0
poll([{fd=3, events=POLLOUT, revents=POLLOUT}], 1, 0) = 1
sendto(3, "\\213\\321\\1\\0\\0\\1\\0\\0\\0\\0\\0\\0\\3www\\4news\\3com\\0\\0\\34\\0\\1", 30, MSG_NOSIGNAL, NULL, 0) = 30
poll([{fd=3, events=POLLIN, revents=POLLIN}], 1, 5000) = 1
recvfrom(3, "\\213\\321\\201\\200\\0\\1\\0\\1\\0\\1\\0\\0\\3www\\4news\\3com\\0\\0\\34\\0\\1\\300\\f"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("62.30.112.39")}, [16]) = 153
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("62.30.112.39")}, 28) = 0
poll([{fd=3, events=POLLOUT, revents=POLLOUT}], 1, 0) = 1
sendto(3, "k\\374\\1\\0\\0\\1\\0\\0\\0\\0\\0\\0\\3www\\4news\\3com\\0\\0\\1\\0\\1", 30, MSG_NOSIGNAL, NULL, 0) = 30
poll([{fd=3, events=POLLIN, revents=POLLIN}], 1, 5000) = 1
recvfrom(3, "k\\374\\201\\200\\0\\1\\0\\2\\0\\0\\0\\0\\3www\\4news\\3com\\0\\0\\1\\0\\1\\300\\f"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("62.30.112.39")}, [16]) = 106
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("62.30.112.39")}, 28) = 0
poll([{fd=3, events=POLLOUT, revents=POLLOUT}], 1, 0) = 1
sendto(3, "\\\\\\2\\1\\0\\0\\1\\0\\0\\0\\0\\0\\0\\3www\\4news\\3com\\0\\0\\1\\0\\1", 30, MSG_NOSIGNAL, NULL, 0) = 30
poll([{fd=3, events=POLLIN, revents=POLLIN}], 1, 5000) = 1
recvfrom(3, "\\\\\\2\\201\\200\\0\\1\\0\\2\\0\\0\\0\\0\\3www\\4news\\3com\\0\\0\\1\\0\\1\\300\\f"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("62.30.112.39")}, [16]) = 106
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("216.239.122.102")}, 16) = -1 EINPROGRESS (Operation now in progress)
select(4, NULL, [3], NULL, NULL) = 1 (out [3])
这个连接尝试访问了/var/run/nscd/socket,这意味着nc命令首先尝试连接NSCD服务(名称缓存守护进程,通常用于NIS,YP,LDAP中的名字查找)。在上面的例子里执行失败。
nc命令转而使用DNS(DNS的端口是53,"sin_port=htons(53)" )。可以看到程序调用”sendto()"发送包含www.news.com信息的DNS数据包。因为某些原因,尝试了3次。为什么会这样呢?我猜测可能www.news.com是CNAME ,最后,程序连接从DNS获取到的IP,注意这里,返回EINPROGRESS。这意味这这个连接是非堵塞的。连接成功后nc调用select。
添加read和write到跟踪的系统调用列表里,连接上后敲入test,你会看到如下信息:
read(0, "test\\n", 1024) = 5
write(3, "test\\n", 5) = 5
poll([{fd=3, events=POLLIN, revents=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1
read(3, "
你可以看到,程序从标准输入中读取到“test”,写到网络连接中,然后调用poll()等待响应,读取响应然后写入到标准输出中。
用strace排查故障的5种简单方法(每日一译)的更多相关文章
- 使用strace工具故障排查的5种简单方法
使用strace工具故障排查的5种简单方法 本文源自5 simple ways to troubleshoot using strace strace 是一个非常简单的工具,用来跟踪可执行程序的系统调 ...
- WPF编程 ,TextBlock 显示百分数值的一种简单方法。
原文:WPF编程 ,TextBlock 显示百分数值的一种简单方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/article/ ...
- Honeywords项目——检查密码是否被破解的一种简单方法
Honeywords项目使用一种简单的方法来改进hash后的密码的安全性——为每个账户维护一个额外的honeywords(假密码).如果有黑客拿到了密码的文件,然后试图用brute froce的方式破 ...
- Qt实现软件自动更新的一种简单方法
前言 最近在学习Qt开发上位机,想实现一个检查更新的功能,网上搜索了一大圈,发现实现过程都很复杂,关键是代码看不懂,所以就自己开发一种简单的方式来实现.实现效果如下: 点击"检查更新&quo ...
- Mac上打开终端的7种简单方法
终端机是用于给Mac命令的便捷工具,尽管它可能会吓倒许多人.毕竟,这不像输入句子然后Mac响应那样简单.如果您有兴趣学习使用Terminal或只想输入一两个命令,我们在下面列出了一些文章,可以帮助您使 ...
- SSM/SSH框架的MySQL 读写分离实现的一种简单方法
简介 MySQL已经是使用最为广泛的一种数据库,往往实际使用过程中,为实现高可用及高性能,项目会采用主丛复制的方式实现读写分离.MySQL本身支持复制,通过简单的配置即可实现一主多从的配置,具体实现可 ...
- Flask生成SECRET_KEY(密钥)的一种简单方法
SECRET_KEY是Flask中比较重要的一个配置值.本文介绍一种比较简单的生成SECRET_KEY的方法. Session, Cookies以及一些第三方扩展都会用到SECRET_KEY值,这是一 ...
- 下载文件的一种简单方法js
我在做的一个项目有一部分要下载附件,可是我们公司用了一个包和网上的用response的解决方法冲突,而网上的js解决方法又用到了ActiveXObj我们经理不让用这个.还好我一个同事很利害用了一个很简 ...
- Visual Studio写的项目在 IIS 服务器上运行的两种简单方法
首先需要PC上开启了IIS服务,相关方法网上很多,也很简单 第一种:直接在项目中操作 1.创建一个项目,然后右击选中项目,右击,单击属性,打开项目属性标签页面 如图,选择Web标签,在服务器栏目中选中 ...
随机推荐
- marquee
marquee: 页面的自动滚动效果,可由javascript来实现,但是今天无意中发现了一个html标签 - <marquee></marquee>可以实现多种滚动效果,无需 ...
- Scala具体解释---------类
Scala中的类 摘要: 在本篇中.你将会学习怎样用Scala实现类. 假设你了解Java或C++中的类,你不会认为这有多难.而且你会非常享受Scala更加精简的表示法带来的便利.本篇的要点包含: 1 ...
- jmeter响应数据中文乱码问题
进入jmeter安装文件目录:D:\Program File\apache-jmeter-2.13\apache-jmeter-2.13\bin\ 修改jmeter.properties文件,在最下方 ...
- 2、TaskFactory类
使用实例化的TaskFactory类,在其中把TaskMethod方法传递给StartNew()方法,就会立即启动任务. 1: TaskFactory tf = new TaskFactory(); ...
- 将二级目录下的文件合并成一个文件的Python小脚本
这个小程序的目的是将二级目录下的文件全部合并成一个文件(其实几级目录都可以,只要做少许改动) #coding:utf8 import sys, os def process(path): new_fi ...
- 免费的EmBitz可替代Keil MDK开发STM32、NXP项目
一.背景 由于使用之前开发STM32是基于Keil MDK编译环境开发的,由于该软件是收费的,想用个免费开源的软件来替代Keil,EmBitz编译器是免费的,可以完全替代开发.下载程序支持J-Link ...
- 设计模式六大原则(五):迪米特法则(Law Of Demeter)
定义: 一个对象应该对其他对象保持最少的了解. 问题由来: 类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大. 解决方案: 尽量降低类与类之间的耦合. PS: 自从我们接 ...
- git还原文件
http://jingyan.baidu.com/album/e4511cf33479812b855eaf67.html
- 非常有用的sql脚本
/*sql 语法学习*/ /*函数的学习---------------------------------------*/ 获取当前时间(时/分/秒):select convert(varchar(1 ...
- css基础属性
color:设置文本颜色:属性值:1.表示颜色的英文单词,例如:red.blue.green.pink.purple.cyan等:2.十六进制表示法:#ff0000: 0.1.2...9.a.b.c. ...