昨晚收到服务器报警邮件,提示如下:
open /dev/null: too many open files
显然是服务器中打开的文件数太多,准确地说是某个进程打开的文件数太多。那么,我们先看下进程能够占用的最大文件描述符数是多少。
[root@i data0]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 95000
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 95000
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
由输出结果中的指标open files可知,当前系统一个进程能够打开的最大文件数是1024。显然可以增大这个值,有两种方法,一是直接执行命令:
ulimit -n 16384
但这种方式起的作用是临时的,如果想永久的生效,则需要修改配置文件limits.conf文件,在其末尾加上如下两行:
* soft nofile 16384
* hard nofile 16384
然后注销重启就可以了。这里顺带说下limits.conf文件的原理。limits.conf是pam_limits.so的配置文件,/etc/pam.d/下的应用程序调用pam_***.so模块。当用户访问服务器,服务程序将请求发送到PAM模块,PAM模块根据服务名称在/etc/pam.d 目录下选择一个对应的服务文件,然后根据服务文件的内容选择具体的PAM模块进行处理。
例:限制admin用户登录到sshd的服务不能超过2个 在/etc/pam.d/sshd 中添加 session required pam_limits.so;在/etc/security/limits.conf中添加 admin - maxlogins 2
其实还可以看看是哪个进程占用的文件描述符数超了,这里就要用到lsof命令了。
[root@localhost data0]# lsof | more
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
init 1 root cwd DIR 8,3 4096 2 /
init 1 root rtd DIR 8,3 4096 2 /
init 1 root txt REG 8,3 150352 81983 /sbin/init
init 1 root mem REG 8,3 65928 114718 /lib64/libnss_files-2.12.so
init 1 root mem REG 8,3 1922152 115146 /lib64/libc-2.12.so
init 1 root mem REG 8,3 93224 115162 /lib64/libgcc_s-4.4.7-20120601.so.1
init 1 root mem REG 8,3 47064 115149 /lib64/librt-2.12.so
init 1 root mem REG 8,3 145720 115148 /lib64/libpthread-2.12.so
init 1 root mem REG 8,3 268232 115150 /lib64/libdbus-1.so.3.4.0
init 1 root mem REG 8,3 39896 114918 /lib64/libnih-dbus.so.1.0.0
init 1 root mem REG 8,3 101920 114920 /lib64/libnih.so.1.0.0
init 1 root mem REG 8,3 156872 115145 /lib64/ld-2.12.so
init 1 root 0u CHR 1,3 0t0 3842 /dev/null
init 1 root 1u CHR 1,3 0t0 3842 /dev/null
init 1 root 2u CHR 1,3 0t0 3842 /dev/null
init 1 root 3r FIFO 0,8 0t0 7312 pipe
这里列出的就是所有打开的文件数,第二列是每个打开的文件对应的进程id。另外这里显示的也只是一小部分,实际上还有很多。这时可以执行以下命令查看每个进程对应的打开的文件数。
[root@localhost data0]# lsof | awk '{print $2}' | uniq -c | sort -rn | head -n 10
89 24833
77 23132
73 31469
70 9557
69 26242
68 8893
68 8643
68 8626
68 26210
68 13002
结果中显示的第二列是进程id,第一列是该进程打开的文件数,可见pid为24833的进程打开的文件数最多,并按从多到少排列。知道pid后,就可以通过ps -ef | grep pid查看对应的进程,之后要杀要剐悉听尊便。