lsof —— 谁占着这个文件或端口

运维工具手册 02-进程与网络诊断 4.0 KB 原文

lsof —— 谁占着这个文件或端口

分类:02 进程与网络诊断 适用:Linux / macOS(Linux 上读 /proc/*/fd,权限要求高) 一句话:lsof = list open files。Linux 里"一切皆文件",所以它也能查端口、socket、设备。

1. 它解决什么问题

  • 端口被占用,起不来服务,是哪个进程?
  • 文件删了但磁盘没释放(deleted 句柄)。
  • 某个目录被哪个进程占着,导致 umount 失败。
  • 进程打开了多少文件,是否触及 ulimit -n。

2. 安装

apt install -y lsof
dnf install -y lsof
apk add lsof

3. 按端口 / 网络查

lsof -i :80                  # 谁在用 80 端口
lsof -i :80 -sTCP:LISTEN     # 只看监听
lsof -i tcp                  # 所有 TCP
lsof -i udp:53               # UDP 53
lsof -i @10.0.0.5            # 与某 IP 的所有连接
lsof -i @10.0.0.5:3306       # 指定 IP + 端口
lsof -i -n -P                # -n 不解析主机名,-P 不解析端口名(快很多)
lsof -i 4                    # 只 IPv4
lsof -i 6                    # 只 IPv6
lsof -a -p 1234 -i           # 某进程的网络连接(-a 表示条件 AND)

不加 -a 时多个条件是 OR,这是 lsof 最常见的误用。

4. 按进程 / 用户 / 文件查

lsof -p 1234                 # 该进程打开的所有文件
lsof -p 1234 -a -d 1,2       # 只看 fd 1、2
lsof -c nginx                # 按命令名(前缀匹配,<=9 字符)
lsof -c nginx -c php         # 多个 OR
lsof -u nginx                # 按用户
lsof -u ^root                # 排除 root
lsof /var/log/nginx/access.log   # 谁打开了这个文件
lsof +D /data                # 递归查目录下所有被打开的文件(慢)
lsof +L1                     # 链接数为 0 的文件(已删除但被占用)
lsof /dev/sdb                # 谁占着设备(umount 失败时用)
lsof -t /path                # 只输出 PID,便于管道

5. 输出怎么读

COMMAND  PID  USER   FD      TYPE   DEVICE  SIZE/OFF     NODE NAME
nginx   1234  root  cwd       DIR    253,0      4096        2 /
nginx   1234  root  txt       REG    253,0   1256448   131074 /usr/sbin/nginx
nginx   1234  root    1w      REG    253,0 104857600   524301 /var/log/nginx/access.log
nginx   1234  root    6u     IPv4  1234567       0t0      TCP *:80 (LISTEN)
列 含义
FD 文件描述符。cwd 当前目录、txt 程序本体、mem 内存映射、数字为 fd
FD 后缀 r 读、w 写、u 读写
TYPE REG 普通文件、DIR 目录、IPv4/IPv6 网络、CHR 字符设备、FIFO、unix
DEVICE 设备号(主,次)
SIZE/OFF 文件大小或偏移
NODE inode 号
NAME 路径或连接四元组

6. 实战场景

6.1 端口占用

lsof -i :8080 -sTCP:LISTEN
# 或
ss -lntp | grep :8080
fuser -n tcp 8080            # 更轻量

处理:确认进程归属,systemctl stop 或 kill,别直接杀不认识的进程。

6.2 文件已删但磁盘没释放

lsof +L1
# 或
lsof | grep -i deleted
java  1234  app  3w  REG  253,0  8589934592  524301 /data/app.log (deleted)

处理方式(不要重启服务):

# 方式一:清空该 fd(推荐,进程继续写,空间释放)
: > /proc/1234/fd/3
# 方式二:重启/重载该进程
systemctl reload <service>

df 显示满但 du 算不出来,99% 是这个原因。

6.3 umount 失败:设备忙

lsof +f -- /mountpoint       # 或
lsof /mountpoint
fuser -vm /mountpoint

常见占用者:shell 的 cwd、tail -f 的日志、nfs 客户端。

6.4 检查文件句柄是否耗尽

lsof -p <PID> | wc -l
cat /proc/<PID>/limits | grep 'open files'
ls /proc/<PID>/fd | wc -l

报 Too many open files 时,先确认是泄漏还是限额太小。泄漏特征:fd 数持续单调上涨。

按类型统计泄漏源:

lsof -p <PID> | awk '{print $5}' | sort | uniq -c | sort -nr

6.5 找出日志被谁在写

lsof /var/log/app/*.log
# 迁移日志目录前必须确认没有进程持有旧 inode

7. 常见坑

  1. 性能极差:lsof 全量扫描会遍历所有进程的 fd,机器上进程多时可能跑几十秒甚至卡顿。加 -n -P,并尽量带条件。
  2. 必须 root 才看得全:普通用户只能看到自己进程的 fd,会得出"没人占用"的错误结论。
  3. 多条件是 OR:lsof -p 1234 -i 是"该进程 OR 有网络连接",要 AND 必须加 -a。
  4. -c 只匹配前 9 个字符:长命令名要用 -c 配合 grep 或直接用 pgrep -f。
  5. deleted 文件要看 fd 号:不同线程/fd 指向同一 inode,清一个不一定够。
  6. 容器内看不到宿主机:命名空间隔离,需在宿主机查,或用 nsenter。
  7. NFS 上 lsof 可能挂住:网络存储异常时 lsof 会一起卡,先用 -b 避免阻塞调用。
  8. lsof -i 输出会解析域名:慢,加 -n。
  9. +D 递归很慢:大目录用 find + lsof 组合更可控。

8. 速查表

lsof -i :<port>                  # 端口占用
lsof -i :<port> -sTCP:LISTEN     # 仅监听
lsof -i @<ip>:<port>             # 指定连接
lsof -p <PID>                    # 进程打开的文件
lsof -u <user>                   # 按用户
lsof /path/to/file               # 谁打开了文件
lsof +D /dir                     # 目录下被打开的文件
lsof +L1                         # 已删除仍占用
lsof -t /path                    # 只要 PID
lsof -a -p <PID> -i              # AND 组合
lsof -nP -i                      # 不解析,速度快

# 释放已删文件
: > /proc/<PID>/fd/<N>

# 替代
ss -lntp                         # 端口
fuser -vm /mount                 # 设备占用