lsof-文件监控常用命令

以下是阅读《软件性能测试、分析与调优实践之路 (张永清)》书籍和其他资料整理的读书笔记

lsof命令

lsof(list open file)是Linux操作系统中对文件进行监控的一个常用命令。使用该命令可以列出当前系统打开了哪些文件、系统中某个进程打开了哪些文件等信息。

主要选项参数释义

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

安装lsof命令

yum install lsof -y

直接执行lsof命令即可以显示当前操作系统打开了哪些文件。
lsof命令必须运行在root用户下,因为lsof命令执行时需要访问核心内存和内核文件

[root@vircent7 ~]# lsof
COMMAND    PID  TID    USER   FD      TYPE             DEVICE  SIZE/OFF       NODE NAME
systemd      1         root  cwd       DIR              253,0       224         64 /
systemd      1         root  rtd       DIR              253,0       224         64 /
systemd      1         root  txt       REG              253,0   1632960     467282 /usr/lib/systemd/systemd
systemd      1         root  mem       REG              253,0     20064      12226 /usr/lib64/libuuid.so.1.3.0
systemd      1         root  mem       REG              253,0    265576     341954 /usr/lib64/libblkid.so.1.1.0
systemd      1         root  mem       REG              253,0     90160      12216 /usr/lib64/libz.so.1.2.7
systemd      1         root  mem       REG              253,0    157424       1429 /usr/lib64/liblzma.so.5.2.2
systemd      1         root  mem       REG              253,0     23968      38683 /usr/lib64/libcap-ng.so.0.0.0     
COMMAND    PID  TID    USER   FD      TYPE             DEVICE  SIZE/OFF       NODE NAME

lsof输出各列信息的意义如下

  1. COMMAND:进程的名称
  2. PID:进程的id编号
  3. USER:进程所有者,也就是这个进程是运行在哪个Linux用户下的
  4. PGID:进程所属组
  5. FD:文件描述符,应用程序通过文件描述符识别该文件
  6. TYPE:文件类型
  7. DEVICE:指定磁盘的名称
  8. SIZE/OFF:文件的大小
  9. NODE:索引节点(文件在磁盘上的标识)
  10. NAME:打开文件的确切名称

第5列FD是文件描述符 ( File Descriptor Number),常见文件描述符类型有

文件描述符简称(全称) 解释
cwd(current work dirctory) 应用程序的当前工作目录,这是该应用程序启动的目录,除非它本身对这个目录进行更改
txt(program txt) 该类型的文件是程序代码,如应用程序二进制文件本身或共享库,包括编译后的代码文件以及产生的数据文件等。
pd(parent directory) 父目录
rtd(root directory) root根目录
lnn(library references) (AIX)(库引用)
err(FD information error) 文件描述信息错误
jld(jail directory) 监控目录
ltx(shared library text ) 共享的lib数据
mxx (hex memory-mapped type number xx) 十六进制内存映射类型号xx
m86(DOS Merge mapped file) 合并映射文件
mem(memory-mapped file) 把磁盘文件映射到内存中
mmap(memory-mapped device) 把磁盘设备映射到内存中
tr(kernel trace file) 内核跟踪文件
v86 VP/ix mapped file VP/IX映射文件
DEL(a Linux map file that has been deleted) 代表已经删除的Linux映射文件
数字+字符,如0u、1w、2w 0:表示标准输出
1:表示标准输入
2:表示标准错误
u:表示该文件被打开并处于读取/写入模式
r:表示文件被打开并处于只读模式
w:表示该文件被打开并处于只写入模式

TYPE是打开的文件类型,常见的文件类型有

文件类型 解释
DIR(Directory) 表示目录
CHR(character special file) 特殊字符文件
LINK(symbolic link file) 连接文件
BLK(block) 块设备类型。
IPv4(IPv4 socket) 网际协议 (IP) 套接字。
IPv6(IPv4 network file) 打开了一个IPv6的网络文件
REG(regular file) 普通文件
UNIX(Unix domain socket) UNIX 域套接字。即常说的IPC socket(进程间的通信socket)
FIFO(FIFO special file) 先进先出 (FIFO) 队列文件
MPB(multiplexed block file) 多路复用的块文件
MPC(multiplexed character file) 多路复用的字符文件
inet(an Inernet domain socket) Intent域套接字

DEVICE:展示的是设备号,以逗号分隔,一般使用character special、block special、regular、directory 等来表示设备号,在有些时候也会以地址或者设备名称来表示。

SIZE:展示的是文件的大小(前提是文件有效)。

