開會時CPU 飆升100%同事們都手忙腳亂記一次應急處理過程
阿新 • • 發佈:2020-07-14
# 告警
正在開會,突然釘釘告警聲響個不停,同時市場人員反饋客戶在投訴系統登不進了,報504錯誤。檢視釘釘上的告警資訊,幾臺業務伺服器節點全部報CPU超過告警閾值,達100%。
趕緊從會上下來,SSH登入伺服器,使用 top 命令檢視,幾個Java程序CPU佔用達到180%,190%,這幾個Java程序對應同一個業務服務的幾個Pod(或容器)。
# 定位
1. 使用 docker stats 命令檢視本節點容器資源使用情況,對佔用CPU很高的容器使用 docker exec -it <容器ID>bash 進入。
2. 在容器內部執行 top 命令檢視,定位到佔用CPU高的程序ID,使用 top -Hp <程序ID> 定位到佔用CPU高的執行緒ID。
3. 使用 jstack <程序ID> > jstack.txt 將程序的執行緒棧列印輸出。
4. 退出容器, 使用 docker cp <容器ID>:/usr/local/tomcat/jstack.txt ./ 命令將jstack檔案複製到宿主機,便於檢視。獲取到jstack資訊後,趕緊重啟服務讓服務恢復可用。
5.將2中佔用CPU高的執行緒ID使用 pringf '%x\n' <執行緒ID> 命令將執行緒ID轉換為十六進位制形式。假設執行緒ID為133,則得到十六進位制85。在jstack.txt檔案中定位到 nid=0x85的位置,該位置即為佔用CPU高執行緒的執行棧資訊。如下圖所示,
![在這裡插入圖片描述](https://img2020.cnblogs.com/other/1973721/202007/1973721-20200714195454292-684920069.png)
6. 與同事確認,該處為使用一個框架的excel匯出功能,並且,匯出excel時沒有分頁,沒有限制!!!檢視SQL查詢記錄,該匯出功能一次匯出50w條資料,並且每條資料都需要做轉換計算,更為糟糕的是,操作者因為匯出時久久沒有響應,於是連續點選,幾分鐘內發起了10多次的匯出請求。。。於是,CPU被打滿,服務崩潰了,我也崩潰了。。
# 解決
對於此類耗資源的操作,一定要做好相應的限制。比如可以限制請求量,控制最大分頁大小,同時可以限制訪問頻率,比如同一使用者一分鐘內最多請求多少次。
# 再發
服務重啟後恢復。到了下午,又一臺伺服器節點CPU告警,依前面步驟定位到佔用CPU高的執行緒,如下
```java
"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情況,如圖
![在這裡插入圖片描述](https://img2020.cnblogs.com/other/1973721/202007/1973721-20200714195454530-1484628390.png)
發現Full GC次數達到1000多次,且還在不斷增長,同時Eden區,Old區已經被佔滿(也可使用`jmap -heap <程序ID>`檢視堆記憶體各區的佔用情況),使用jmap將記憶體使用情況dump出來,
```java
jmap -dump:format=b,file=./jmap.dump 13
```
退出容器,使用 `docker cp <容器ID>:/usr/local/tomcat/jmap.dump` ./ 將dump檔案複製到宿主機目錄,下載到本地,使用 MemoryAnalyzer(下載地址:www.eclipse.org/mat/downloa… )開啟,如圖
![在這裡插入圖片描述](https://img2020.cnblogs.com/other/1973721/202007/1973721-20200714195454753-154177639.png)
> 如果dump檔案比較大,需要增大MemoryAnalyzer.ini配置檔案中的-Xmx值
發現佔用記憶體最多的是char[], String物件,通過右鍵可以檢視引用物件,但點開貌似也看不出所以然來,進入記憶體洩露報告頁面,如圖
![在這裡插入圖片描述](https://img2020.cnblogs.com/other/1973721/202007/1973721-20200714195455003-1836739024.png)
該頁面統計了堆記憶體的佔用情況,並且給出疑似洩露點,在上圖中點開“see stacktrace”連結,進入執行緒棧頁面,
![在這裡插入圖片描述](https://img2020.cnblogs.com/other/1973721/202007/1973721-20200714195456240-1859706214.png)
似曾熟悉的畫面,還是跟excel匯出有關,資料太多,導致記憶體溢位。。。於是GC頻繁,於是CPU爆了。根源還是同一個。
# 總結
本文以處理一次線上服務CPU 100%的實戰過程示例了在遇到Java服務造成伺服器CPU消耗過高或記憶體溢位的一般處理方法,希望對大家定位線上類似問題提供參考。同時,開發實現功能時需要考慮的更深遠一些,不能停留在解決當前的場景,需要考慮資料量不斷增大時,你的實現是否還能適用。俗話說,初級程式設計師解決當前問題,中級程式設計師解決兩年後的問題,高階程式設計師解決五年後的問題,^_^。
作者:[雨歌](https://juejin.im/post/5f0803d2e51d4534ba19e756)
![file](https://img2020.cnblogs.com/other/1973721/202007/1973721-20200714195457041-1657998076.gif)