lsof的错误使用场景和查看打开文件数的正确方法

2019-08-20 19:07:36

参考地址 lsof的错误使用场景和查看打开文件数的正确方法

前两天在调查一个"too many open files"的问题,和之前一样,自然而然的用到了lsof,加上一堆漂亮的命令组合来查看哪些程序打开了很多文件。

lsof | awk '{print $2}' | uniq -c | sort -rnk1 | head
啪的一敲回车,很顺利的定位到几个docker内运行的Java进程排在最前,分别都是几万的结果,怀疑是不是docker的问题。很不幸的是,这个调查结果是错的。。。

先说真实的情况,后面再展开分析:

  • 真实的元凶,是一个并没有在上面的命令结果中排在最前面的进程,由于编程的bug,不断的打开同样的文件没有关闭,真正的占用了很多fd。

  • CentOS 7中的lsof是按PID/TID/file的组合显示结果的,上面lsof组合命令显示“打开”了很文件的进程,只是因为进程运行了N个线程,而每个线程都“用到”了M个jar包,并且FD一栏分别为mem和具体fd号都分别显示了一次,就出现了2*N*M——上万条结果。

结论一:
使用lsof查看fd数是不正确的。
尽管网上很多文章教人这么用,但实际上不应该这么做。

这是因为:

  1. lsof的结果包含了并非以fd形式打开的文件,比如用mmap方式访问文件(FD一栏显示为mem),实际并不占用fd。
    其中包括了像.so这样的文件。从结果看.jar文件也是以FD为mem和具体fd编号分别打开了一次。

  2. CentOS 7的lsof(我这里lsof -v的版本号是4.87)是按PID/TID/file的组合对应一行,不是一行一个fd。同一个进程如果多个线程访问同一个文件通常只需要打开一次、占用一个fd,但在lsof中就显示多行。
    如果用lsof -p <pid>,则不按TID显示,结果数少很多。但仍包含了没有使用fd的文件。

结论二:
准确的查看fd使用总数的命令是:
cat /proc/sys/fs/file-nr
或者(结果多的时候运行需要一段时间)
sudo find /proc -print | grep -P '/proc/\d+/fd/'| wc -l

注意如果用
sudo ls -l /proc/*/fd/* | wc -l
结果是不对的,比上面的命令返回结果少很多。原因是实际执行是会把*扩充成具体的目录作为参数,而这个参数长度有限制。

查看具体一个进程号的fd数量是:
ls -l /proc/<pid>/fd | wc -l

查看哪个进程使用的fd最多(再来一路组合拳):
sudo find /proc -print | grep -P '/proc/\d+/fd/'| awk -F '/' '{print $3}' | uniq -c | sort -rn | head

但还要注意上面的命令返回的是系统的fd使用情况,而ulimit的配置是针对单用户的,两者是有区别的。

结论三:
不同版本的lsof输出结果不同。

CentOS 7.3的lsof (我这里是4.87),按PID/TID/file显示。CentOS 6.6的lsof(我这里是4.82),按PID/file显示。结果数相差很大。但lsof -p <pid>的结果是一致的。
这在容器OS版本和宿主机OS版本不同时就需要注意了,在容器里和宿主机上用lsof查看同一进程的结果会很不同,我碰到的就是这种情况。

</br>


之前使用lsof(或lsof -n不解析协议主机名)的相关命令和真实意义:
打开文件总记录数(没太大意义):
lsof | wc -l

lsof -n | wc -l #不解析协议主机名

查看哪些pid使用文件数量最多(其实也没有太大意义):
lsof | awk '{print $2}' | uniq -c | sort -rnk1 | head



  • 2020-12-07 22:06:13

    System Extension Blocked - warning

    After upgrading your macOS computer to High Sierra 10.13.4 or higher (starting in April 2018), you may see a message about a System Extension Blocked. At Williams we have seen this warning appear for these programs:

  • 2020-12-08 08:57:12

    win10上使用win-sshfs

    首先在GitHub上下载DokanSetup-1.0.5.1000和WinSSHFS-1.6.1.13-devel 注意:Dokan不能使用最新的版本,得使用1.0.5版本。要不win-sshfs会报Dokan版本错误的问题。(win10版本)

  • 2020-12-08 11:51:54

    Ubuntu安装Node.js和npm

    Node.js是基于Chrome的JavaScript构建的跨平台JavaScript运行时环境,npm是Node.js的默认程序包管理器,也是世界上最大的软件注册表。本篇文章展示了三种在Ubuntu 20.04服务器上安装Node.js和npm的方法。

  • 2020-12-08 17:13:57

    nvm卸载、安装node和npm

    1、node.js、nvm、 npm (1)在cmd中输入`where node`找到node长须所在位置进行删除 (2)确保计算机-环境变量删除相关引用 (3)在cmd中输入`node -v` ,得到以下结果,删除成功

  • 2020-12-08 17:23:36

    Window下完全卸载删除Nodejs

    1.从卸载程序卸载程序和功能。 2.重新启动(或者您可能会从任务管理器中杀死所有与节点相关的进程)。 3.寻找这些文件夹并删除它们(及其内容)(如果还有)。根据您安装的版本,UAC设置和CPU架构,这些可能或可能不存在:

  • 2020-12-09 08:48:45

    nodejs版本以及其对应的npm版本

    正在寻找某个大版本的最新版? Node.js 10.x Node.js 8.x Node.js 6.x Node.js 4.x Node.js 0.12.x Node.js 0.10.x 所有版本