Linux常用命令--lsof

摘要

  • 本文介绍 lsof 命令的使用方法

  • 本文基于CentOS8。

lsof 是什么?

  • lsof = list open files

  • 它用来查看:

    • 当前系统中所有进程打开的文件
    • 包含普通文件、目录、socket、管道、网络连接、设备等
  • 在 Linux 中:“一切皆文件”

  • 所以你可以用 lsof 查看:

    • 谁在占用你的端口?
    • 哪个进程正在读/写某个文件?
    • 为什么文件删除了却还占磁盘?
    • 哪个文件被锁住?
    • 哪些程序在访问某个目录?
  • CentOS 默认包含 lsof,但如果没有,可以通过 yum 安装

1
yum install lsof -y

lsof 的基本用法

查看被删除但仍被占用的文件

  • 如果进程正在运行且保持文件的句柄,此时没有停止进程就执行了rm命令,此时文件的**目录项(名字)**被删除,但是文件数据本身没有被删除,只要有进程还在打开这个文件(保持文件句柄),它就继续占用磁盘空间。

  • 文件已经被删除(unlink),但进程仍然持有该文件的打开句柄,这种文件在:

1
2
3
ls 中看不到
du 不会统计空间
只有 lsof 能看到,这是典型的 “deleted but still open” 状态。
  • 此时可以通过如下命令查询哪些被删除的文件还被占用:

1
2
3
4
# 列出所有 link count 小于 1 的(deleted)文件
lsof +L1
# 列出所有被删除的文件
lsof | grep deleted
  • 如果查询到这种文件,则需要停止进程,才能真正删除文件。

记一次线上服务器磁盘空间告警问题排查

  • 监控系统告警磁盘空间小于15%,通过如下命令查看确实如此
1
2
3
4
5
6
$ df -hT
# 输出
Filesystem Type Size Used Avail Use% Mounted on
/dev/xvda1 ext4 7.9G 3.3G 4.6G 42% /
tmpfs tmpfs 2.0G 0 2.0G 0% /dev/shm
/dev/xvdf1 ext4 99G 80G 15G 85% /usr/local/boss/logs
  • 但通过如下命令具体查看目录占用空间时,发现占用的空间比实际占用的空间少很多
1
2
3
$ du -sh /usr/local/boss/logs
# 输出
2.3G /usr/local/boss/logs
  • 此时想到可能是删除的文件句柄没有被释放,可以通过如下命令查看:
1
2
3
4
5
lsof +L1
## 输出示例,NLINK:硬链接数量(Number of Links),=0 表示文件被删除,但是进程没有释放文件句柄
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
java 1836 boss 1w REG 202,81 82677994584 0 917554 /usr/local/boss/logs/tomcat_log/catalina.out (deleted)
java 1836 boss 2w REG 202,81 82677994584 0 917554 /usr/local/boss/logs/tomcat_log/catalina.out (deleted)
  • 结果如预期,这是一个tomcat进程,应该是删除了其日志文件,但是删除时没有停止tomcat进程,导致文件被继续占用,此时已经占用了80多个G的磁盘空间,如果要释放磁盘空间需要停止tomcat。

查端口被哪个进程占用

  • 通过如下命令查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 列出指定端口对应的进程
lsof -i tcp:8080
# 协议可以省略
lsof -i :8080
## 输出示例
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 18548 boss 39u IPv6 1251548211 0t0 TCP *:webcache (LISTEN)

# 将服务名称替换为端口
lsof -i :8080 -P
## 输出示例
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 18548 boss 39u IPv6 1251548211 0t0 TCP *:8080 (LISTEN)

查看某个进程打开的所有文件

  • 通过如下命令查询:

1
2
3
4
5
6
7
8
lsof -p <PID>

## 输出示例
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 18548 boss cwd DIR 202,1 4096 35377 /home/boss
java 18548 boss rtd DIR 202,1 4096 2 /
java 18548 boss mem REG 202,1 106065056 60671 /usr/lib/locale/locale-archive

  • 能看到这个进程:

    • 打开的日志文件
    • 使用的 jar 文件
    • 使用的 socket
    • 使用的 config 文件
  • 输出结果字段说明

字段 含义
COMMAND 程序名(java)
PID 进程号(18548)
USER 运行用户(boss)
FD 文件描述符
TYPE 文件类型
DEVICE 所在磁盘分区 ID
SIZE/OFF 文件大小(字节)
NODE inode 编号
NAME 文件名(或网络连接信息)

查看指定用户占用的文件

  • 通过如下命令查询:

1
2
# 列出用户 boss 所有进程打开的文件
lsof -u <USER>

