一、linux的文件描述符
文件描述符(FD:file descriptors),也可以說是文件句柄,當某個程序打開文件時,內核返回相應的文件描述符,程序為了處理該文件必須引用此描述符。文件描述符是一個正整數,用以標明每一個被進程所打開的文件和socket。最前面的三個文件描述符(0,1,2)分別與標准輸入(stdin),標准輸出(stdout)和標准錯誤(stderr)對應,后面打開的文件依此類推對應3、4…… 。
linux系統對每個用戶、進程、或整個系統的可打開文件描述符數量都有一個限制,一般默認為1024。當我們在系統或應用的日志中碰到“too many open files”錯誤記錄時,這個其實不是說打開的文件過多,而是打開的文件描述符數量已達到了限制,這時就需要增加文件描述符的數量限制了。
1.1 獲取系統打開的文件描述符數量
[root@localhost ~]# cat /proc/sys/fs/file-nr
1216 0 197787
//第一列 1216 :為已分配的FD數量
//第二列 0 :為已分配但尚未使用的FD數量
//第三列197787:為系統可用的最大FD數量
已用FD數量=為已分配的FD數量 - 為已分配但尚未使用的FD數量。注意,這些數值是系統層面的。
1.2 獲取進程打開的文件描述符數量
[root@localhost ~]# pidof vim
3253
[root@localhost ~]# ll /proc/3253/fd
總用量 0
lrwx------. 1 test test 64 6月 8 18:11 0 -> /dev/pts/0
lrwx------. 1 test test 64 6月 8 18:11 1 -> /dev/pts/0
lrwx------. 1 test test 64 6月 8 18:11 2 -> /dev/pts/0
lrwx------. 1 test test 64 6月 8 18:11 4 -> /home/test/.bash_history.swp
//可以看到vim進程用了4個FD
1.3 更改文件描述符限制
當碰到“too many open files”錯誤時,就需要增加文件描述符的限制數量,系統的默認文件描述符都比較大,一般來說,只需增加用戶或進程的就可以了
//用戶或進程
[root@localhost ~]# ulimit -n
1024
[root@localhost ~]# ulimit -n 10240
[root@localhost ~]# ulimit -n
10240
注意,使用ulimit 命令更改后只是在當前會話生效,當退出當前會話重新登錄后又會回到默認值1024,要永久更改可以修改文件 /etc/security/limit.conf,如
[root@localhost ~]#vi /etc/security/limits.conf
加入 “abc hard nofile 10240”
abc:用戶名,即允許test使用ulimit命令更改FD限制,最大值不超過10240,更改后abc用戶的每一個進程(以abc用戶運行的進程)可打開的FD數量為10240個
hard:限制類型,有soft/hard兩種,達到soft限制會在系統的日志(一般為/var/log/messages)里面記錄一條告警日志,但不影響使用。hard,達到這個限制,有日志且會影響使用。
nofile:限制的內容,nofile - max number of open files
1024 :值
更改后,退出終端重新登錄,用ulimit看看有沒有生效,如果沒生效,可以在abc用戶的.bash_profile文件加上 ulimit -n 10240 ,以使用戶abc每次登錄時都會將FD最大值更改為10240,如:
[root@localhost ~]#echo "ulimit -n 10240" >> /home/abc/ .bash_profile
10240
[root@localhost ~]# su - abc
[abc@localhost ~]$ ulimit -n
10240
limit.conf文件里面本身已有很詳細的使用方法,這個下次可以說說。
//系統級別
將整個操作系統可以使用的FD數量更改為51200
[root@localhost ~]# echo "51200" > /proc/sys/fs/file-max
[root@localhost ~]# cat /proc/sys/fs/file-nr
1184 0 51200
像這樣更改在系統重啟后會恢復到默認值,要永久更改可以在sysctl.conf文件加上fs.file-max = 51200
如:
[root@localhost ~]# echo "fs.file-max = 51200" >> /etc/sysctl.conf
二、獲取打開的文件數量
linux的一切皆為文件,那么如何知道系統/應用打開了哪些或是多少個文件呢?很簡單,用lsof命令就行了,lsof,list open files的簡寫,可列出程序或系統正在使用的文件。
2.1 獲取整個系統打開的文件數量
[root@localhost ~]# lsof |wc -l
1864
2.2 獲取某個用戶打開的文件數量
[root@localhost ~]# lsof -u test |wc -l
15
2.3 獲取某個程序打開的文件數量
[root@localhost ~]# pidof vim
3253
[root@localhost ~]# lsof -p 3253 |wc -l
31
上面所示只是用lsof來顯示已打開的文件數量,lsof的功能遠不止這些,有興趣可以man lsof看一下
三、進程打開的文件描述符與文件
如前面說的,為什么說“too many open files”錯誤不是說打開的文件過多,而是打開的文件描述符數量已達到了限制,這個簡單的可以用man ulimit就可得知
[abc@localhost ~]$ man ulimit
//找到ulimit,可以看到下列一行
-n The maximum number of open file descriptors (most systems do not allow this value to be set)
這行就說明了用ulimit -n xxx 更改的是文件描述符而不是文件的最大值。
我們可以來測試一下:
-
打開一個進程vim,獲取vim打開的文件及文件描述符數量
[abc@localhost ~]$ lsof -p 3330 |wc -l //文件數量
31
[abc@localhost ~]$ ls /proc/3330/fd |wc -l //文件描述符數量
4
[abc@localhost ~]$ killall -9 vim
[1]+ 已殺死 vim .bash_profile
[abc@localhost ~]$ ulimit -n 20
-
更改限制,並測試vim的運行情況
[abc@localhost ~]$ ulimit -n 20 //更改為20,即小於文件數量31
[abc@localhost ~]$ ulimit -n
20
[abc@localhost ~]$ vim .bash_profile //可看到vim可以正常打開文件
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin
export PATH
ulimit -n 10240
----------------------------------
[abc@localhost ~]$ ulimit -n 3 //更改為3,即小於FD數量4
[abc@localhost ~]$ ulimit -n
3
[abc@localhost ~]$ vim .bash_profile
-bash: start_pipeline: pgrp pipe: Too many open files
vim: error while loading shared libraries: libselinux.so.1: cannot open shared object file: Error 24
從上面可看到小於文件描述符的數值時即報“Too many open files”錯誤,那么這個應該可以說明這個“Too many open files”錯誤是是打開的文件描述符數量已達到了限制所引起的,跟打開的文件數量沒有關系。
另用lsof可知道進程都打開了哪些文件和文件描述符:
[abc@localhost ~]$ lsof -p 3330
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
vim 3555 abc cwd DIR 253,0 4096 923587 /home/abc
vim 3555 abc rtd DIR 253,0 4096 2 /
vim 3555 abc txt REG 253,0 1971360 287900 /usr/bin/vim
vim 3555 abc mem REG 253,0 155696 846 /lib64/ld-2.12.so
vim 3555 abc mem REG 253,0 26104 281208 /usr/lib64/libgpm.so.2.1.0
vim 3555 abc mem REG 253,0 1912928 847 /lib64/libc-2.12.so
vim 3555 abc mem REG 253,0 22536 852 /lib64/libdl-2.12.so
vim 3555 abc mem REG 253,0 145672 859 /lib64/libpthread-2.12.so
vim 3555 abc mem REG 253,0 598816 848 /lib64/libm-2.12.so
vim 3555 abc mem REG 253,0 124624 857 /lib64/libselinux.so.1
vim 3555 abc mem REG 253,0 113904 856 /lib64/libresolv-2.12.so
vim 3555 abc mem REG 253,0 1489600 406575 /usr/lib64/perl5/CORE/libperl.so
vim 3555 abc mem REG 253,0 142504 96 /lib64/libncurses.so.5.7
vim 3555 abc mem REG 253,0 34336 890 /lib64/libacl.so.1.1.0
vim 3555 abc mem REG 253,0 43392 869 /lib64/libcrypt-2.12.so
vim 3555 abc mem REG 253,0 387880 868 /lib64/libfreebl3.so
vim 3555 abc mem REG 253,0 1753952 271694 /usr/lib64/libpython2.6.so.1.0
vim 3555 abc mem REG 253,0 17520 886 /lib64/libutil-2.12.so
vim 3555 abc mem REG 253,0 138280 826 /lib64/libtinfo.so.5.7
vim 3555 abc mem REG 253,0 20280 887 /lib64/libattr.so.1.1.0
vim 3555 abc mem REG 253,0 116136 889 /lib64/libnsl-2.12.so
vim 3555 abc mem REG 253,0 61624 42 /lib64/libnss_files-2.12.so
vim 3555 abc mem REG 253,0 26050 265158 /usr/lib64/gconv/gconv-modules.cache
vim 3555 abc mem REG 253,0 124855 528606 /usr/share/vim/vim72/lang/zh_CN/LC_MESSAGES/vim.mo
vim 3555 abc mem REG 253,0 135533 528604 /usr/share/vim/vim72/lang/zh_CN.UTF-8/LC_MESSAGES/vim.mo
vim 3555 abc mem REG 253,0 99158752 264902 /usr/lib/locale/locale-archive
vim 3555 abc 0u CHR 136,0 0t0 3 /dev/pts/0
vim 3555 abc 1u CHR 136,0 0t0 3 /dev/pts/0
vim 3555 abc 2u CHR 136,0 0t0 3 /dev/pts/0
vim 3555 abc 4u REG 253,0 4096 923589 /home/abc/.bash_profile.swp
可看到運行vim時,打開了很多個文件,但文件描述符只有后面四個。