这个Linux命令太牛了!lsof让我在生产环境救火无数次
最近在群里看到有小伙伴问,服务器上某个端口被占用了,但是不知道是哪个进程在用,怎么办?还有人说磁盘空间明明删除了大文件,但是df显示空间还是没释放。这些问题其实都可以用一个神器来解决——lsof。
说实话,我刚开始的时候,对lsof这个命令也是一知半解的。记得有一次生产环境出问题,nginx启动不了,报端口被占用,当时我还傻乎乎地用ps aux | grep去找进程,结果找了半天也没找到。后来一个同事过来,直接一个lsof -i:80就把问题定位了(当然ss和netstat也可以),那一刻我才意识到这个命令的强大。
ps:下次面试官问如何查看端口占用的时候,就别只说一个netstat了。还有lsof和ss可以用!!!
lsof到底是什么
lsof的全称是"list open files",翻译过来就是列出打开的文件。但是在Linux系统中,一切皆文件,所以lsof能做的事情远比你想象的要多。网络连接是文件,设备是文件,管道也是文件,所以lsof实际上是一个超级强大的系统诊断工具。
我经常跟新人说,lsof就像是系统的"透视镜",能让你看到系统内部正在发生什么。哪个进程打开了哪些文件,哪个端口被哪个程序占用,哪些文件被删除了但还在被进程使用着,这些信息lsof都能告诉你。
基础用法先搞明白
最简单的用法就是直接输入lsof,不过这样会输出所有打开的文件,信息量太大了,一般我们不会这么用。
lsof
输出的每一行代表一个打开的文件,包含了这些信息:
- COMMAND:进程名称
- PID:进程ID
- USER:用户名
- FD:文件描述符
- TYPE:文件类型
- DEVICE:设备号
- SIZE/OFF:文件大小或偏移量
- NODE:inode号
- NAME:文件名或网络连接信息
刚开始看这些输出可能会觉得眼花缭乱,但是用多了就习惯了。
网络相关的妙用
查看端口占用情况
这个功能我用得最多,特别是在部署新服务的时候。
# 查看80端口被哪个进程占用
lsof -i:80
# 查看所有TCP连接
lsof -i tcp
# 查看所有UDP连接
lsof -i udp
# 查看指定IP和端口的连接
lsof -i@192.168.1.100:22
有一次我们的Redis服务启动不了,报6379端口被占用,但是用systemctl status redis看显示是停止状态的。用lsof -i:6379一查,发现有个僵尸进程还占着端口,kill掉就解决了。
查看网络连接状态
# 查看所有网络连接
lsof -i
# 查看指定状态的连接
lsof -i -sTCP:LISTEN # 查看监听状态的TCP连接
lsof -i -sTCP:ESTABLISHED # 查看已建立的TCP连接
这个在排查网络问题的时候特别有用。比如怀疑某个服务连接数过多,就可以用这个命令来确认。
进程相关的用法
查看进程打开的文件
# 查看指定PID打开的文件
lsof -p 1234
# 查看指定进程名打开的文件
lsof -c nginx
# 查看指定用户打开的文件
lsof -u www-data
我记得有次排查一个Java应用内存泄漏的问题,就是用lsof -p查看进程打开的文件数量,发现文件句柄数量一直在增长,最后定位到是代码里没有正确关闭文件流。
查看文件被哪些进程使用
# 查看指定文件被哪些进程打开
lsof /var/log/nginx/access.log
# 查看指定目录下的文件被哪些进程使用
lsof +D /var/log/
这个在你想删除某个文件但是提示文件被占用的时候特别有用。
文件系统相关的神操作
找出被删除但未释放的文件
这个功能简直是救命稻草!经常遇到这种情况:明明删除了大文件,但是df显示磁盘空间没有释放。这通常是因为文件被删除了,但还有进程在使用这个文件。
# 查找被删除但未释放的文件
lsof | grep deleted
# 或者更精确的查找
lsof +L1
有一次我们的服务器磁盘空间告警,我删除了几个GB的日志文件,但是空间还是没释放。用lsof | grep deleted一查,发现有个进程还在往已删除的日志文件里写数据。重启了那个进程,空间立马就释放了。
查看挂载点使用情况
# 查看指定挂载点被哪些进程使用
lsof /mnt/data
# 查看所有挂载点的使用情况
lsof -f -- /dev/sda1
在卸载文件系统的时候,如果提示设备忙,就可以用这个命令找出是哪些进程在使用。
实战案例分享
案例1:解决端口冲突问题
前段时间部署一个新的Web服务,配置的是8080端口,但是启动的时候一直报错说端口被占用。用netstat看了半天也没找到问题。
lsof -i:8080
结果发现是Jenkins占用了这个端口,但是Jenkins配置文件里写的是8081,很奇怪。后来发现是Jenkins的某个插件启动了一个额外的服务占用了8080端口。
案例2:排查文件句柄泄漏
有个Python应用运行一段时间后就会报"Too many open files"的错误。怀疑是文件句柄泄漏。
# 先找到进程PID
ps aux | grep python_app
# 查看进程打开的文件数量
lsof -p 12345 | wc -l
# 查看具体打开了哪些文件
lsof -p 12345
发现进程打开了大量的临时文件,而且数量一直在增长。最后定位到是代码里创建临时文件后没有正确清理。
案例3:磁盘空间异常问题
服务器磁盘使用率突然飙升到95%,但是找不到大文件。后来用lsof发现有个日志轮转脚本有问题。
# 查找大文件
lsof | awk '$7 ~ /^[0-9]+$/ && $7 > 1000000 {print $2, $7, $9}' | sort -k2 -nr
发现有个进程打开了一个几GB的文件,但是这个文件在文件系统里找不到,原来是被删除了但进程还在写入。
高级用法和技巧
组合条件查询
lsof支持多种条件的组合,默认是OR关系,可以用-a参数改为AND关系。
# 查看用户www-data打开的网络连接(OR关系)
lsof -u www-data -i
# 查看用户www-data打开的网络连接(AND关系)
lsof -a -u www-data -i
输出格式控制
# 不显示主机名,直接显示IP
lsof -n -i
# 不显示端口名,直接显示端口号
lsof -P -i
# 组合使用
lsof -nP -i:80
这个在脚本里特别有用,因为解析主机名和端口名会比较慢。
持续监控
# 每2秒刷新一次
lsof -r 2 -i:80
# 监控到没有输出就退出
lsof +r 1 -i:80
这个功能在调试网络连接问题的时候很有用,可以实时看到连接的变化。
性能优化小贴士
lsof虽然强大,但是在大型系统上运行可能会比较慢,特别是不加任何参数的时候。有几个优化技巧:
- 尽量使用具体的参数,避免全量扫描
- 使用-n和-P参数避免DNS和端口名解析
- 在脚本中使用时,考虑缓存结果
# 这样比较快
lsof -nP -i:80
# 这样会很慢
lsof | grep :80
常见问题和注意事项
使用lsof的时候有几个坑需要注意:
- 权限问题:有些信息需要root权限才能看到
- 系统负载:在高负载系统上运行lsof可能会影响性能
- 输出解读:要理解各个字段的含义,特别是FD字段
FD字段的含义比较复杂:
- cwd:当前工作目录
- txt:程序代码
- mem:内存映射文件
- 数字:文件描述符号
- r、w、u:读、写、读写模式
与其他工具的配合
lsof经常需要和其他工具配合使用:
# 配合ps使用
lsof -p $(pgrep nginx)
# 配合netstat对比
netstat -tlnp | grep :80
lsof -i:80
# 配合awk处理输出
lsof -i | awk '/ESTABLISHED/ {print $2}' | sort | uniq -c
我个人比较喜欢把lsof和其他工具组合起来写成小脚本,这样排查问题的时候效率会高很多。
总结
lsof真的是一个被低估的神器,掌握了它基本上可以解决大部分文件和网络相关的问题。从端口占用到文件句柄泄漏,从磁盘空间异常到网络连接排查,lsof都能派上用场。
当然,工具只是工具,关键还是要理解系统的工作原理。lsof能告诉你现象,但是要分析出根本原因,还是需要对系统有深入的理解。
记住,运维这个工作很多时候就是在和时间赛跑,系统出问题的时候,每一分钟的延迟都可能造成巨大的损失。而lsof这样的工具,就是你手中最锐利的武器。不过话说回来,再好的工具也需要不断的实践才能真正掌握。我建议大家可以在自己的测试环境里多折腾折腾,比如故意制造一些端口冲突、文件句柄泄漏的场景,然后用lsof来排查。这样真正遇到问题的时候,你就不会手忙脚乱了。
最后想说的是,lsof的输出信息比较敏感,包含了很多系统内部的信息。在分享排查过程或者截图的时候,记得做好脱敏处理,避免泄露重要的系统信息。
如果这篇文章对你有帮助,别忘了点赞转发支持一下!想了解更多运维实战经验和技术干货,记得关注微信公众号@运维躬行录,领取学习大礼包!!!我会持续分享更多接地气的运维知识和踩坑经验。让我们一起在运维这条路上互相学习,共同进步!
公众号:运维躬行录
个人博客:躬行笔记