以下是我解決Too many open files異常時學習的知識的理解和總結,如有不正確指出,敬請指出!
此問題中文搜索雷同,你可以嘗試以下關鍵字:"file descriptor leak" "stackoverflow" "how to solve open files exception“等。
一下是我的一些總結,或許對您有所幫助!
1.fd
fd is short for file descriptor
在linux環境下,任何事物都以文件的形式存在,通過文件不僅僅可以訪問常規數據,還可以訪問網絡連接和硬件,
應用程序就是通過fd識別該文件/設備/服務..
你可能需要自行了解更多fd的定義及功能知識。
2.lsof
linux下的命令, 全稱:list system open files
第1節說linux所有資源都是以file形式的,所以這個lsof命令是我們查看系統資源占用情況的得力工具。排查linux下各種資源耗盡,異常
等問題都可以使用它。中文能找到的幾乎都是這種http://www.cnblogs.com/ggjucheng/archive/2012/01/08/2316599.html,以下為引用:
在終端下輸入lsof即可顯示系統打開的文件,因為 lsof 需要訪問核心內存和各種文件,所以必須以 root 用戶的身份運行它才能夠充
地發揮其功能。直接輸入lsof部分輸出為:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
init 1 root cwd DIR 8,1 4096 2 /
init 1 root rtd DIR 8,1 4096 2 /
init 1 root txt REG 8,1 150584 654127 /sbin/init
udevd 415 root 0u CHR 1,3 0t0 6254 /dev/null
udevd 415 root 1u CHR 1,3 0t0 6254 /dev/null
udevd 415 root 2u CHR 1,3 0t0 6254 /dev/null
udevd 690 root mem REG 8,1 51736 302589 /lib/x86_64-linux-gnu/libnss_files-2.13.so
syslogd 1246 syslog 2w REG 8,1 10187 245418 /var/log/auth.log
syslogd 1246 syslog 3w REG 8,1 10118 245342 /var/log/syslog
dd 1271 root 0r REG 0,3 0 4026532038 /proc/kmsg
dd 1271 root 1w FIFO 0,15 0t0 409 /run/klogd/kmsg
dd 1271 root 2u CHR 1,3 0t0 6254 /dev/null
每行顯示一個打開的文件,若不指定條件默認將顯示所有進程打開的所有文件。
lsof輸出各列信息的意義如下:
COMMAND:進程的名稱 PID:進程標識符
USER:進程所有者
FD:文件描述符,應用程序通過文件描述符識別該文件。如cwd、txt等 TYPE:文件類型,如DIR、REG等
DEVICE:指定磁盤的名稱
SIZE:文件的大小
NODE:索引節點(文件在磁盤上的標識)
NAME:打開文件的確切名稱
你可能需要自行了解lsof命令使用細節
3. fix too many open files excepiton(POSIX)
a. 網上尤其使用baidu搜出來的答案幾乎全是“ulimit -n”查看最大能打開的fd的限制值,通常是 1024(意思是最多能打開1024個),然後
使用“ulimit -n 4096”調大該限制。這裡先下個結論,這個解決方案是碰運氣式的,詳情且看下面分解。
b. too many open files 出現的原因:
》第1節有說,linux(POSIX)所有存在都是以file形式表示的,所以引起這個異常的原因(幾乎)就是你打開了太多‘files’,超過了限制。
那a中調大限制的方法明顯可以用啊。下面這段話給出了不推薦這樣做的理由:
摘自http://oroboro.com/file-handle-leaks-server/
Wrong Answers, Myths and Bad Ideas
Raise the file handle limit
One common answer to this problem is to just raise the limit of open file handles and then restart the server every
day or every few hours.
This will delay the problem but likely will not fix it. It is possible that your program is not leaking and has a
legitimate need to hold a large number of file handles. But if your program is designed correctly there usually isn’t
a need to keep a large number of handles open – even if you have thousands of simultaneous connections. We’ll discuss
some methods of managing that later.
If this was a good idea the operating system would already come configured with a higher file descriptor limit. If
this was necessary, Apache would require you to up this limit before running.
》原因(大多數時候)
The problem is almost certainly that you are leaking file handles. That is, handles are being opened, and after you are
done with them they are not closed.
Leaked file handles can come from many sources, not just open files. Some common sources are:Sockets,Pipes,Database
connections,Windows HANDLES,Files.
c. 如何排查及修復(重點)
》當不滿足於“ulimit -n 4096”的解決方案,深入想要分析原因時,搜索到的分析方法也大同小異,大多和lsof命令相關,以下羅列一些;
=.To find out PID for mysqld process, enter: pidof mysqld #pidof命令是找出進程的id號,如pidof java找到Java進程的id號
=.List File Opened By a PID:lsof -p ${pid} #-p 參數是 --pid的意思, 如 lsof -p 10086是打印10086進程的所有open files
或者 ls /proc/${pid}/fd #和上行一樣,查看該進程打開的files
=.List File Descriptors in Kernel Memory
sysctl fs.file-nr #結果:fs.file-nr = 2688 0 379264
=> The number of allocated file handles
=> The number of unused-but-allocated file handles
=> The system-wide maximum number of file handles
sysctl fs.file-max #結果是能打開的最大files數量
=.查看某個用戶下打開的files: lsof -u jboss
=.和計數器結合起來,計算打開的文件數量,如:lsof -p 10086|wc -l, ls -alt /etc/10086/fd|wc -l等等。
這些分析方法大多是利用lsof配合參數和管道命令,或者是統計/proc/${pid}/fd目錄,來分析你的目標的openfiles情況。
》困惑
=. lsof -u root |wc -l 結果是2223, 而ulimit -n 結果是1024, 為什麼root用戶當前的open files還要比limit大? 這個如果不清楚那
分析就沒意義了,因為你就是要解決open file limit問題的,結果root當前運行時就打開了比limit還多的files.
=. lsof -p 54552|wc -l 結果是658,54552是我java的進程pid, 而ll /proc/54552/fd |wc -l,結果卻是358,為什麼統計同一個進程當前
的open files數量卻有如此大的差異? 以哪個為准,和ulimit -n的值有有什麼關系?
=. 先解釋第2點,lsof will also give you memory mapped .so-files - which technically isn't the same as a file handle the
application has control over. /proc/<pid>/fd is the measuring point for open file descriptors。 意思是說lsof的結果包含
memory mapped .so-files,這些在原理上並不是一般的應用程序控制的fd。 而/proc/<pid>/fd目錄很好的反映了fd的open情況。
適當修改下lsof: lsof -p <pid> | grep -v mem | egrep -v '^COMMAND PID' | wc -l,這樣就等同於/proc/<pid>/fd下統計情況。
=. 是第2點的問題引起了第1點?使用lsof -u root |grep -v mem | egrep -v '^COMMAND PID' | wc -l, 結果是 1221,還是大於limit.
就是說root用戶當前open 1221 files是確定定, root 的 files limit是1024也是確定的, 而造成more than limit究竟為何:其實是
limit這個限制針對的對象,最終找出是這樣的:because the limit is on a per-process base and not per-user 。 limit限制是基於
一個進程而言的(該用戶擁有的進程)並非用戶。 就是ulimit -n是1024的意思是由root用戶執行的某個進程最多只能打開1024個文件,
並非root總共只能打開1024個。
=. sysctl fs.file-max 我的結果是379264,這個數字則是kenel內核總共能支持的open files數量。這個是不能改變的。
》解決
=. 至此可以解釋為啥放大limit是碰運氣式的,畢竟一個process正常情況下同時要打開超過1024個files還是比較少見的。
=. 如果需分析leak或者查看open fiels的細節, 則應從pid粒度著手,而不要被user迷惑。
lsof -p <pid> | grep -v mem | egrep -v '^COMMAND PID'
或者對/proc/<pid>/fd 目錄分析。
=. uprize limit
即使需要擴大limit限制,實際上大多是os上簡單的“ulimit -n 4096”是行不通的,操作系統不允許。 以下兩種方式供參考
Raising the Global Limit。Edit /etc/sysctl.conf and add the following line:fs.file-max = 65536
Apply the changes with:sudo sysctl -p /etc/sysctl.conf
Raising the per-User Limit.
&Edit as root the following system configuration file: % sudo vi /etc/security/limits.conf
&Modify the values for nuxeo user (we assume here JBOSS is launched with the sytem user "nuxeo")
nuxeo soft nofile 4096
nuxeo hard nofile 8192
If you want to raise the limits for all users you can do instead:
* soft nofile 4096
* hard nofile 8192
&Edit /etc/pam.d/su: sudo vi /etc/pam.d/su
&Uncomment the line:
session required pam_limits.so
&Once you save file, you may need to logout and login again
d.總結
擴大open files數量限制的操作可以起效,但在此之前相比你應該也對為何出錯會感興趣吧,不妨先分析一下喽。
以上總結中的觀點是網上各處搜羅及個人理解所得,如有誤,請諒解指正。