Linux|Linux lsof 调试 PHP

1 简介

lsof(list open files) 是一个列出当前系统打开文件的工具。
在 linux 环境下,任何事物都以文件的形式存在,通过文件不仅仅可以访问常规数据,还可以访问网络连接和硬件。所以如传输控制协议 (TCP) 和用户数据报协议 (UDP) 套接字等,系统在后台都为该应用程序分配了一个文件描述符,无论这个文件的本质如何,该文件描述符为应用程序与基础操作系统之间的交互提供了通用接口。因为应用程序打开文件的描述符列表提供了大量关于这个应用程序本身的信息,因此通过 lsof 工具能够查看这个列表对系统监测以及排错将是很有帮助的。
2 命令使用
lsof [选项] [绝对路径的文件名]

选项:
-a:列出打开文件存在的进程; -c<进程名>:列出指定进程所打开的文件; -g:列出GID号进程详情; -d<文件号>:列出占用该文件号的进程; +d<目录>:列出目录下被打开的文件; +D<目录>:递归列出目录下被打开的文件; -n<目录>:列出使用NFS的文件; -i<条件>:列出符合条件的进程。(4、6、协议、:端口、 @ip ) -p<进程号>:列出指定进程号所打开的文件; -u:列出UID号进程详情; -h:显示帮助信息; -v:显示版本信息。

显示示例:
[root@localhost public]# lsof /usr/local/php71/sbin/php-fpm COMMANDPID USERFDTYPE DEVICE SIZE/OFFNODE NAME php-fpm 1544 root txtREG253,0 40770864 1506860 /usr/local/php71/sbin/php-fpm php-fpm 1545www txtREG253,0 40770864 1506860 /usr/local/php71/sbin/php-fpm php-fpm 1546www txtREG253,0 40770864 1506860 /usr/local/php71/sbin/php-fpm php-fpm 1547www txtREG253,0 40770864 1506860 /usr/local/php71/sbin/php-fpm php-fpm 1548www txtREG253,0 40770864 1506860 /usr/local/php71/sbin/php-fpm php-fpm 1549www txtREG253,0 40770864 1506860 /usr/local/php71/sbin/php-fpm php-fpm 1550www txtREG253,0 40770864 1506860 /usr/local/php71/sbin/php-fpm ......

每行显示一个打开的文件,默认如果后面不跟任何东西,将打开系统打开的所有文件。
参数 说明
COMMAND 进程名称
PID 进程标识符
USER 进程所有者
FD 文件描述符,应用程序通过文件描述符识别到该文件。如 cwd、txt 等。
TYPE 文件类型,如 REG、DIR、CHR、BLK、UNIX、FIFO、IPV4。
DEVICE 指定磁盘名称
SIZE 文件大小。单位(字节)。
补充:FD 列中的文件描述 cwd 值表示应用程序的当前工作目录,这是该程序启动的目录,除非它本身对这个目录进行更改。txt 类型的是程序代码,如应用程序二进制文件本身或者共享库。其次数值表示应用程序的文件描述符,这是打开文件时一个返回的一个整数。
3 TYPE 说明
参数 说明
REG 文件。
DIR 目录。
CHR 字符设备。命令行终端。
BLK 块设备。如硬盘、内存。
UNIX UNIX 域套接字。
FIFO 先进先出 (FIFO) 队列。
IPV4 网际协议 (IP) 套接字。
NODE 索引节点(文件在磁盘上的标识) 。
4 FD 说明
参数 说明
cwd 表示current work dirctory,即:应用程序的当前工作目录,这是该应用程序启动的目录,除非它本身对这个目录进行更改 。
txt 该类型的文件是程序代码,如应用程序二进制文件本身或共享库,如上列表中显示的 /sbin/init 程序 。
lnn library references (AIX)。
er FD information error (see NAME column) 。
jld jail directory (FreeBSD) 。
ltx shared library text (code and data) 。
mxx hex memory-mapped type number xx。
m86 DOS Merge mapped file。
mem memory-mapped file。
mmap memory-mapped device。
pd parent directory。
rtd root directory。
tr kernel trace file (OpenBSD) 。
v86 VP/ix mapped file。
0 表示标准输出。
1 表示标准输入。
2 表示标准错误。
一般在标准输出、标准错误、标准输入后还跟着文件状态模式
参数 说明
u 表示该文件被打开并处于读取/写入模式。
r 表示该文件被打开并处于只读模式。
w 表示该文件被打开并处于写入模式。
空格 表示该文件的状态模式为 unknow,且没有锁定。
- 表示该文件的状态模式为 unknow,且被锁定。
5 调试 PHP
以下示例来源于网络整理。目的是解决进程卡死的情况。经验证,示例当中步骤以及命令无误。
5.1) 首先获取该进程 ID
ps -aux | grep QueryABC.php sync360111150.00.06564864 ?Ss14:000:00 /bin/sh -c /usr/local/bin/php /home/QueryABC.php BILL99DF 10-8>> /home sync360111240.00.4 361628 17296 ?S14:000:04 /usr/local/bin/php /home/QueryABC.php BILL99DF 10-8 sync360252300.00.063384872 pts/0S+15:280:00 grep QueryABC.php

