記一次上線就跪的故障排查案例

這個是我很早之前解決的一個案例,其現象是系統每次上線後,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

 

關注個人微信公衆號,獲取最新故障案例分析;

相關文章
相關標籤/搜索