1. 程式人生 > >記一次上線就跪的故障排查案例

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

微信公眾號 難題 成了 出現 監控 執行 故障排查 上線 外部

這個是我很早以前解決的一個案例,其現象是系統每次上線後,20多臺機器,總有兩三機器,出現假死的情況。如何判斷出系統假死?借助的是一個第三方公司運維監控平臺;這種情況,前同事稱之為的“假死”,需要重新啟動系統才能恢復。因為我是新來乍到,覺得這種情況不正常,而且對研發(在這邊是研發上線)來說,是一個非常大的上線負擔;於是我決定解決一下這個“百年難題”。

我親自上線,果然很快就碰到了假死的機器。我看到機器的CPU,內存和磁盤IO都很正常,根本不像出問題的機器。直覺告訴我,先用jstack打印個堆棧看看當前tomcat在做什麽吧,於是叫上支持上線的運維小哥給打印了一個,然後手工重新部署了一下有問題的機器(記住出問題一定要先止損)。

拿到手的堆棧,第一眼就發現了一些問題。前幾行如下:

技術分享圖片

可以看到tomcat的線程號已經到了215,而tomcat默認最大處理數為200,已經到了飽和狀態。後續的請求就只能排隊了。

堆棧中,有很多waiting to lock <0x0000000784588098>的線程,從執行堆棧看,應該是CXF要調用.NET的webservice。調用的業務方法各不相同。

繼續往下看,在堆棧的後半部分(註意行數),打印了一個死鎖的提示。

技術分享圖片

我們進一步分析,為了方便大家閱讀,我對上面的死鎖線程畫了一個依賴圖,可以看出,線程25和線程48形成了死鎖。這4個線程的等待關系如下:

技術分享圖片

繼續分析,什麽導致的死鎖;

線程25的堆棧如下:

技術分享圖片

線程48的堆棧:

技術分享圖片

線程持有鎖和堆棧中提示的鎖信息正好照應

技術分享圖片

從上面堆棧可以分析出,gson和第三方的agent發生了循環死鎖。至此問題的解決方法已經有了,要不去掉gson,要不就去掉那個第三方agent。

除了上面的解決方法外,我們還在系統中增加了一個容器探活的接口(這個功能從監控來看,非常有意義)。即在controller中寫一個方法,直接返回一個字符串。這樣在外部定時的去調用接口(也可以手工使用curl來探測),就知道這個服務是否還存活,也不用第三方監控系統來判斷了;

經驗教訓:

1、系統需從容器級別支持外部探測,以證明自身健康

2、不要輕易引入外部agent

知識點:

1、tomcat(BIO)默認最大線程數200

關註我的微信公眾號,獲取最新故障案例分析;

技術分享圖片

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