5.2) strace 查看该进程正在持续的状态
sudo strace -T -tt -e trace=all -p 11124 [sudo] password for ancongcong: Process 11124 attached - interrupt to quit 15:33:07.259044 read(9,

5.3) lsof 查看进程的所有使用的文件
lsof -p 11124 .... php11124 sync360memREG8,1237363211320 /lib64/libnss_dns-2.5.so php11124 sync3600rFIFO0,61522728709 pipe php11124 sync3601wREG8,140888191869737 /home/logs/QueryABC.log php11124 sync3602wFIFO0,61522728710 pipe php11124 sync3603wCHR1,3982 /dev/null php11124 sync3604uIPv4 1522728838TCP 211.151.122.234:46004->10.117.128.47:rtmp-port (CLOSE_WAIT) php11124 sync3605wWREG8,102704363 /home/lockfile/QueryABC.php.BILL99DF.10-8 php11124 sync3606uIPv4 1522728841TCP 211.151.122.234:51019->10.117.128.46:rtmp-port (CLOSE_WAIT) php11124 sync3607wREG8,1 319603841869789 /home/logs/XXXX_info.log.20180118 php11124 sync3608wREG8,1 181517221869806 /home/logs/XXXX_QRY_info.log.20180118 php11124 sync3609uIPv4 1522729884TCP 211.151.122.234:54976->61.152.114.130:https (ESTABLISHED)

sudo netstat -tunpa | grep 11124 tcp00 211.151.122.234:5497661.152.114.130:443ESTABLISHED 11124/php tcp10 211.151.122.234:5101910.117.128.46:3500CLOSE_WAIT11124/php tcp10 211.151.122.234:4600410.117.128.47:3500CLOSE_WAIT11124/php

可以发现最终是停留在 https 的链接建立,等待获取数据,查看此处代码 :
ini_set('default_socket_timeout',30); $scOptions = array('connection_timeout' => 30); $clientObj = new SoapClient( $wsdl , $scOptions);

当前版本 php 较老,这里是有个 bug 的在 https 链接请求时 SOAPClient 的超时时间是不生效。导致一直连接不释放,当请求量上来的时候,会导致服务器陷入高负载状态。
6 查询 PHP 进程状态
所谓状态,指的是我们在启动 PHP 的时候,PHP-FPM 加载的系统库、PHP 扩展、以及其他日志文件等的状态信息。
6.1) 查询 PHP-FPM 进程的 PID
[root@localhost ~]# ps -aux|grep php-fpm root15440.00.8 291448 16244 ?SsJul300:06 php-fpm: master process www15450.00.9 291920 17340 ?SJul300:00 php-fpm: pool www www15460.00.9 292136 17856 ?SJul300:00 php-fpm: pool www www15470.00.9 291908 17336 ?SJul300:00 php-fpm: pool www www15480.00.9 291916 17308 ?SJul300:00 php-fpm: pool www www15490.00.9 292272 17880 ?SJul300:00 php-fpm: pool www www15500.00.9 292616 18132 ?SJul300:00 php-fpm: pool www ......

