记一次上线就跪的故障排查案例

这个是我很早之前解决的一个案例,其现象是系统每次上线后,20多台机器,总有两三机器,出现假死的状况。如何判断出系统假死?借助的是一个第三方公司运维监控平台;这种状况,前同事称之为的“假死”,须要从新启动系统才能恢复。由于我是新来乍到,以为这种状况不正常,并且对研发(在这边是研发上线)来讲,是一个很是大的上线负担;因而我决定解决一下这个“百年难题”。web

我亲自上线,果真很快就碰到了假死的机器。我看到机器的CPU,内存和磁盘IO都很正常,根本不像出问题的机器。直觉告诉我,先用jstack打印个堆栈看看当前tomcat在作什么吧,因而叫上支持上线的运维小哥给打印了一个,而后手工从新部署了一下有问题的机器(记住出问题必定要先止损)。tomcat

拿到手的堆栈,第一眼就发现了一些问题。前几行以下:微信

 

 

能够看到tomcat的线程号已经到了215,而tomcat默认最大处理数为200,已经到了饱和状态。后续的请求就只能排队了。运维

堆栈中,有不少waiting to lock <0x0000000784588098>的线程,从执行堆栈看,应该是CXF要调用.NET的webservice。调用的业务方法各不相同。curl

继续往下看,在堆栈的后半部分(注意行数),打印了一个死锁的提示。url

 

 

咱们进一步分析,为了方便你们阅读,我对上面的死锁线程画了一个依赖图,能够看出,线程25和线程48造成了死锁。这4个线程的等待关系以下:线程

 

 

继续分析,什么致使的死锁;blog

线程25的堆栈以下:接口

 

线程48的堆栈:内存

 

线程持有锁和堆栈中提示的锁信息正好照应

 

从上面堆栈能够分析出,gson和第三方的agent发生了循环死锁。至此问题的解决方法已经有了,要不去掉gson,要不就去掉那个第三方agent。

 

除了上面的解决方法外,咱们还在系统中增长了一个容器探活的接口(这个功能从监控来看,很是有意义)。即在controller中写一个方法,直接返回一个字符串。这样在外部定时的去调用接口(也能够手工使用curl来探测),就知道这个服务是否还存活,也不用第三方监控系统来判断了;

 

 

经验教训:

一、系统需从容器级别支持外部探测,以证实自身健康

二、不要轻易引入外部agent

知识点:

一、tomcat(BIO)默认最大线程数200

 

关注个人微信公众号,获取最新故障案例分析;

相关文章
相关标签/搜索