转载需注明出处:https://www.codelast.com/

前几天发现服务器上的一个JAVA程序表现很不对劲,运行起来特别“慢”,仔细一看程序的日志,发现里面有Exception抛出,提示“too many open files”,由于无论是读写文件还是创建网络连接,都需要占用文件描述符(fd),于是怀疑是服务器上的某个程序占用的资源没有释放,达到了系统设置的上限从而导致程序异常。

『1』查看系统open files限制
可以用下面的命令来查看:

ulimit -n

文章来源:https://www.codelast.com/
『2』查看系统里占用fd最多的进程
用root用户运行下面的命令,可以打印出每个进程占用的fd数量(从大到小):

lsof -n | awk '{print $2}' | sort | uniq -c | sort -nr | more

部分输出类似于:

  12520 16485
    125 7054
     69 20120
     69 15291
     65 20113
     65 15284
     57 19774
......
第一列是占用的fd数量,第二列是进程的pid。最可疑的显然是占用数量最多的头几个进程。
文章来源:https://www.codelast.com/
『3』查找出有问题的程序到底在干什么
为便于排查,先从第一个进程查起,如果第一个进程就定位到了问题,那么就不用查后面的了。
ll /proc/16485/fd
部分输出类似于:

lrwx------ 1 root root 64 Aug 24 11:51 9992 -> socket:[547491750]
lrwx------ 1 root root 64 Aug 24 11:51 9993 -> socket:[547491752]
lrwx------ 1 root root 64 Aug 24 11:51 9994 -> socket:[547491753]
lrwx------ 1 root root 64 Aug 24 11:51 9995 -> socket:[547491754]
lrwx------ 1 root root 64 Aug 24 11:51 9996 -> socket:[547491755]
lrwx------ 1 root root 64 Aug 24 11:51 9997 -> socket:[547491756]
lrwx------ 1 root root 64 Aug 24 11:51 9998 -> socket:[547491757]
lrwx------ 1 root root 64 Aug 24 11:51 9999 -> socket:[547491758]
其实这个输出列表真的很长,只不过由于篇幅的原因,这里只粘贴上来了一小部分。从这个输出信息中,貌似一眼看不出来该程序占用的那些fd到底是在进行网络通信呢,还是在干嘛,于是我们可以用另一种方法:
lsof -p 16485
还是只展示一小部分输出信息:

java    16485 root *500u  IPv4          547501909        0t0       TCP abc.abc.com:57700->test1.abc.com:50010 (CLOSE_WAIT)
java    16485 root *501u  IPv4          547501910        0t0       TCP abc.abc.com:targus-getdata->test2.abc.com:50010 (CLOSE_WAIT)
java    16485 root *502u  IPv4          547501911        0t0       TCP abc.abc.com:59671->test3.abc.com:50010 (CLOSE_WAIT)
java    16485 root *503u  IPv4          547501939        0t0       TCP abc.abc.com:55784->test4.abc.com:50010 (CLOSE_WAIT)
java    16485 root *504u  IPv4          547501942        0t0       TCP abc.abc.com:netsupport->test5.abc.com:50010 (CLOSE_WAIT)
java    16485 root *505u  IPv4          547501995        0t0       TCP abc.abc.com:58486->test6.abc.com:50010 (CLOSE_WAIT)
java    16485 root *506u  IPv4          547501996        0t0       TCP abc.abc.com:38031->test7.abc.com:50010 (CLOSE_WAIT)
由于我这里的test*.abc.com是Hadoop集群的服务器,于是我马上就明白了:我的程序里有读写HDFS文件的操作,所以很可能是读写时没有close资源导致占用的fd持续增加。
于是我去检查了一下代码,果然在用BufferedReader频繁读取HDFS文件的时候,用完了也没有把它close(),于是fix之后赶紧试验了一下,问题解决!
[原创] 解决Linux系统上由于程序占用的文件描述符(file descriptor)过多导致的异常问题
Tagged on:         

发表评论

电子邮件地址不会被公开。 必填项已用*标注