可以获知我们的 PHP-FPM 主进程的 PID 为 1544。
6.2) 查询进程状态
[root@localhost ~]# lsof -p 1544 COMMANDPID USERFDTYPEDEVICESIZE/OFFNODE NAME php-fpm 1544 rootcwdDIR253,027164 / php-fpm 1544 rootrtdDIR253,027164 / php-fpm 1544 roottxtREG253,0407708641506860 /usr/local/php71/sbin/php-fpm php-fpm 1544 rootmemREG253,062184482957 /usr/lib64/libnss_files-2.17.so php-fpm 1544 rootmemREG253,04194305 16881237 /tmp/phptrace.ctrl php-fpm 1544 rootmemREG253,0185046441259 /usr/lib64/libdb-5.3.so php-fpm 1544 rootmemREG253,028216 33654797 /usr/lib64/sasl2/libsasldb.so.3.0.0 php-fpm 1544 rootmemREG253,019968 33654794 /usr/lib64/sasl2/libanonymous.so.3.0.0 php-fpm 1544 rootDELREG0,418634 /dev/zero php-fpm 1544 rootmemREG253,0159600 51987804 /usr/local/php71/lib/php/extensions/no-debug-non-zts-20160303/trace.so php-fpm 1544 rootmemREG253,04414480 50968175 /usr/local/php71/lib/php/extensions/no-debug-non-zts-20160303/mongodb.so php-fpm 1544 rootmemREG253,0851128 50666307 /usr/local/lib/libevent_core-2.1.so.6.0.2 php-fpm 1544 rootmemREG253,0502032 50666311 /usr/local/lib/libevent_extra-2.1.so.6.0.2 php-fpm 1544 rootmemREG253,0116088 50666319 /usr/local/lib/libevent_openssl-2.1.so.6.0.2 php-fpm 1544 rootmemREG253,0883440 52435182 /usr/local/php71/lib/php/extensions/no-debug-non-zts-20160303/event.so php-fpm 1544 rootmemREG253,012132041640 /usr/lib64/libsasl2.so.3.0.0 php-fpm 1544 rootmemREG253,05662520 51023034 /usr/local/lib/librdkafka.so.1 php-fpm 1544 rootmemREG253,0440512 51861780 /usr/local/php71/lib/php/extensions/no-debug-non-zts-20160303/rdkafka.so php-fpm 1544 rootmemREG253,04408400 50919001 /usr/local/php71/lib/php/extensions/no-debug-non-zts-20160303/swoole.so php-fpm 1544 rootmemREG253,01426032 52419266 /usr/local/php71/lib/php/extensions/no-debug-non-zts-20160303/yaf.so php-fpm 1544 rootmemREG253,03618280 51005421 /usr/local/php71/lib/php/extensions/no-debug-non-zts-20160303/fileinfo.so php-fpm 1544 rootmemREG253,01734168 52419246 /usr/local/php71/lib/php/extensions/no-debug-non-zts-20160303/redis.so php-fpm 1544 rootmemREG253,01310320 51861871 /usr/local/php71/lib/php/extensions/no-debug-non-zts-20160303/xdebug.so php-fpm 1544 rootmemREG253,01631520 51851520 /usr/local/php71/lib/php/extensions/no-debug-non-zts-20160303/opcache.so php-fpm 1544 rootmemREG253,0 106070960 50918862 /usr/lib/locale/locale-archive php-fpm 1544 rootmemREG253,040238441228 /usr/lib64/libpcre.so.1.2.0 php-fpm 1544 rootmemREG253,0155784264930 /usr/lib64/libselinux.so.1 php-fpm 1544 rootmemREG253,01568843432 /usr/lib64/libkeyutils.so.1.5 php-fpm 1544 rootmemREG253,0587281528050 /usr/lib64/libkrb5support.so.0.1 php-fpm 1544 rootmemREG253,021084044058 /usr/lib64/libk5crypto.so.3.1 php-fpm 1544 rootmemREG253,0158481299 /usr/lib64/libcom_err.so.2.1 php-fpm 1544 rootmemREG253,0963576177761 /usr/lib64/libkrb5.so.3.3 php-fpm 1544 rootmemREG253,03204081349437 /usr/lib64/libgssapi_krb5.so.2.2 php-fpm 1544 rootmemREG253,01574241300 /usr/lib64/liblzma.so.5.2.2 php-fpm 1544 rootmemREG253,0144792524665 /usr/lib64/libpthread-2.17.so php-fpm 1544 rootmemREG253,01938441444 /usr/lib64/libgpg-error.so.0.10.0 php-fpm 1544 rootmemREG253,053506441239 /usr/lib64/libgcrypt.so.11.8.2 php-fpm 1544 rootmemREG253,0114641231 /usr/lib64/libfreebl3.so php-fpm 1544 rootmemREG253,021735121485 /usr/lib64/libc-2.17.so php-fpm 1544 rootmemREG253,0887201499604 /usr/lib64/libgcc_s-4.8.5-20150702.so.1 php-fpm 1544 rootmemREG253,01419360 51389508 /usr/local/lib/libiconv.so.2.6.0 php-fpm 1544 rootmemREG253,02583441577528 /usr/lib64/libxslt.so.1.1.28 php-fpm 1544 rootmemREG253,0571361579626 /usr/lib64/libicuio.so.50.1.2 php-fpm 1544 rootmemREG253,0207898961579622 /usr/lib64/libicudata.so.50.1.2 php-fpm 1544 rootmemREG253,015393921579636 /usr/lib64/libicuuc.so.50.1.2 php-fpm 1544 rootmemREG253,020960561579624 /usr/lib64/libicui18n.so.50.1.2 php-fpm 1544 rootmemREG253,06917361349410 /usr/lib64/libfreetype.so.6.10.0 php-fpm 1544 rootmemREG253,0472672 51303927 /usr/local/lib/libcurl.so.4.4.0 php-fpm 1544 rootmemREG253,025128321528053 /usr/lib64/libcrypto.so.1.0.2k php-fpm 1544 rootmemREG253,04703601528055 /usr/lib64/libssl.so.1.0.2k php-fpm 1544 rootmemREG253,0150937641480 /usr/lib64/libxml2.so.2.9.1 php-fpm 1544 rootmemREG253,0117680482950 /usr/lib64/libnsl-2.17.so php-fpm 1544 rootmemREG253,01139680177756 /usr/lib64/libm-2.17.so php-fpm 1544 rootmemREG253,02852965399 /usr/lib64/libjpeg.so.62.1.0 php-fpm 1544 rootmemREG253,01792965419 /usr/lib64/libpng15.so.15.13.0 php-fpm 1544 rootmemREG253,09958401337428 /usr/lib64/libstdc++.so.6.0.19 php-fpm 1544 rootmemREG253,019776858 /usr/lib64/libdl-2.17.so php-fpm 1544 rootmemREG253,0662504 50758820 /usr/local/lib/libmcrypt.so.4.4.8 php-fpm 1544 rootmemREG253,0444481254 /usr/lib64/librt-2.17.so php-fpm 1544 rootmemREG253,0106848524736 /usr/lib64/libresolv-2.17.so php-fpm 1544 rootmemREG253,0873681577526 /usr/lib64/libexslt.so.0.8.17 php-fpm 1544 rootmemREG253,09066441257 /usr/lib64/libz.so.1.2.7 php-fpm 1544 rootmemREG253,041080854 /usr/lib64/libcrypt-2.17.so php-fpm 1544 rootmemREG253,01642401517336 /usr/lib64/ld-2.17.so php-fpm 1544 rootDELREG0,420579 /dev/zero php-fpm 1544 root0uCHR1,30t01028 /dev/null php-fpm 1544 root1uCHR1,30t01028 /dev/null php-fpm 1544 root2wREG253,01998396 36911463 /usr/local/php71/var/log/php71-fpm.log php-fpm 1544 root3wREG253,01998396 36911463 /usr/local/php71/var/log/php71-fpm.log php-fpm 1544 root4uunix 0xffff886c38c9c0000t020580 socket php-fpm 1544 root5rFIFO0,90t020585 pipe php-fpm 1544 root6uunix 0xffff886c38c9d4000t020581 socket php-fpm 1544 root7uunix 0xffff886c38c9c8000t020582 /dev/shm/php71-cgi.sock php-fpm 1544 root8ua_inode0,1006123 [eventpoll]

