上周,公司某一环境发生java service wrapper内存剧增导致最后被自动killed的情况,经过分析,确定导致java service wrapper(后续简称wrapper)守护进程内存快速增长直至被killed的最根本原因是应用程序到mysql数据库的jdbc可用连接远远小于java应用并发线程数,导致报了很多的连接异常(这些异常在至少三种情况下会发生:应用程序启动时mysql未启动,应用程序启动期间mysql被正常或异常关闭,mysql负载过高无响应或者超时,三者均可重现wrapper内存无限增长直至溢出),无论是dbcp 1.x,2.x还是c3p0,该问题均会发生,这些未被捕获的异常堆栈被传递到了wrapper守护进程,进而导致wrapper进程内存激增而溢出。而这些错误仅仅会在wrapper的日志级别为INFO或者更低时会被传递给wrapper;如果设置为ERROR或者更高,则不会(至于为何在这种情况下错误堆栈会被传递给wrapper,尚未找到具体的原因)。它与应用程序设置的log4j级别并无直接关系。同时dbcp连接池1.4以及以下版本因对无效的连接自动回收存在bug,会加速该问题的发生。
PS:上述问题仅在出问题的环境centos 7.0.1406版本下wrapper 3.5.29已验证可重现,不保证在其他版本下一定可重现。
解决方法:
1、使用wrapper,需设置conf/osm-runtime.conf中下列参数为ERROR:
wrapper.console.loglevel
wrapper.logfile.loglevel
wrapper.syslog.loglevel
这么更改的副作用是后续主应用程序中的异常将被suppressed,事后无法查找非显示打印的异常。
2、使用tomcat或者其他应用程序比如自己编写shell脚本作为主容器。
建议:统一将jdbc连接池调整为dbcp 2.1.1。