tomcat宕机无法响应问题研究解决

本人所在公司有一个系统部署单个tomcat上,该系统由前开发人员开发。本人于两年前接手,在对该系统进行开发运维过程中,先后解决了两种tomcat宕机无法提供服务情况,具体如下:

(1)JVM 内存不足

主Tomcat运行过程出现宕机无法响应的现象,刚开始无法定位问题时只能在挂死出现时采用手工重启的方式解决。后在服务器配置tomcat每天晚上重启的策略,每天宕机的次数相对原来有所减少,但仍然会随机出现。经分析大概判断是内存不足导致。采取的措施是增大jvm的内存,但原服务器安装的是32位jdk6,jvm内存最大只能设置的2G,因此通过升级JDK为64位,将jvm内存设置到4G,并对系统进行部分模块的适应性调整。重新部署后,系统宕机次数大幅度减少。频次降到一两个月一次。此次改造,系统稳定性得到较大的提升。

(2)程序逻辑问题

在解决因JVM内存不足导致Tomcat频繁宕机问题后,该系统又出现了另外一种情形的宕机。就是某模块的java代码在开发环境下运行正常,但是编译并发布到正式系统上,只要执行报告审核操作,系统随机马上挂死,无法响应,端口telnet不通。这个问题从发现到解决,期间经历了半年的时间(因为一直往java后台方向去排查,事后才知道是已离职的同事挖的历史大坑啊,排查方向有误,我操!先吐口老血再慢慢说)。

刚开始一直感到很疑惑,一样的代码,为什么以前编译的文件运行正常,新编译的就出错呢?为什么挂死会随机?正值不久前升级了jdk版本(解决上面宕机问题),以为是编译环境导致,于是换回原版本jdk进行编译,仍然出错。找到原同事发代码给他让其帮忙编译,仍然出错。真是百思不得姐了。此外因为是上班时间宕机,因此出现状况时就直接登陆服务器,tomcat进程还在,控制台已停止输出,处于挂死状态,情况紧急就直接重启tomcat。期间断断续续通过各种方式编译部署,但都没有最终解决问题。本宝宝是个责任心爆棚的人,不解决问题,吃不下饭啊。不扯了,解决过程如下:

1)本地再次编译该模块代码并部署,启动tomcat,开启jconsole对tomcat进行监控;

2)执行该模块的报告批准操作,tomcat随即处于挂死状态,报告审核没有这个问题;查看监控内存、cpu使用率正常;线程数上到几千,都是http请求,一筹莫展之际,随机点了下http请求线程,描述中出现了一个该action的method(事前无论如何都没想到报告批准操作会调用到这个不相关的method)。

3)到开发环境查这个method,尼玛,是谁写的一个死循环在这里,站出来,我保证不打死你,操你大爷啊,

坑死爹爹了。死循环如下:

public ActionForward updateReport(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response)

{

String reportId =request.getParameter("reportId");

String url ="http://localhost/xxx/xxx.do?method=updateReport&reportId=" + reportId;

URL myUrl = null;

try {

myUrl = new URL(url);

} catch (MalformedURLException e) {

e.printStackTrace();

}

try {

myUrl.openStream();

} catch (IOException e) {

e.printStackTrace();

}

return null;

}

4)再查jsp,果然在报告批准页面里面,当报告状态为7的时候调用了这个method,不停的向系统发出http请求,当请求数上到2千左右,tomcat拒绝了响应,tomcat挂死。元凶终于找到了,但是没查出来前是无论如何也想不到会调用到这个垃圾啊。

5)此外审核不会出现宕机是因为当批准的时候才调用,就解释了为何审核不会导致宕机。但原版代码为什么没有问题呢?再追溯代码,原版代码地址不完全一样,端口不同,至此一切真相大白了。

6)最后这个method即使不是死循环,里面有正确的逻辑代码,但URL的使用一定要谨慎,需要设置等待超时,否则一样容易出现tomcat无期等待致死的情况。

URL myUrl = new URL(url);

HttpURLConnection con = (HttpURLConnection)myUrl.openConnection();

con.setConnectTimeout(8000);//连接超时

con.setReadTimeout(8000);//读操作超时

好的代码像粥一样,都是用时间熬出来的
原文地址:https://www.cnblogs.com/jijm123/p/15138915.html