通过以上信息,我们可以明确知道我们的这个进程对应的 PHP-FPM 的绝对路径。以及它加载了系统的哪些类库,和加载了 PHP 的哪些类库。
php-fpm 1544 root0uCHR1,30t01028 /dev/null php-fpm 1544 root1uCHR1,30t01028 /dev/null php-fpm 1544 root2wREG253,01998396 36911463 /usr/local/php71/var/log/php71-fpm.log

通过此项,我们可以看到,标准输出(0u)丢弃了(/dev/null)。标准转入(1u)也丢弃了(/dev/null)。标准的错误(2w)转出到了 /usr/local/php71/var/log/php71-fpm.log 文件。
7 其它用法
7.1) 列出所有打开的文件:
lsof

备注: 如果不加任何参数,就会打开所有被打开的文件,建议加上一下参数来具体定位。通常我们不会这样直接用。
7.2) 查看谁正在使用某个文件:
lsof /usr/local/php53/var/log/php-fpm.log

7.3) 递归查看某个目录的文件信息:
lsof +D /usr/local/php53/var/log/

备注: 使用了+D,对应目录下的所有子目录和文件都会被列出
7.4) 列出某个用户打开的文件信息
lsof -u www

备注: -u 选项,u 其实是 user 的缩写。该示例在笔者电脑上是列出 nginx/php-fpm 打开的文件信息。
7.5) 列出某个程序所打开的文件信息
lsof -c mysql lsof -c php-fpm