查看指定程序(COMMAND)打开的文件

  • 通过如下命令查询:

1
lsof -c <command>

查某个目录或文件正在被哪些进程占用

1
2
3
4
5
6
7
8
9
10
11
# 目录 +D
# 能显示所有正在访问该目录中文件的进程
lsof +D /home/boss/logs

# 文件
lsof /home/boss/logs/access.log

# 只列出 nginx 用户占用的文件目录中的哪些文件
# -a: 逻辑与,不加 -a 则表示 逻辑或
lsof -a -u nginx +D /usr/local/nginx/logs

查看网络连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
lsof -i
# 过滤协议
lsof -i tcp
lsof -i udp
# 过滤状态
lsof -i -s tcp:listen

# 列出所有监听端口,
# -i: 显示网络相关的文件
# -P: 显示端口(不加-P则显示的是服务名)
# -n: 不将 IP 映射成主机名(禁用 DNS 查询)
# -s: 过滤显示连接状态
lsof -i -P -n -s tcp:listen
## 输出示例
mongod 1782 root 5u IPv4 8697 0t0 TCP *:27017 (LISTEN)
java 1808 boss 36u IPv6 9221 0t0 TCP *:8082 (LISTEN)
java 1808 boss 39u IPv6 9230 0t0 TCP 127.0.0.1:7093 (LISTEN)

# 列出用户 boss 的网络连接
# -a: 逻辑与,不加 -a 则表示 逻辑或
lsof -a -u boss -i

常用参数详解

参数 作用 示例
-i 查看网络相关文件/端口 lsof -i
-i :端口 查看指定端口 lsof -i :8080
-p PID 查看某个进程所有打开文件 lsof -p 1836
-u 用户名 查看某个用户进程的打开文件 lsof -u nginx
-c 进程名关键字 查看某个进程名相关的文件 lsof -c java
+D 目录 查看目录中所有被访问的文件 lsof +D /usr/local/netqin/boss/netqin/logs
+L1 查找已删除但仍被打开的文件 lsof +L1(=查找“(deleted)”占盘问题)
-d FD 查看指定文件描述符 lsof -d 1 -p 1836(看进程 stdout)
-n 不做 DNS 解析,提高速度 lsof -i -n
-P 显示端口号(不解析为服务名) lsof -i -P
-s 按连接状态过滤(TCP/UDP) lsof -i -sTCP:LISTEN
-r 持续输出(实时监控) lsof -i -r 1(每秒刷新网络连接)
-a 逻辑 AND,不加 -a 都是 逻辑 OR lsof -u boss -i(列出用户 boss 的网络连接)

lsof 文件 FD 字段详细解释

  • FD(文件描述符)格式总规则:数字 + 标志位

  • lsof 输出中的 FD(文件描述符)列,每一个都代表进程打开的一个“文件”(包括普通文件、目录、设备、socket、pipe 等)。

  • 示例

1
2
3
10r   → FD=10,read only(只读)
1w → FD=1,write only(只写)
36u → FD=36,read/write(可读可写)
  • 解释

部分 含义
数字(0、1、2、3、10、36…) 文件描述符编号
字母(r / w / u) 访问模式:读/写/读写
FD 编号 标准含义
0 stdin(标准输入)
1 stdout(标准输出)
2 stderr(标准错误输出)
3 及以上 进程打开的普通文件、日志、socket、管道等
  • 特殊 FD 类型(没有数字)

字段 含义
cwd 当前工作目录,说明进程在这个目录下运行
rtd 进程的根目录,大多数情况下是 /,容器里可能是别的 rootfs
txt 可执行文件本体
mem 内存映射(mmap)文件,进程加载到内存中的库 / jar / so 文件

lsof 文件 TYPE 字段详细解释

文件类型 全称 含义 常见场景
REG Regular file 普通文件 日志、配置、可执行程序等
DIR Directory 目录 进程访问的目录,例如当前工作目录
CHR Character special file 字符设备文件 /dev/null/dev/tty、串口、键盘等
BLK Block special file 块设备文件 /dev/sda、硬盘、分区等
FIFO Named pipe 命名管道 Linux 进程间通信,如 Nginx 和 PHP-FPM 的通信
sock Socket 套接字(Unix 域 socket) /var/run/docker.sock、MySQL UNix socket
IPv4 IPv4 socket IPv4 网络连接/监听 TCP *:80UDP 127.0.0.1:53
IPv6 IPv6 socket IPv6 网络连接/监听 TCP [::]:22
unix Unix domain socket 本地进程通信 /run/systemd/journal/stdout