某套应用,部署在Linux下的中间件上,在某个时刻开始报警,从日志看是无法获取JDBC连接,

一则open files的故障_打开文件


应用前几天刚做了升级,但当时测试没什么问题,难道是什么原因,导致累积的问题?


再看日志,发现有"Too many open files"的错误,难道和超过open files个数有关?

一则open files的故障_应用程序_02


通过ulimit看下open files设置,是10240,

一则open files的故障_文件描述符_03

现在的问题是,应用进程究竟打开了多少个文件,此时,Linux下的lsof指令,非常有用,

lsof是list open files的缩写,是一个列出当前系统打开文件的工具。在Linux环境下,任何事物都以文件的形式存在,通过文件不仅仅可以访问常规数据,还可以访问网络连接和硬件。所以如传输控制协议(TCP)和用户数据报协议(UDP)套接字等,系统在后台都为该应用程序分配了一个文件描述符,无论这个文件的本质如何,该文件描述符为应用程序与基础操作系统之间的交互提供了通用接口。因为应用程序打开文件的描述符列表提供了大量关于这个应用程序本身的信息,因此通过lsof工具能够查看这个列表对系统监测以及排错将是很有帮助的。


lsof输出各列信息的意义如下:

COMMAND:进程的名称PID:进程标识符

USER:进程所有者

FD:文件描述符,应用程序通过文件描述符识别该文件。如cwd、txt等 TYPE:文件类型,如DIR、REG等

DEVICE:指定磁盘的名称

SIZE:文件的大小

NODE:索引节点(文件在磁盘上的标识)

NAME:打开文件的确切名称


其中,FD列中的文件描述符cwd值表示应用程序的当前工作目录,这是该应用程序启动的目录,除非它本身对这个目录进行更改,txt类型的文件是程序代码,如应用程序二进制文件本身或共享库。


其次数值表示应用程序的文件描述符,这是打开该文件时返回的一个整数。u表示该文件被打开并处于读取/写入模式,而不是只读®或只写(w)模式。同时还有大写的W表示该应用程序具有对整个文件的写锁。该文件描述符用于确保每次只能打开一个应用程序实例。初始打开每个应用程序时,都具有三个文件描述符,从0到2,分别表示标准输入、输出和错误流。所以大多数应用程序所打开的文件的FD都是从3开始。


与FD列相比,Type列则比较直观。文件和目录分别称为REG和DIR。而CHR和BLK,分别表示字符和块设备;或者UNIX、FIFO和IPv4,分别表示UNIX域套接字、先进先出(FIFO)队列和网际协议(IP)套接字。


通过如下指令,获得应用进程号,

ps -ef | grep 应用进程名称


通过lsof和wc指令,检索进程打开的文件个数,发现值是11000多,明显超过10240的限制,




lsof | grep 应用进程号 | wc -l


因此,可以推测,正是由于应用打开的文件个数超过了系统open files的限制,提示"Too many open files",因此,导致新的打开文件的请求无法满足(这里是获取JDBC连接的操作)。


为何应用打开的文件个数超高?通过应用排查,发现是因为每次请求都会将消息发送给kafka队列,但是这段期间,队列配置有误,导致每次推送,都是错误的,应用虽然捕获了异常,但未做close操作,导致每个应用和kafka的TCP连接不会释放,逐渐累积到了open files的上限,所以这个问题,并未在上线当天暴露,而是过了几天,才出现的。


针对这个问题,一个是需要应用在捕获异常的时候主动close释放连接,关闭打开的文件,另一个就是需要对系统当前打开文件的个数进行监控,当接近open files上限之前,进行报警,避免出现"Too many open files"。


关于open files改动,可以参考,

Linux中Too many open files错误的解决