备注: -c 选项将会列出所有以 mysql 开头的程序的文件。
7.6) 列出多个程序多打开的文件信息
lsof -c mysql -c apache

7.7) 列出某个用户以及某个程序所打开的文件信息
lsof -u root -c mysql

7.8) 列出除了某个用户外的被打开的文件信息
lsof -u ^root

备注:^这个符号在用户名之前,将会把是 root 用户打开的进程不让显示。
7.9) 通过某个进程号显示该进行打开的文件
lsof -p 进程 ID

7.10) 列出多个进程号对应的文件信息
lsof -p 进程ID,进程ID,进程ID

7.11) 列出除了某个进程号,其他进程号所打开的文件信息
lsof -p ^1

【Linux|Linux lsof 调试 PHP】7.12) 列出所有的网络连接
lsof -i

7.13) 列出所有 tcp 网络连接信息
lsof -i tcp

7.14) 列出所有udp网络连接信息
lsof -i udp

7.15) 列出谁在使用某个端口
[root@localhost ~]# lsof -i :6379 COMMANDPIDUSERFDTYPE DEVICE SIZE/OFF NODE NAME redis-ser 1344 redis4uIPv4195210t0TCP localhost:6379 (LISTEN)

7.16) 列出谁在使用某个特定的udp端口
lsof -i udp:55

7.17) 列出谁在使用某个特定的tcp端口
lsof -i tcp:80

7.18) 列出某个用户的所有活跃的网络端口
lsof -a -u root -i

7.19) 列出所有网络文件系统
lsof -N

7.20) 域名 socket 文件
lsof -u

8 总结
lsof 命令可以用来查看我们的进程打开的文件、目录、网络设置、网络连接等。在排查 PHP 性能问题的时候,可以起到一个直接或间接的佐证工具。让我们能快速定位问题并解决问题。

    推荐阅读