這個是我很早之前解決的一個案例,其現象是系統每次上線後,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
關注個人微信公衆號,獲取最新故障案例分析;