前几天部署JAVA项目,在测试环境上跑了几个小时Tomcat出现异常
java.net.SocketException: Too many open files
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:384)
at java.net.ServerSocket.implAccept(ServerSocket.java:453)
at java.net.ServerSocket.accept(ServerSocket.java:421)
at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:60)
at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:216)
出现这个错误原因是打开文件数(Linux一切皆文件,所以打开文件数包含文件和Socket连接数)超过Linux设置的最大值
使用lsof -p pid | wc -l 查看Tomcat进程打开文件数5622 pid ---表示程序的进程号
查看当前进程最大打开文件数限制 cat /proc/pid/limits (一定要以查看当前进程为准)
查看当前打开文件数限制 ulimit -a 显示 (有可能出现ulimit -a 查看的open files 和 cat /proc/pid/limits不一致的情况 ,一定要以上述查看当前进程为准,因为有可能在程序运行中,修改过open files的大小,而运行中的程序只会以启动时的open files大小为准)
目前该用户单进程文件数打开限制为4096,解决方案当然是修改单进程文件数打开限制(比如修改为8192)
修改时需要将用户切换为root用户,否则修改会失败,普通用户不具备修改的权限
普通用户修改会出现如下错误
su root 将用户切换为root用户
- 临时修改方案:ulimit -n 8192然后查看 ulimit -a
这种方式只能暂时起作用,比如系统重启后将恢复为原来的设置
- 彻底修改方案: /etc/security/limits.conf 在文件末尾添加
* soft nofile 8192
* hard nofile 8192
执行如下命令 其中*号代表任意用户 在实际环境中指定为当前用户 如 xxxuser
echo "* soft nofile 8192" >> /etc/security/limits.conf
echo "* hard nofile 8192" >> /etc/security/limits.conf
修改完成后,重启应用,后面就没有出现该问题了,到这里问题是解决了,但是问题原因还是不清楚,到底是什么造成打开文件数过大,后来查看日志文件,以及问题复现,发现是并发访问过多。每一个访问都需要建立Socket连接,而每个Socket连接都有会占用句柄数,连接过多并且释放不及时,很多TCP连接处于CLOSE_WAIT状态,这时候就需要进一步去优化TCP连接参数
如果修改后,程序运行一段时间之后继续出现Too many open files异常,那么就应该查看句柄信息,进一步分析是什么句柄占用最多,排查原因,导出句柄信息到文件 lsof -p pid> lsof.log,筛选出占用句柄前十的信息
cat lsof.log | awk '{print $8}' | sort | uniq -c | sort -rn | head -n 10
然后再进行分析,希望能帮助你解决问题
(转载请注明出处)