./log-error-2023-05-05.0.log:java.io.FileNotFoundException: /tmp/tomcat.8054.6662226014931657024/work/Tomcat/localhost/ROOT/upload_2de0ae12_86e7_49cd_b138_fc8af49b7a59_00006179.tmp (打开的文件过多)
服务突然宕机 出现这个错误
打开的文件过多,一般来说是由于应用程序对资源使用不当造成,比如没有及时关闭Socket或数据库连接等。但也可能应用确实需要打开比较多的文件句柄,而系统本身的设置限制了这一数量。
过程
最开始还以为是linux文件数不不够,不停的调整文件打开大小
查看系统允许打开的最大文件数
#cat /proc/sys/fs/file-max
查看每个用户允许打开的最大文件数
ulimit -a
发现系统默认的是open files (-n) 1024,问题就出现在这里。
在系统文件/etc/security/limits.conf中修改这个数量限制,在文件中加入内容:
* soft nofile 65536 * hard nofile 65536 * soft nproc 65536 * hard nproc 65536 * soft memlock unlimited * hard memlock unlimited 或只加下面两个参数都行的 * soft nofile 65536 * hard nofile 65536 修改完成保存,重启服务器
错误
异常1: 12-Jun-2018 01:30:15.340 严重 [http-nio-8080-Acceptor-0] org.apache.tomcat.util.net.NioEndpoint$Acceptor.run Socket accept failed java.io.IOException: 打开的文件过多 at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method) at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:422) at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:250) at org.apache.tomcat.util.net.NioEndpoint$Acceptor.run(NioEndpoint.java:453) at java.lang.Thread.run(Thread.java:748) 异常二 java.net.SocketException: Too many open files at java.net.PlainSocketImpl.accept(Compiled Code) at java.net.ServerSocket.implAccept(Compiled Code) at java.net.ServerSocket.accept(Compiled Code) at weblogic.t3.srvr.ListenThread.run(Compiled Code) 第一个异常则在错误影响到 I/O 操作时抛出,而第二个异常在错误影响到基础 TCP 协议时抛出。
分析
- 可能是tomcat文件/tmp/tomcat.8054.6662226014931657024/work/Tomcat/localhost 说明是这个目录下的文件找不到了,后来经过查资料,tmp的文件10天之内不访问就会删除,所以可能是这个原因,调整tomcat的日志路径
#tomcat server.tomcat.basedir=/home/tomcatlog server.tomcat.accesslog.enabled=true server.tomcat.accesslog.pattern= '%h %l %u %t "%r" %s %b %D %{User-Agent}i'
- 使用命令lsof -p 进程id可以查看单个进程所有打开的文件详情,使用命令lsof -p 进程id | wc -l可以统计进程打开了多少文件:
查看进程打开的文件
lsof -p 31878
发现大量文件
改成静态
lsof -p 1305 | wc -l 查看当前进程id为1305的 文件操作状况
- 如果你对你的程序有一定的解的话,应该对程序打开文件数(链接数)上限有一定的估算,如果感觉数字异常,请使用第一步的lsof -p 进程id > openfiles.log命令,获得当前占用句柄的全部详情进行分析,
1)打开的这些文件是不是都是必要的?
2)定位到打开这些文件的代码
3)是否程序操作了文件写入,但是没有进行正常关闭
4)是否程序进行了通讯,但是没有正常关闭(也就是没有超时结束的机制)
实战
崩溃的原因 文件打开过多,解决方案:
lsof -p 19945 | wc -l 进程pid为19945的文件打开数
lsof -p 19945 进程的文件打开详情
之前设置的各种文件打开最大数限制好像并未生效,文件数到4096就开始报错了
后来使用arthas查到了jvm打开最大文件数是4096
MAX-FILE-DESCRIPTOR-COUNT:JVM 进程最大可以打开的文件描述符数
OPEN-FILE-DESCRIPTOR-COUNT:JVM 当前打开的文件描述符数
找到对应代码之后,使用postman调用,每次调用文件打开数就会+1,查找到内存泄露的代码后,改完,再次使用postman调用,文件打开数不再明显增长