Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题

时间:2024-04-09 20:41:55

1、项目运行环境, CentOS Linux release 7.4.1708,springboot 2.1.0.RELEASE,jdk1.8,mysql 5.6.16

 

2、系统在某个周末的时候,无法正常运行,连续抛几十分钟异常java.sql.SQLNonTransientConnectionException: Could not create connection to database server,导致系统宕机,截图如下,当时telnet ip port,发现mysql数据库服务端网络也是正常的:

Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题

3、最开始以为是连接不上数据库,或者数据库连接池的设置问题,然后去看了一下连接池配置,是不是连接池设置越大越好呢,点击这篇连接:

数据库连接池的大小值设定,不能随意设置太大的值:https://blog.csdn.net/educast/article/details/93461372

Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题

看完以后,发现系统设置的初始化大小:5,最大:20,好像并没有什么问题

 

4、是不是系统在某个时间点,由于网络原因,连接不上服务了,解析域名的时候报错,当网络恢复以后无法正常连接?发现以下连接设置,有autoReconnect=true参数,当网络恢复的时候,会自动进行数据库重连接,也不至于导致系统宕机。

spring.datasource.url=jdbc:mysql://*************.mysql.rds.aliyuncs.com:3306/**********?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&autoReconnect=true

下面验证一下是否会进行自动重连,在测试环境配置一个数据库访问域名,先断开网络,报异常如下:

Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题

 

恢复网络,发现预编译sql都打印出来,并且执行,说明autoReconnect=true参数是有作用的,并且不会由于网络临时抖动问题,导致数据一直抛异常:java.sql.SQLNonTransientConnectionException: Could not create connection to database server

 

Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题

5、并且在同一台服务器上,我们还有另外一台应用A;A应用和B应用部署在同一台服务器上,用的同一数据库连接配置,这种宕机的问题,发生过两次,都在B应用,同时间A应用却没有找到这样的异常日志,我们再把这个异常日志分析一下:

在SQLNonTransientConnectionException异常发生之前,有很多 Socket accept failed
java.io.IOException: Too many open files

Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题

那么数据库连接异常 和 Too many open files有什么关系呢?

在linux环境下,在linux环境下,任何事物都以文件的形式存在,通过文件不仅仅可以访问常规数据,还可以访问网络连接和硬件:普通文件,目录,NFS文件,字符文件,管道,Socket流,网络Socket等等,并且可以通过lsof命令,查看系统打开文件大小,或者某个pid占用文件大小;使用ulimit命令,查看默认分配占用文件大小;

关于上面所说的可以参考如下博客链接:

参考连接,Linux lsof命令:https://blog.csdn.net/qq_27870421/article/details/92803453

limit资源限制ulimit 详解:https://blog.csdn.net/skiwnc/article/details/84100095

 

6、所以问题大概就出在文件使用资源上面,再从日志里面搜一下,Too many open files第一次出现的地方

grep -C 200 'Too many open files'    ***.log | more
Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题file/config/EcspPublicKey.cer证书文件,无法读取;那么我们再去看代码,是不是有使用文件资源的地方,没有释放呢?

 

7、全局搜索  FileInputStream使用地方:

Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题

找到demo代码如下,168~174行被修改过,这里的InputStream和OutPutStream都没有关闭,并且在finally里面的delete()方法,由于没有关闭流,也是删除不掉文件的(这一点已经在本地测试过,就不贴代码了):

Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题

然后我们去看一下这里代码的提交记录对比,左边是之前版本,右变是修改后的版本

Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题

try(){}catch{},和 try{}catch{}是不一样的(注意第一个try语法后面的小括号)

原来是用了 try-with-recourse 语法;

8、Java库中有很多资源需要手动关闭,比如InputStream、OutputStream、java.sql.Connection等等。在此之前,通常是使用try-finally的方式关闭资源;Java7之后,推出了try-with-resources声明来替代之前的方式。 try-with-resources 声明要求其中定义的变量实现 AutoCloseable 接口,这样系统可以自动调用它们的close方法,从而替代了finally中关闭资源的功能;

我们写了一段代码,在try()中声明IO流对象,并没有手动关闭资源,打包后反编译class文件,可以看到编译器识别到了语法糖,自动加上了资源释放代码:

Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题

想必修改的人,可能不知道这个语法,而且也忽略了关闭资源,导致了资源泄漏的问题;

关于 try-with-recourse 详细语法细节问题,可以参考帖:

https://blog.csdn.net/weixin_40255793/article/details/80812961?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase

9、然后回到代码继续找,没有关闭资源的地方:

这里,关闭了ObjectInputStream,却没有关闭FileInputStream :

Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题

还有这里,如果抛异常,也会导致资源无法关闭:

Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题

10、回到应用服务器上,ulimit -a,查看单个pid允许最大文件数:1024Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题

Socket accept failed java.io.IOException: Too many open files 导致的系统宕机问题

之前抛异常的应用程序,pid为26562 ,目前已经达到557,昨天看还是400多;

希望下次出故障的时候,能再分析,确认一下是这个文件的问题;

未完待续。。。。。