1. 程式人生 > 實用技巧 >Arthas 實踐——生產環境排查 CPU 飈高問題

Arthas 實踐——生產環境排查 CPU 飈高問題

作者 | 李昊(可以養肥)

【Arthas 官方社群正在舉行徵文活動,參加即有獎品拿~點選投稿

生產環境 CPU 告警:

13:40 收到我們的生產環境伺服器綠版 CUP 超負載告警通知。

此時心裡只有一個想法,重啟大法好,馬上登入伺服器,執行 top 發現程序 30247 和 28337 佔用 CPU 為 200 多和100 多基本佔用了 4 核的 3 核,整個過程大概用時 30 秒,維護群依然很平靜,運營的電話也沒打過來,這時候我斷定,這次問題應該影響面很小,使用者可能也暫時沒有發現,好吧,還有時間做排查。

Arthas排查過程:

  • 開啟 Arthas 工具找到對應的 30247 運單模組和 28337 支付模組,選擇運單模組進入:
java -jar arthas-boot.jar

  • 執行 dashboard 命令,執行緒 35 和 12042 不正常 CUP 佔用 49%:
dashboard

  • 執行 thread 35 thread 12042 定位程式碼行:
thread 35
thread 12042

  • 檢視程式碼,業務需求為生成一個至少包含 2 個數字的隨機字串,我們使用的統一的工具類方法,該方法中先通過 UUID.randomUUID() 隨機出一個 10 位的字元池,然後再從這個字元池中隨機需要位數的字串,如果隨機出來的 10 位字元池中都是字母,則二次隨機時候就會出現死迴圈,問題程式碼如下:
public static String getRandomStr(boolean numberFlag, int length) {
    String retStr = "";
    String strTable =
        numberFlag
            ? UUID.randomUUID().toString().replaceAll("-", "").substring(0, 10)
            : "1234567890abcdefghijkmnpqrstuvwxyz";
    int len = strTable.length();
    boolean bDone = true;
    do {
      retStr = "";
      int count = 0;
      for (int i = 0; i < length; i++) {
        double dblR = Math.random() * len;
        int intR = (int) Math.floor(dblR);
        char c = strTable.charAt(intR);
        if (('0' <= c) && (c <= '9')) {
          count++;
        }
        retStr += strTable.charAt(intR);
      }
      if (count >= 2) {
        bDone = false;
      }
    } while (bDone);
    return retStr;
  }
  • 線下模擬不到二萬次 UUID.randomUUID() 前十位會出現一次全字母的情況。

  • 最終原因是死迴圈導致的 CPU 飈高,修復程式碼,增加是否都是字母的判斷,第一次隨機出來的 10 位字元池都是字母,則重新隨機。

Arthas 常用命令:

安裝

curl -O arthas.aliyun.com/arthas-boot…
java -jar arthas-boot.jar

基礎命令

help——檢視命令幫助資訊
cat——列印檔案內容,和 linux 裡的 cat 命令類似
echo–列印引數,和 linux 裡的 echo 命令類似
grep——匹配查詢,和 linux 裡的 grep 命令類似
tee——複製標準輸入到標準輸出和指定的檔案,和 linux 裡的 tee 命令類似
pwd——返回當前的工作目錄,和 linux 命令類似
cls——清空當前螢幕區域
session——檢視當前會話的資訊
reset——重置增強類,將被 Arthas 增強過的類全部還原,Arthas 服務端關閉時會重置所有增強過的類
version——輸出當前目標 Java 程序所載入的 Arthas 版本號
history——列印命令歷史
quit——退出當前 Arthas 客戶端,其他 Arthas 客戶端不受影響
stop——關閉 Arthas 服務端,所有 Arthas 客戶端全部退出
keymap——Arthas 快捷鍵列表及自定義快捷鍵

jvm相關

dashboard——當前系統的實時資料面板
thread——檢視當前 JVM 的執行緒堆疊資訊
jvm——檢視當前 JVM 的資訊
sysprop——檢視和修改 JVM 的系統屬性
sysenv——檢視 JVM 的環境變數
vmoption——檢視和修改 JVM 裡診斷相關的 option
perfcounter——檢視當前 JVM 的 Perf Counter 資訊
logger——檢視和修改 logger
getstatic——檢視類的靜態屬性
ognl——執行 ognl 表示式
mbean——檢視 Mbean 的資訊
heapdump——dump java heap, 類似 jmap 命令的 heap dump 功能

class/classloader相關

sc——檢視 JVM 已載入的類資訊
sm——檢視已載入類的方法資訊
jad——反編譯指定已載入類的原始碼
mc——記憶體編譯器,記憶體編譯 .java 檔案為 .class 檔案
redefine——載入外部的 .class 檔案,redefine 到 JVM 裡
dump——dump 已載入類的 byte code 到特定目錄
classloader——檢視 classloader 的繼承樹,urls,類載入資訊,使用 classloader 去 getResource

monitor/watch/trace相關

  • monitor 方法執行監控

monitor -c 5 demo.MathGame primeFactors

-c 5 未統計週期預設 120s

  • watch 能觀察到的範圍為:返回值、丟擲異常、入參

watch demo.MathGame primeFactors “{params,target,returnObj}” -x 2 -b -s -n 2

-x 2 輸出結果的屬性遍歷深度
-b 方法呼叫前
-s 方法返回後
-n 2 執行2次

watch demo.MathGame primeFactors “{params[0],throwExp}” -e -x 2

-e表示丟擲異常時才觸發

  • trace 方法內部呼叫路徑,並輸出方法路徑上的每個節點上耗時

trace demo.MathGame run