告警
正在開會,突然釘釘告警聲響個不停,同時市場人員反饋客戶在投訴系統登不進了,報504錯誤,查看釘釘上的告警資訊,幾臺業務服務器節點全部報CPU超過告警閾值,達100%,
趕緊從會上下來,SSH登錄服務器,使用 top 命令查看,幾個Java行程CPU占用達到180%,190%,這幾個Java行程對應同一個業務服務的幾個Pod(或容器),
定位
-
使用
docker stats命令查看本節點容器資源使用情況,對占用CPU很高的容器使用docker exec -it <容器ID> bash進入, -
在容器內部執行
top命令查看,定位到占用CPU高的行程ID,使用top -Hp <行程ID>定位到占用CPU高的執行緒ID, -
使用
jstack <行程ID> > jstack.txt將行程的執行緒堆疊列印輸出, -
退出容器, 使用
docker cp <容器ID>:/usr/local/tomcat/jstack.txt ./命令將jstack檔案復制到宿主機,便于查看,獲取到jstack資訊后,趕緊重啟服務讓服務恢復可用, -
將2中占用CPU高的執行緒ID使用
pringf '%x\n' <執行緒ID>命令將執行緒ID轉換為十六進制形式,假設執行緒ID為133,則得到十六進制85,在jstack.txt檔案中定位到nid=0x85的位置,該位置即為占用CPU高執行緒的執行堆疊資訊,如下圖所示,

- 與同事確認,該處為使用一個框架的excel匯出功能,并且,匯出excel時沒有分頁,沒有限制!!!查看SQL查詢記錄,該匯出功能一次匯出50w條資料,并且每條資料都需要做轉換計算,更為糟糕的是,操作者因為匯出時久久沒有回應,于是連續點擊,幾分鐘內發起了10多次的匯出請求,,,于是,CPU被打滿,服務崩潰了,我也崩潰了,,
解決
對于此類耗資源的操作,一定要做好相應的限制,比如可以限制請求量,控制最大分頁大小,同時可以限制訪問頻率,比如同一用戶一分鐘內最多請求多少次,
再發
服務重啟后恢復,到了下午,又一臺服務器節點CPU告警,依前面步驟定位到占用CPU高的執行緒,如下
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007fa114020800 nid=0x10 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007fa114022000 nid=0x11 runnable
使用命令 jstat -gcutil <行程ID> 2000 10 查看GC情況,如圖

發現Full GC次數達到1000多次,且還在不斷增長,同時Eden區,Old區已經被占滿(也可使用jmap -heap <行程ID>查看堆記憶體各區的占用情況),使用jmap將記憶體使用情況dump出來,
jmap -dump:format=b,file=./jmap.dump 13
退出容器,使用 docker cp <容器ID>:/usr/local/tomcat/jmap.dump ./ 將dump檔案復制到宿主機目錄,下載到本地,使用 MemoryAnalyzer(下載地址:https://www.eclipse.org/mat/downloads.php )打開,如圖

如果dump檔案比較大,需要增大MemoryAnalyzer.ini組態檔中的-Xmx值
發現占用記憶體最多的是char[], String物件,通過右鍵可以查看參考物件,但點開貌似也看不出所以然來,進入記憶體泄露報告頁面,如圖

該頁面統計了堆記憶體的占用情況,并且給出疑似泄露點,在上圖中點開“see stacktrace”鏈接,進入執行緒堆疊頁面,

似曾熟悉的畫面,還是跟excel匯出有關,資料太多,導致記憶體溢位,,,于是GC頻繁,于是CPU爆了,根源還是同一個,
總結
本文以處理一次線上服務CPU 100%的實戰程序示例了在遇到Java服務造成服務器CPU消耗過高或記憶體溢位的一般處理方法,希望對大家定位線上類似問題提供參考,同時,開發實作功能時需要考慮的更深遠一些,不能停留在解決當前的場景,需要考慮資料量不斷增大時,你的實作是否還能適用,俗話說,初級程式員解決當前問題,中級程式員解決兩年后的問題,高級程式員解決五年后的問題,_,
[轉載請注明出處]
作者:雨歌
歡迎關注作者公眾號:半路雨歌,查看更多技術干貨文章

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/1183.html
標籤:其它
