正文
联想到前面的报错Too many open files,会不会也是由于文件句柄数不够,所以导致JVM无法从文件系统读取jar包,从而导致NoClassDefFoundError?
关于该应用出现的问题,种种迹象表明那个时段应该是进程句柄数不够引起的,例如无法从本地加载文件,无法建立Redis连接,无法发起网络请求等等。
前一阵我们的一个应用也出现了这个问题,当时发现老机器的Max Open Files设置是65536,但是一批新机器上的Max Open Files都被误设置为4096了。
虽然后来运维帮忙统一修复了这个设置问题,但是需要重启才会生效。所以目前生产环境还有相当一部分机器的Max Open Files是4096。
所以,我们登陆到其中一台出问题的机器上去查看是否存在这个问题。但是出问题的应用已经重启,无法获取到应用当时的情况。不过好在该机器上还部署了另外的应用,pid为16112。通过查看/proc/16112/limits文件,发现里面的Max Open Files是4096。
所以有理由相信应用出问题的时候,它的Max Open Files也是4096,一旦当时的句柄数达到4096的话,就会导致后续所有的IO都出现问题。
故障原因算是找到了,是由于Max Open Files的设置太小,一旦进程打开的文件句柄数达到4096,后续的所有请求(文件IO,网络IO)都会失败。
由于该应用依赖了redis,所以一旦一段时间内无法连接redis,就会导致请求大量超时,造成请求堆积,进入恶性循环。(好在SOA框架有熔断和限流机制,所以问题影响只持续了几分钟)
故障原因算是找到了,各方似乎对这个答案还算满意。不过还是有一个疑问一直在心头萦绕,为啥故障发生时间这么凑巧,就发生在用户通过配置中心发布配置后?
为啥在配置发布前,系统打开的文件句柄还小于4096,在配置发布后就超过了?难道配置客户端在配置发布后会大量打开文件句柄?
4.1 代码分析
通过对配置客户端的代码分析,在配置中心推送配置后,客户端做了以下几件事情:
-
之前断开的http long polling会重新连接
-
会有一个异步task去服务器获取最新配置