too many open files 异常
项目运行过程中出现了too many open files 这种错误,查了linux配置 和代码工程,初步有了解决问题的思路,先记录下来。
- 工程报错
- 错误分析
- 资料收集
- 原因分析
- 代码复查
工程报错
最近项目因为要跑定时任务而且频率非常大,在项目运行一段之后,在日志里面就报错too many open files。
[2017-09-26 09:20:08] [WARN] [New I/O server boss #1 ([id: 0x37cac656, /0:0:0:0:0:0:0:0:20783])] com.alibaba.dubbo.remoting.transport.netty.NettyHelper$DubboLogger.warn(NettyHelper.java:90) - [DUBBO] Failed to accept a connection., dubbo version: 5.0.2, current host: 127.0.0.1
java.io.IOException: Too many open files
at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:241)
at org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink$Boss.run(NioServerSocketPipelineSink.java:244)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
错误分析
在网络上搜索了下问题,发现大部分都给出的修改linux的配置参数来解决问题。
-http://www.blogjava.net/fly2008/archive/2009/08/26/292626.html
主要修改参数是open files 这个参数,系统默认大小是1024。
资料收集
查看系统允许打开的最大文件数:
cat /proc/sys/fs/file-max
查看每个用户允许打开的最大文件数:
ulimit -a
发现系统默认的是open files (-n) 1024,问题就出现在这里。
在系统文件/etc/security/limits.conf中修改这个数量限制,
在文件中加入内容:
* soft nofile 65536
* hard nofile 65536
另外方法:
1.使用ps -ef |grep java (java代表你程序,查看你程序进程) 查看你的进程ID,记录ID号,假设进程ID为12
2.使用:lsof -p 12 | wc -l 查看当前进程id为12的 文件操作状况
执行该命令出现文件使用情况为 1052
3.使用命令:ulimit -a 查看每个用户允许打开的最大文件数
发现系统默认的是open files (-n) 1024,问题就出现在这里。
4.然后执行:ulimit -n 4096
将open files (-n) 1024 设置成open files (-n) 4096
原因分析
好吧,修改环境参数就修改环境参数吧,我通过linux命令,查看服务器的参数配置,结果如下:
![]()
可以看得出,目前系统的配置参数就是默认参数 大小1024 ,这样的话系统根本不够用,而时间文件句柄打开的大小是这样的:
![]()
实际产生的句柄达到了 4160个,远远大于1024,当然会报错了。
通过命令lsof -p 进程号 可以发现系统打开的文件句柄基本都是重复的文件。
想了下问题原因,发现解决这种问题,也只有2种方法了。
1.修改linux系统参数,
通过设置open files的大小,可以设置为10240,这样就能避免程序跑到一定的时间再次出现这种问题。
但是想想这种办法还是指标不治本,如果java程序一直在产生句柄,只要服务一直运行,总有一天会达到最大值,而且对服务器的性能要求也很高。
2.优化java代码
java工程里面的所有的句柄都是以文件的形式打开的,那就在读取完毕后,将文件进行关闭。这样才能从根本上减少文件句柄的打开次数,避免这个错误。
代码复查
结合优化代码这个思路,仔细分析了下代码中打开文件的地方,特别的针对linux环境打开文件句柄较多的文件进行了分析,分析后发现在编码过程中只有打开文件而没有关闭文件。所以这就是问题的根本原因了。
##问题代码##
public void init(){
pro = new Properties();
try { pro.load(this.getClass().getResourceAsStream("/cfg/properties/cloudConfig.properties"));
} catch (IOException e) {
e.printStackTrace();
}
}
##优化后的代码##
public void init(){
pro = new Properties();
try { //pro.load(this.getClass().getResourceAsStream("/cfg/properties/cloudConfig.properties"));
InputStream in = this.getClass().getResourceAsStream("/cfg/properties/cloudConfig.properties");
pro.load(in);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
文件打开就要关闭,养成良好习惯是关键。