早些年,如果你知道有个 strace 命令,就很牛了,而现在大家基本都知道 strace 了,如果你遇到性能问题求助别人,十有八九会建议你用 strace 挂上去看看,不过当你挂上去了,看着满屏翻滚的字符,却十有八九看不出个所以然。本文通过一个简单的案例,向你展示一下在用 strace 诊断问题时的一些套路。
strace是Linux环境下的一款程序调试工具,用来监察一个应用程序所使用的系统调用及它所接收的系统信息。追踪程序运行时的整个生命周期,输出每一个系统调用的名字,参数,返回值和执行消耗的时间等。 strace常用参数: -p 跟踪指定的进程 -f 跟踪由fork子进程系统调用 -F 尝试跟踪vfork子进程系统调吸入,与-f同时出现时, vfork不被跟踪 -o filename 默认strace将结果输出到stdout。通过-o可以将输出写入到filename文件中 -ff 常与-o选项一起使用,不同进程(子进程)产生的系统调用输出到filename.PID文件 -r 打印每一个系统调用的相对时间 -t 在输出中的每一行前加上时间信息。 -tt 时间确定到微秒级。还可以使用-ttt打印相对时间 -v 输出所有系统调用。默认情况下,一些频繁调用的系统调用不会输出 -s 指定每一行输出字符串的长度,默认是32。文件名一直全部输出 -c 统计每种系统调用所执行的时间,调用次数,出错次数。 -e expr 输出过滤器,通过表达式,可以过滤出掉你不想要输出
如下真实案例,如有雷同,实属必然!让我们看一台高负载服务器的 top 结果:
技巧:运行 top 时,按「1」打开 CPU 列表,按「shift+p」以 CPU 排序。
在本例中大家很容易发现 CPU 主要是被若干个 PHP 进程占用了,同时 PHP 进程占用的比较多的内存,不过系统内存尚有结余,SWAP 也不严重,这并不是问题主因。
不过在 CPU 列表中能看到 CPU 主要消耗在内核态「sy」,而不是用户态「us」,和我们的经验不符。Linux 操作系统有很多用来跟踪程序行为的工具,内核态的函数调用跟踪用「strace」,用户态的函数调用跟踪用「ltrace」,所以这里我们应该用「strace」:
shell> strace -p
不过如果直接用 strace 跟踪某个进程的话,那么等待你的往往是满屏翻滚的字符,想从这里看出问题的症结并不是一件容易的事情,好在 strace 可以按操作汇总时间:
shell> strace -cp
通过「c」选项用来汇总各个操作的总耗时,运行后的结果大概如下图所示:
exec 函数,通过如下命令验证它确实会导致 clone 系统调用:
shell> strace -eclone php -r 'exec("ls");'
如果想要追踪多个fpm进程可以用以下脚本:
strace -eall -c $(ps auxf|grep -E ‘(9013|9014|9015)’|awk ‘{if ($1=”www-data”) print “-p “$2}’)
最后再考大家一个题:如果我们用 strace 跟踪一个进程,输出结果很少,是不是说明进程很空闲?其实试试 ltrace,可能会发现别有洞天。记住有内核态和用户态之分。