Linux 调试三剑客——strace,lsof,tcpdump

2017/3/10 posted in  linux

Brendan D. Gregg 专注 Linux performance & tuning 许多年,其博客 brendangregg.com 里关于分析和调优的干货琳琅满目。一篇名为 Linux Performance 文章全面而详细的整理了常用工具,覆盖了硬件、存储、网络乃至应用,如下图:

linux_observability_tools

能掌握上图的十八般武艺固然最好,从定位分析的角度来说,我认为三个高级而常用的命令是 strace, lsof 和 tcpdump。

strace

strace - trace system calls and signals

据说,对一个经验丰富的 Linux C/C++ 工程师,他通过 strace 即可分析多数软件的大致实现方式。Linux 进程空间可分为用户空间和内核空间,程序通常运行在用户态,它需要通过 系统调用 访问内核空间。系统调用的重要性不言而喻,凡是涉及到进程、文件管理、设备管理和通信等的操作都必须依赖系统调用完成,如下:

  • Process Control: load_execute_end_abort_create_terminate process, get_set process attributes, wait for time_event_signal, allocate/free memory
  • File management: create_delete_open_read_write_reposition file, get_set file attributes
  • Device Management: request_release_attach_detach device,read_write_reposition, get_set device attributes
  • Communication: create_delete connection, send_receive messages, transfer status information

strace 追踪进程产生的所有系统调用,包括参数、返回值和执行消耗的时间,很多是涉及到内核和资源层面的操作都需要系统调用完成,所以 strace 在诊断以下场景非常有效:

strace 的通常使用方式如下:

strace -f -F -T -tt -o output.txt straced_cmd -f 跟踪 fork 产生的子进程
-F 跟踪 vfork 产生的子进程
-tt 在输出中的每一行前加上时间信息,微秒级
-T 显示每一个调用所耗的时间
-o 输出到指定文件 output.txt

例如:

$ strace -T -tt -f -F ls
14:17:18.096447 execve("/bin/ls", ["ls"], [/* 31 vars */]) = 0 <0.000191>
14:17:18.097156 brk(0) = 0x1852000 <0.000196>
14:17:18.097554 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) <0.000088>
14:17:18.097836 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6056b52000 <0.000186>
14:17:18.098242 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) <0.000097>
14:17:18.101519 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 <0.000131>

对于守护进程,strace 的使用为:

strace -T -tt -e trace=all -o output.txt -p daemon_pid

lsof

Unix philosophy: everything is a file.

Linux/Unix 的 文件类型 有以下 7 种:

  • Regular file
  • Directory
  • Symbolic link
  • Named pipe
  • Socket
  • Device file
  • Door

lsof 用于查看进程打开的文件,使用方式如下:

# 查看某个进程打开的文件
lsof -p pid # 查看某个文件被哪些进程打开
lsof file_name

例如:

# 1250 为 nova-api 的 pid
$ lsof -p 1250
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nova-api 1250 nova cwd DIR 252,0 4096 133223 /var/lib/nova
nova-api 1250 nova rtd DIR 252,0 4096 2 /
nova-api 1250 nova txt REG 252,0 3345416 274069 /usr/bin/python2.7
nova-api 1250 nova mem REG 252,0 31720 407980 /usr/lib/python2.7/dist-packages/Crypto/Cipher/_AES.x86_64-linux-gnu.so
......
nova-api 1250 nova 5w FIFO 0,9 0t0 12796 pipe
nova-api 1250 nova 6u IPv4 12864 0t0 TCP *:8773 (LISTEN)
nova-api 1250 nova 7u IPv4 12891 0t0 TCP *:8774 (LISTEN)
nova-api 1250 nova 8r CHR 1,9 0t0 6683 /dev/urandom
nova-api 1250 nova 9u IPv4 12986 0t0 TCP *:8775 (LISTEN)
nova-api 1250 nova 17u 0000 0,10 0 6631 anon_inode~ bash

又如,查询 _var_log_nova_nova-api 被哪些进程打开:

$ lsof /var/log/nova/nova-api.log
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nova-api 1250 nova 3w REG 252,0 2086779 133272 /var/log/nova/nova-api.log
nova-api 2235 nova 3w REG 252,0 2086779 133272 /var/log/nova/nova-api.log
nova-api 2247 nova 3w REG 252,0 2086779 133272 /var/log/nova/nova-api.log
nova-api 2255 nova 3w REG 252,0 2086779 133272 /var/log/nova/nova-api.log

tcpdump

tcpdumpwireshark 类似,都是抓包工具,windows 用户多用 wireshark,linux 用户多用 tcpdump。tcpdump 允许用户拦截和显示发送或收到过网络连接到该计算机的TCP/IP和其他数据包,从数据链路层、网络层、传输层乃至应用层,覆盖了多种常用协议,并提供了丰富的过滤功能,使用如下:

过滤网卡:

过滤 IP:

tcpdump net 10.10.10.1
tcpdump src net 10.10.10.1
tcpdump dst net 10.10.10.2

过滤 port:

tcpdump port 80
tcpdump src port 80
tcpdump dst port 80

过滤 protocol:

tcpdump arp
tcpdump icmp
tcpdump ip
tcpdump udp
tcpdump tcp

常用表达试:

& or 'and'
|| or 'or'
! or 'not'

抓取所有经过 eth0,目的地址是 10.10.10.1:80 的 TCP 数据:

$ tcpdump -i eth0 (tcp) and (dst port 80) and (dst net 10.10.10.1)

Linux 调试三剑客——strace,lsof,tcpdump