Caused by: java.net.SocketException: Too many open files
at java.base/java.net.Socket.createImpl(Socket.java:462)
at java.base/java.net.Socket.getImpl(Socket.java:522)
at java.base/java.net.Socket.setTcpNoDelay(Socket.java:980)
at com.mysql.jdbc.StandardSocketFactory.configureSocket(StandardSocketFactory.java:132)
at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:203)
at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:301)
... 119 common frames omitted
Springboot server healthcheck失败,查看log发现以上错误,使用netstat查看发现Java进程与ElasticSearch服务器有400多个TCP,所有怀疑是代码中有socket没有释放。查看代码中与ElasticSearch通信的部分,确实没有找到close方法。代码中使用的RestHighLevelClient初始化ElasticSearch的连接,参考https://www.journaldev.com/18148/spring-boot-elasticsearch和https://stackoverflow.com/questions/54746822/elasticsearch-java-high-level-rest-client-establish-a-bunch-of-tcp-connection-an在使用RestHighLevelClient时必须使用Singleton Pattern并且需要在bean销毁的时候关闭连接。
debug过程中用到的命令:ulimit, lsof
ulimit主要是用来限制进程对资源的使用情况的,它支持各种类型的限制,常用的有:内核文件的大小限制,进程数据块的大小限制,Shell进程创建文件大小限制,可加锁内存大小限制,常驻内存集的大小限制,打开文件句柄数限制,分配堆栈的最大大小限制,CPU占用时间限制用户最大可用的进程数限制,Shell进程所能使用的最大虚拟内存限制。
ulimit 选项 含义
-a 显示当前系统所有的limit资源信息。
-H 设置硬资源限制,一旦设置不能增加。
-S 设置软资源限制,设置后可以增加,但是不能超过硬资源设置。
-c 最大的core文件的大小,以 blocks 为单位。
-f 进程可以创建文件的最大值,以blocks 为单位.
-d 进程最大的数据段的大小,以Kbytes 为单位。
-m 最大内存大小,以Kbytes为单位。
-n 查看进程可以打开的最大文件描述符的数量。
-s 线程栈大小,以Kbytes为单位。
-p 管道缓冲区的大小,以Kbytes 为单位。
-u 用户最大可用的进程数。
-v 进程最大可用的虚拟内存,以Kbytes 为单位。
-t 最大CPU占用时间,以秒为单位。
-l 最大可加锁内存大小,以Kbytes 为单位。
其中ulimit -n用于限制进程能够打开的文件描述符的最大数目。因为任何设备在linux下都是文件,通信的接口也有专门的接口文件负责,所以linux下进程tcp链接的最大并发量也受限于该值。使用ulimit -Hn 查看硬限制为4096 使用ulimit -Sn查看软限制为1024
lsof 用于查看你进程开打的文件,打开文件的进程,进程打开的端口(TCP、UDP)。可以看到进程ID的打开文件状况。
lsof -p [进程ID]
使用改名命令查看java进程打开的文件描述符数量为4096已经达到了硬限制,所以无法再创建新的socket连接了。