1. 为什么每个Linux运维都应该掌握lsof
第一次在服务器上排查端口冲突时,我盯着netstat输出的杂乱信息束手无策,直到前辈演示了用lsof -i :8080直接锁定进程的魔法。这个1989年由Victor A. Abell开发的工具(全称List Open Files),经过30余年的进化已成为Linux系统诊断的"瑞士军刀"——它不仅能列出所有打开的文件描述符,更能穿透抽象层直击系统资源占用的真相。
在容器化与微服务架构普及的当下,服务器上往往同时运行着数百个进程。上周我们某个K8s节点突发磁盘I/O瓶颈,正是通过lsof +D /var/log快速定位到某个失控的日志收集器。与ps、netstat等工具相比,lsof的核心优势在于其全局视角:
- 跨命名空间可见性:能穿透容器隔离看到宿主机层面的真实资源占用
- 资源关联分析:通过文件描述符关联进程、网络连接、磁盘文件等对象
- 实时性:直接读取内核的
/proc信息,无需额外守护进程
以下是生产环境中lsof的典型应用场景:
bash复制# 查看被删除但仍被进程占用的文件(释放磁盘空间)
$ lsof -n | grep deleted
# 分析某个容器的所有网络活动
$ lsof -p $(docker inspect --format='{{.State.Pid}}' nginx) -i
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心参数深度解析
2.1 基础查询模式
lsof的输出字段看似简单,但暗藏玄机。以这条典型输出为例:
bash复制python3 1894 ubuntu 3u IPv4 42356 0t0 TCP 10.0.0.1:5678->10.0.0.2:http (ESTABLISHED)
各字段含义如下:
python3:进程名称1894:进程PIDubuntu:进程所属用户3u:文件描述符3(u表示读写模式)IPv4 42356:inode编号TCP...:网络连接详情
常用过滤组合:
bash复制# 按用户+协议过滤
$ lsof -u www-data -i TCP
# 显示指定进程打开的文件(包括内存映射)
$ lsof -p 1894 -a +fg
2.2 高级过滤技巧
多数人只用到-i参数查端口,其实过滤条件可以更精确:
bash复制# 查找所有ESTABLISHED状态的SSH连接
$ lsof -i TCP:ssh -s TCP:ESTABLISHED
# 查看修改时间超过7天的日志文件
$ lsof -t /var/log/* +MT7
特殊场景下的组合拳:
bash复制# 找出占用磁盘IO的前10个进程
$ lsof +fg -Fn | awk '/^p/ {pid=$2} /^n.*REG/ {print pid,$0}' | sort -k5 -nr | head
3. 生产环境实战案例
3.1 磁盘空间异常排查
某次报警显示/var分区使用率95%,但du -sh统计只有50%占用。使用lsof发现被删除的日志文件:
bash复制$ lsof +L1 /var | grep deleted
httpd 1234 root 5r REG 8,1 2G 123456 /var/log/access.log (deleted)
处理方案:
bash复制# 方案1:重启进程(临时)
systemctl restart httpd
# 方案2:清空文件内容(保留句柄)
: > /proc/1234/fd/5
3.2 网络连接分析
当netstat显示某端口处于CLOSE_WAIT状态时:
bash复制$ lsof -i :5432 -s TCP:CLOSE_WAIT
postgres 5678 dbuser 4u IPv6 112233 0t0 TCP db01:5432->app01:38492 (CLOSE_WAIT)
这通常意味着应用未正确关闭连接,需要检查:
- 应用连接池配置
- 数据库
tcp_keepalive参数 - 防火墙可能拦截了FIN包
4. 性能优化与安全实践
4.1 降低系统负载的技巧
在大规模服务器上,直接运行lsof可能导致高负载:
bash复制# 错误示范(扫描全部进程)
$ lsof > /tmp/output
# 正确做法(指定目录或PID)
$ lsof -p $(pgrep nginx) +f -- /var
推荐的安全检查流程:
- 先用
-t只输出PID - 结合
/proc/<pid>/fd人工验证 - 最后用完整模式确认
4.2 容器环境专用命令
在Docker/K8s环境中排查问题时:
bash复制# 查看容器内所有网络连接
$ lsof -p $(docker inspect --format='{{.State.Pid}}' nginx) -nP -i
# 找出挂载卷的写操作
$ lsof +fg -- $(docker volume inspect my-vol --format='{{.Mountpoint}}')
5. 常见陷阱与解决方案
5.1 权限问题处理
普通用户运行lsof可能看不到完整信息:
bash复制# 看不到其他用户的进程
$ lsof -i :80
lsof: no permission to look at 1234
# 解决方案
$ sudo lsof -i :80
# 或预先授权
$ sudo setcap cap_dac_read_search+ep /usr/sbin/lsof
5.2 输出解析技巧
处理lsof输出时建议:
bash复制# 使用-F生成可解析格式
$ lsof -F pcfn -i :3306
# 结合jq处理JSON输出
$ lsof -F json -i | jq '.processes[] | select(.command == "nginx")'
我曾用以下命令找出某个文件被哪个进程锁定:
bash复制$ lsof /var/lib/mysql/ibdata1 | awk 'NR>1 {print $2}' | xargs -I{} grep "lock" /proc/{}/status
记住:lsof的输出永远反映的是瞬时状态。对于高频变化的场景(如负载均衡器连接),建议配合watch命令使用:
bash复制watch -n1 'lsof -i :8080 -s TCP:ESTABLISHED -F pcn'