NODE:展示的是操作系统本地文件的node number或者服务器主机中NFS文件的inode number或者协议类型(在网络通信的情况下会展示通信协议类型。

NAME:展示的是文件的绝对路径或者网络通信链接的地址、端口、状态或者挂载点等。

实例

losf -c 进程名查看某个进程名称当前打开的文件

例如查看mysql进程当前打开了哪些文件。

lsof -c mysql

[root@localhost ~]# lsof -c mysql
COMMAND  PID    USER   FD   TYPE DEVICE SIZE/OFF      NODE NAME
mysqld  1404 polkitd  cwd    DIR  253,0     4096      2034 /var/lib/mysql
mysqld  1404 polkitd  rtd    DIR   0,38       28  34882914 /
mysqld  1404 polkitd  txt    REG   0,38 30318832   1113654 /usr/sbin/mysqld
mysqld  1404 polkitd  mem    REG  253,0            1113654 /usr/sbin/mysqld (stat: No such file or directory)
mysqld  1404 polkitd  mem    REG  253,0           34031034 /lib/x86_64-linux-gnu/libnss_files-2.28.so (stat: No such file or directory)
mysqld  1404 polkitd  DEL    REG   0,11              27557 /[aio]
mysqld  1404 polkitd  DEL    REG   0,11              27556 /[aio]
mysqld  1404 polkitd  DEL    REG   0,11              27555 /[aio]
mysqld  1404 polkitd  DEL    REG   0,11              27554 /[aio]

...

lsof -p PID查看某个进程id当前打开的文件

例如,查看进程id为1的进程当前打开了哪些文件。

lsof -p 1

[root@localhost ~]# lsof -p 1
COMMAND PID USER   FD      TYPE             DEVICE SIZE/OFF       NODE NAME
systemd   1 root  cwd       DIR              253,0      224         64 /
systemd   1 root  rtd       DIR              253,0      224         64 /
systemd   1 root  txt       REG              253,0  1632960     467282 /usr/lib/systemd/systemd
systemd   1 root  mem       REG              253,0    20064      12226 /usr/lib64/libuuid.so.1.3.0
systemd   1 root  mem       REG              253,0   265576     341954 /usr/lib64/libblkid.so.1.1.0
systemd   1 root  mem       REG              253,0    90160      12216 /usr/lib64/libz.so.1.2.7
systemd   1 root  mem       REG              253,0   157424       1429 /usr/lib64/liblzma.so.5.2.2
systemd   1 root  mem       REG              253,0    23968      38683 /usr/lib64/libcap-ng.so.0.0.0
systemd   1 root  mem       REG              253,0    19896      38671 /usr/lib64/libattr.so.1.1.0
systemd   1 root  mem       REG              253,0    19248       1367 /usr/lib64/libdl-2.17.so
...

lsof -i:端口查看指定端口的通信连接情况

lsof -i可以查看IPv4、IPv6下打开的文件,此时看到的大部分都是网络的链接通信,会包括服务端的LISTEN监听或者客户端和服务端的网络通信。在lsof -i后加上“:(冒号)端口号”时,可以定位到某个端口下的IPv4、IPv6模式打开的文件和该端口下的网络链接通信,例如,查看3337端口下的网络链接通信情况

lsof -i:3337

[root@localhost ~]# lsof -i:3337
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
docker-pr 1361 root    4u  IPv4  26089      0t0  TCP *:directv-catlg (LISTEN)
docker-pr 1367 root    4u  IPv6  26095      0t0  TCP *:directv-catlg (LISTEN)

从这个展示的通信情况可以看到,3337端口下启动了两个LISTEN监听进程,都是在root用户下,进行了TCP通信连接。

在这里插入图片描述

TCP通信连接是在做性能测试时经常需要关注的,尤其是在高并发的情况下如何优化TCP连接数和TCP连接的快速释放,是性能调优的一个关注点。连接的常用状态

狀态 说明
LISTEN 监听状态。这个一般应用程序启动时,会启动监听,比如Nginx 程序启动后,就会产生监听进程。一般情况下,监听进程的端口都可以自己进行设置,以防止端口冲突
ESTABLISHED 连接己经正常建立。表示客户端和服务端正在通信中
CLOSE_WAIT 客户端主动关闭连接或者网络异常导致连接中断。此时这次连接下服务端的状态会变成TIME_WAIT,需要服务端来主动关闭该链接。
TIME_WAIT 服务端主动断开连接。收到客户端确认后,连接状态变为TIME_WAIT,但是服务端并不会马上彻底关闭该连接,只是修改了状态。TCP 协议规定TIME_WAIT状态会一直持续2MSL的时间才会彻底关闭,以防止之前连接中的网络数据包因为网络延迟等原因而延迟出现。处于TIME_WAIT状态的连接占用的资源不会被内核释放,所以性能测试中,如果服务端出现了大量的TIME_WAIT状态的连接,就需要分析原因了,一般不建议服务端主动断开连接
SYN_SENT 表示请求正在连接中,当客户端要访问服务器上的服务时,一般都需要发送一个同步信号给服务端的端口,在此时连接的状态就为SYN_SENT。一般SYN_SENT状态的时间都非常短,除非是在非常高的井发调用下,不然一般SYN_SENT状态的连接都非常少
SYN_RECV 表示服务端接收到了客户端发出的SYN请求,同时表示服务端在给客户端回复SYN+ACK后此时服务端所处的中间状态
LAST_ACK 表示TCP连接关闭过程中的一种中间状态。关闭一个TCP连接需要发送方和接收方分别都进行关闭,双方都是通过发送FIN(关闭连接标志)来表示单方向数据的关闭,当通信双方发送了最后一个FIN 的时候,发送方此时处于 LAST_ACK 状态
CLOSING 表示TCP连接关闭过程中的一种中间状态,一般存在的时间很短,不是经常可以看到,在发送方和接收方都主动发送 FIN,并且在收到对方对自己发送的 FIN 之前收到了对方发送的 FIN 的时候,两边就都进入了CLOSING 状态
FIN_WAIT1 同样是表示TCP连接关闭过程中的一种中间状态,存在的时向很短,一般几乎看不到,发送方或者调用方主动调用close函数关闭连接后,会立刻进入FIN_WAIT1状态,此时只要收到对端的 ACK确认后马上会进入FIN_WAIT2状态
FIN_WAIT2 同样是表示TCP连接关闭过程中的一种中间状态,主动关闭连接的一方在等待对端FIN到来的过程中通常会一直保持这个状态。一般网络中断或者对端服务很忙还没有即使发送FIN,或者对端程序有Bug忘记关闭连接等,都会导致主动关闭连接的一方长时间处于FIN_WAIT2状态。如果主动关闭连接的一方发现大量FIN_WAIT2状态,应该需要去检查是不是网络不稳定或者对端的程序存在连接泄漏的情况
CLOSERD 表示连接的初始状态,表示TCP连接是“关闭着的”或“未打开的”

在TCP协议层中有一个FLAGS字段,这个字段一般包含SYN(建立连接标志)、FIN(关闭连接标志)、ACK(响应确认标志)、PSH(DATA数据传输标志)、RST(连接重置标志)、URG(紧急标志)这几种标志,每种标志代表一种连接信号。

不管是什么状态下的TCP连接,都会占用服务器的大量资源,而且每个连接都会占用一个端口,Linux服务器的TCP和UDP的端口总数是有限制的(0~65535),超过这个范围就没有端口可以用了,程序会无法启动,连接也会无法进行。所以如果服务端出现了大量的CLOSE_WAIT和TIME_WAIT的链接时,就需要及时去查找原因并进行优化。CLOSE_WAIT状态大多数都是由自己编写的代码或者程序出现了明显的问题所造成的。

端口占用优化

针对如果出现了大量的TIME_WAIT状态的连接,可以从服务器端进行一些优化以让服务器快速地释放TIME_WAIT状态的连接所占用的资源。优化的方式说明如下。

使用vim /etc/sysctl.conf来编辑sysctl.conf文件,以优化Linux操作系统的文件内核参数设置,加入如下配置

net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time=600
net.ipv4.tcp_max_tw_buckets = 5000
fs.file-max = 900000
net.ipv4.tcp_max_syn_backlog = 2000
net.core.somaxconn = 2048
net.ipv4.tcp_synack_retries = 1
net.ipv4.ip_local_port_range =2048 65535
net.core.rmem_max = 2187154
net.core.wmem_max = 2187154
net.core.rmem_default = 250000
net.core.wmem_default = 2500

然后执行sysctl -p命令可以让内核参数立即生效,这种调优一般在Nginx、Apache这种Web服务器上会经常用到

  • net.ipv4.tcp_syncookies=1 表示开启syn cookies,当出现syn等待队列溢出时启用cookies来处理,默认是关闭状态。客户端向Linux服务器建立TCP通信连接时会首先发送SYN包,发送完后客户端会等待服务端回复SYN+ACK,服务器在给客户端回复 SYNACK后 ,服务器端会将此时处于SYN_RECV状态的连接保存到半连接队列中,以等待客户端继续发送ACK请求给服务器端,直到最终连接完全建立。在出现大量的并发请求时,这个半连接队列中可能会缓存了大量的SYN_RECV状态的连接,从而导致队列溢出。
  • net.ipv4.tcp_max_syn_backlog 队列的长度可以通过内核参数net.ipv4.tcp_max_syn_backlog进行设置,在开启cookies后服务端就不需要将SYN_RECV状态的半状态连接保存到队列中,而是在回复SYN+ACK时,将连接信息保存到ISN中返回给客户端。当客户端进行ACK请求时,通过ISN来获取连接信息,以完成最终的TCP通信连接。
  • net.ipv4.tcp_tw_reuse=1表示开启连接重用,即允许操作系统将TIME-WAIT socket的连接重新用于新的TCP连接请求。默
    认为关闭状态。
  • net.ipv4.tcp_tw_recycle=1表示开启操作系统中TIME-WAIT socket连接的快速回收。默认为关闭状态。
  • net.ipv4.tcp_fin_timeout=30设置服务器主动关闭连接时,socket连接保持等待状态的最大时间。
  • net.ipv4.tcp_keepalive_time=600 表示请求在开启keepalive (现在一般客户端的HTTP请求都是开启了keepalive选项)时,TCP发送keepalive消息的时间间隔。默认是7200秒,在设置短一些后可以更快地清理掉无效的请求。
  • net.ipv4.tcp_max_tw_buckets = 5000 表示连接为TIME_WAIT状态时,Linux操作系统允许其接收的套接字数量的最大值。过多的TIME_WAIT套接字会使Web服务器变慢。
  • fs.file-max=900000 表示Linux操作系统可以同时打开的最大句柄数。在Web服务器中,这个参数有时候会直接限制了Web服务器可以支持的最大连接数。需要注意的是这个参数是对整个操作系统生效的。而ulimit -n可以用来查看进程能够打开的最大句柄数。在句柄数不够时一般会出现类似“Toomany open files”的报错。在CentOS7中,可以使用cat /proc/sys/fs/file-max命令来查看操作系统能够打开的最大句柄数。
[root@localhost ~]# cat /proc/sys/fs/file-max
181168

③使用vi /etc/security/limits.conf编辑limits.conf配置文件,可以修改进程能够打开的最大句柄数,在limits.conf增加如下配置即可。

soft nofile 65535
hard nofile 65535
  • net.ipv4.tcp_max_syn_backlog 表示服务器能接受SYN同步包的最大客户端连接数,也就是上面说的半连接的最大数量。默认值为128。
  • net.core.somaxconn=2048 表示服务器能处理的最大客户端连接数,这里的连接指的是能同时完成连接建立的最大数量。默认值为128。
  • net.ipv4.tcp_synack_retries=1 表示服务器在发送SYN+ACK回复后,在未继续收到客户端的ACK请求时,服务器端重新尝试发送SYN+ACK回复的重试次数。
  • net.ipv4.ip_local_port_range =2048 - 65535修改可以用于和客户端建立连接的端口范围。默认为32768到61000。修改后,可以避免建立连接时端口不够用的情况。
  • net.core.rmem_max=2187154 表示Linux操作系统内核socket接收缓冲区的最大值,单位为字节。
  • net.core.wmem_max = 2187154 表示Linux操作系统内核socket发送缓冲区的最大值,单位为字节。
  • net.core.rmem_default=250000 表示Linux操作系统内核socket接收缓冲区的默认大小,单位为字节。
  • net.core.wmem_default = 250000 表示Linux操作系统内核socket发送缓冲区的默认大小,单位为字节。

lsof +d:列出指定目录下被使用的文件

例如执行lsof +d /usr/lib/locale/命令,查看/usr/lib/locale/目录下有哪些文件被打开使用了

lsof +D:递归列出指定目录下所有子目录中被使用的文件

和上面+d参数的作用类似,也是列出指定目录下被使用的文件,不同的是+D会以递归的形式列出,也就是会列出指定目录下所有子目录中被使用的文件,而-d参数只会列出当前指定目录下被使用的文件,而不会继续去列出子目录下被使用的文件。例如执行lsof +D /usr/lib/命令查看/usr/lib/目录以及子目录下有哪些文件被打开使用了

lsof后面可以直接指定一个全路径的文件以列出该文件正在被哪些进程所使用,例如,执行lsof /usr/lib/modules/3.10.0-862.el7.x86_64/modules.symbols.bin命令 , 可以查看到modules.symbols.bin文件目前正在被哪个进程使用。

lsof-i@ip:可以列出某个指定ip上的所有网络连接通信

例如,执行lsof [email protected]命令,可以查看到192.168.1.221这个ip上的所有网络连接通信。

lsof -i 网络协议:可以列出某个指定协议下的网络连接信息

# 列出tcp下所有的网络连接
lsof -i tcp

# 列出tcp下80端口所有的网络连接信息
lsof -i tcp:80

# 列出udp下所有的网络连接信息
lsof -i udp

# 列出udp下323端口所有的网络连接信息
lsof -i udp:323

猜你喜欢

转载自blog.csdn.net/weixin_41948075/article/details/125558993