然后读回响应。不知为何,它尝试了三次,最后一次有细微的却别,我猜是它www.news.com十一个CNAME(别名),多次请求可能是nc故意的。
最后,它发起一个connect请求到得到的IP地址,注意到返回值是EINPROGRESS。这意味着connect是非阻塞的,nc希望继续处理,然后它调用slect,连接建立后,select返回成功。
添加"read","write"到过滤系统调用列表中,连接时输入一个字串,可能会得到如下
Notice the connection attempts to /var/run/nscd/socket? They mean nc first tries to connect to NSCD - the Name Service Cache Daemon - which is usually used in setups that rely on NIS, YP, LDAP or similar directory protocols for name lookups. In this case the connects fails.
It then moves on to DNS (DNS is port 53, hence the "sin_port=htons(53)" in the following connect. You can see it then does a "sendto" call, sending a DNS packet that contains www.news.com. It then reads back a packet. For whatever reason it tries three times, the last with a slightly different request. My best guess why in this case is that www.news.com is a CNAME (an "alias"), and the multiple requests may just be an artifact of how nc deals with that.
Then in the end, it finally issues a connect to the IP it found. Notice it returns EINPROGRESS. That means the connect was non-blocking - nc wants to go on processing. It then calls select, which succeeds when the connection was successful.
Try adding "read" and "write" to the list of syscalls given to strace and enter a string when connected, and you'll get something like this:
read(0, "test\\n", 1024) = 5 write(3, "test\\n", 5) = 5 poll(, 2, -1) = 1 read(3, "这表示从标准输入读入"test"+换行符,并写到网络连接中,然后调用poll等待响应,读取响应,写回标准输出。
一切看起来都正常工作。
早些年,如果你知道有个 strace 命令,就很牛了,而现在大家基本都知道 strace 了,如果你遇到性能问题求助别人,十有八九会建议你用 strace 挂上去看看,不过当你挂上去了,看着满屏翻滚的字符,却十有八九看不出个所以然。
本文通过一个简单的案例,向你展示一下在用 strace 诊断问题时的一些套路。
如下真实案例,如有雷同,实属必然!让我们看一台高负载服务器的 top 结果:
[attach]56319[/attach]
技巧:运行 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」选项用来汇总各个操作的总耗时,运行后的结果大概如下图所示:
[attach]56320[/attach]
很明显,我们能看到 CPU 主要被 clone 操作消耗了,还可以单独跟踪一下 clone:
shell> strace -T -e clone -p 通过「T」选项可以获取操作实际消耗的时间,通过「e」选项可以跟踪某个操作:
[attach]56321[/attach]
很明显,一个 clone 操作需要几百毫秒,至于 clone 的含义,参考 man 文档:
clone creates a new process, in a manner similar to fork(2). It is actually a library function layered on top of the underlying clone system call, hereinafter referred to as sys_clone. A description of sys_clone is given towards the end of this page.
Unlike fork(2), these calls allow the child process to share parts of its execution context with the calling process, such as the memory space, the table of file descriptors, and the table of signal handlers. (Note that on this manual page, “calling process” normally corresponds to “parent process”. But see the description of CLONE_PARENT below.)
简单来说,就是创建一个新进程。那么在 PHP 里什么时候会出现此类系统调用呢?查询业务代码看到了 exec 函数,通过如下命令验证它确实会导致 clone 系统调用:
shell> strace -eclone php -r 'exec("ls");最后再考大家一个题:如果我们用 strace 跟踪一个进程,输出结果很少,是不是说明进程很空闲?其实试试 ltrace,可能会发现别有洞天。记住有内核态和用户态之分。
strace -f -e trace=read,write -p 17151 -o log #跟踪进程17151及子进程中read和write系统调用,输出到log文件.
-e expr
指定一个表达式,用来控制如何跟踪.格式如下:
value1...
qualifier 只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.
value是用来限定的符号或数字.
默认的 qualifier是 trace.
感叹号是否定符号.
例如:
-eopen等价于 -e trace=open,表示只跟踪open调用.
而-etrace!=open表示跟踪除了open以外的其他调用.
有两个特殊的符号 all 和 none.
注意有些shell使用!来执行历史记录里的命令,所以要使用\\.
-e trace=
只跟踪指定的系统 调用.例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all.
-e trace=file
只跟踪有关文件操作的系统调用.
-e trace=process
只跟踪有关进程控制的系统调用.
-e trace=network
跟踪与网络有关的所有系统调用.
-e strace=signal
跟踪所有与系统信号有关的 系统调用
-e trace=ipc
跟踪所有与进程通讯有关的系统调用
-e abbrev=
设定 strace输出的系统调用的结果集.-v 等于 abbrev=none.默认为abbrev=all.
-e raw=
将至 定的系统调用的参数以十六进制显示.
-e signal=
指定跟踪的系统信号.默认为all.如 signal=!SIGIO(或者signal=!io),表示不跟踪SIGIO信号.
-e read=
输出从指定文件中读出 的数据.例如:
-e read=,
-e write=
通用的完整用法:
strace -o output.txt -T -tt -e trace=all -p 28979上面的含义是 跟踪28979进程的所有系统调用(-e trace=all),并统计系统调用的花费时间,以及开始时间(并以可视化的时分秒格式显示),最后将记录结果存在output.txt文件里面。
语法
strace ... ... ... ... ]
strace -c ... ]