一次GC線程佔用系統CPU過高處理過程

因爲測試人員報告說,最近訂單系統總是超時,要重啓才能恢復正常,但是第二次復現的時間不固定。

然後先是查看下應用狀態是否正常,沒有問題。

然後查看日誌,發現有很多交易報超時。

仔細查看超時的日誌,發現什麼類型的交易都有,而且超時的地方也不固定,更像是系統或者架構層面的錯誤。

趕緊看下(ps ux)linux系統的狀態。發現訂單應用的CPU已經100%,但是內存還有剩餘,內存佔用 大概30%+,下面是已經恢復後的截圖。

繼續查看應用進程中每個線程的具體情況:top -Hp pid

發現有多個線程的CPU特別高,趕緊把堆棧信息打印出來,jstack pid >>pid.stack

用線程的pid轉16進制後去裏面找,發現是下面這個東西佔用高。

這個是JVM的GC線程,至此超時的原因找到了,但是引發這個GC線程佔用CPU過高的根本原因還沒有頭緒。

因爲這套系統是給外部聯調使用,一向很穩定,最近的代碼提交日誌也沒發現啥很特別的地方。查看了下JVM的配置信息,又問了運維人員最近有沒有動這套環境,沒人動。內存又沒溢出,應該不是資源未關閉或者接連未釋放。

最後來是來看看堆棧的日誌吧。說真的堆棧日誌中線程那麼多,而且各種線程的堆棧都有,實在不好找。沒辦法只硬着頭皮看看咯。

看了網上堆棧的分析步驟,因爲是當時系統還在異常中,可以先從runnable(當前正在執行)狀態的線程找。從最後一個開始看,主要是統計哪類線程打印的信息多,發現執行定時任務的線程還比較頻繁,趕緊去看定時任務的日誌。

發現大量日誌報資源繁忙,趕緊停掉定時任務後重啓。在此期間密切監視系統資源情況,發現問題還在,CPU的使用率還是在慢慢升高。

沒辦法,關掉外部接入,不在接受請求了,系統還是沒恢復,應該正在執行的某個任務的問題。

還是去看堆棧信息,一步步排查,過了好久。。。。有個特別長的信息引起了我的注意:

因爲這段代碼是業務代碼部分的,而且這塊代碼已經在生產跑了很久沒有問題,但是我決定還是看看。重點關注:IO,資源接連,外調請求,各種循環操作。然後有個重大發現。

//每筆最低申購額度不爲空時,可申購額度應大於
while( (CommUtil.isNull(minSubsAmount) && CommUtil.compare(applyAmount,new BigDecimal(0))>0) ||(CommUtil.isNotNull(minSubsAmount) && CommUtil.compare(applyAmount,new BigDecimal(minSubsAmount))>=0) ){
						//拆分金額
BigDecimal subOrderAmt = CommUtil.compare(applyAmount,new BigDecimal(maxSubsAmount))>0 ? new BigDecimal(maxSubsAmount) : applyAmount;
FundLimitAllotList fundLimitAllotInfo = SysUtil.getInstance(FundLimitAllotList.class);
fundLimitAllotInfo.setFundCode(fundCode);
fundLimitAllotInfo.setFundName(fundName);
fundLimitAllotInfo.setFundType(null);
fundLimitAllotInfo.setYield(fundInfo.getYield());
fundLimitAllotInfo.setSubOrderAmt(subOrderAmt);//申購金額
fundLimitAllotList.add(fundLimitAllotInfo);
						
applyAmount =applyAmount.subtract(subOrderAmt);//賦值可交易的金額
leftAmount = leftAmount.subtract(subOrderAmt);//剩餘待交易金額
}

這個裏面有個循環,是用作交易拆筆之用。趕緊去交易日誌中看看今天有沒有發生這種交易,果然有且最近一筆交易發生的時間也吻合。根據傳入的參數對比代碼分析,是因爲minSubsAmount和applyAmount同時爲0時,發生while死循環,不斷創建對象,導致GC佔用CPU過高。將該處邏輯修復後重新啓動,問題解決。

雖然從上面的步驟來看,還算順利,但其實過程很曲折,因爲外部聯調環境比較複雜,又很少出錯,一直覺得不是代碼的問題(最近很少動),圍繞着zk,redis,其他系統排查了很久,還關掉一個渠道方的聯調交易(該渠道測試交易量比較大)。

這個問題很解決主要還是通過看堆棧信息,這塊自己不是很熟悉,所以接下來可能要重點充電了。

PS:CPU過高,內存溢出,請第一時間懷疑代碼,先不要嘗試通過排查系統參數,JVM配置來解決。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章