Too many open files

今天发现用JAVA写的ICE服务在高峰期抛了一个文件描述符不够的异常。

java.net.SocketException: Too many open files
at java.net.Socket.createImpl(Socket.java:388)
at java.net.Socket.<init>(Socket.java:362)
at java.net.Socket.<init>(Socket.java:240) java.net.SocketException: Too many open files
at java.net.Socket.createImpl(Socket.java:388)
at java.net.Socket.<init>(Socket.java:362)
at java.net.Socket.<init>(Socket.java:240)

通常这时候都是因为进程的描述符不够导致的。使用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) 71680
max locked memory       (kbytes, -l) 32
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) 71680
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

open files一项是默认的1024,而高峰期ICE的JAVA经常描述符居然高达951。 也就是如果网络堵塞或者数据库慢就会导致更多的Socket因为文件描述符不够而创建失败。

lsof -p 20528 |wc -l
951

在看看打开的文件描述符中jar文件都占了342个(Java的麻烦之处就是启用了太多的jar包,而Java进程打开一个jar文件居然用了两个文件描述符),然后socket也用了300个文件描述符,进程其它占用也用了300个,这样一来默认的1024个描述符在高峰期就不够了。 现在这个ICE服务不能随便终止,于是想不高的时候重启下。但是目前可以先降低socket的占用量。参照这篇文章,添加下面的代码到/etc/sysctl.conf中。

net.ipv4.tcp_keepalive_time = 1800
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl = 15

由于先前开启了net.ipv4.tcp_tw_reuse ,所以想将保留时间降下来,然后在启动icegridenode的脚本里面添加ulimit -n 20000就好了,然后就等待服务压力小的时候重启下icegridenode就好了。 当前需要sysctl -p加载修改的sysctl.conf文件。