快速上手Alibaba Arthas

點擊返回上層目錄

原創聲明:作者:Arnold.zhao 部落格園地址://www.cnblogs.com/zh94

Arthas

本文主要聚焦於快速上手並使用Arthas,所以對於基本的概念及使用目的此處不再贅述,詳情可參考如下鏈接

關於Arthas的基本概念可參考:

//github.com/alibaba/arthas/blob/master/README_CN.md

關於Arthas等相關JVM Debug工具的實現原理可參考:

//www.cnblogs.com/meituantech/p/11670535.html

//blog.csdn.net/u010862794/article/details/87773434

快速使用

啟動Arthas

$ $ curl -O //alibaba.github.io/arthas/arthas-demo.jar
$ $ java -jar arthas-boot.jar
* [1]: 35542
  [2]: 71560 arthas-demo.jar
  1
  此處選擇序號來表示當前所要鏈接的進程;

dashboard

介紹:輸入dashboard,按回車/enter,會展示當前進程的資訊,按ctrl+c可以中斷執行。

優勢:當在生產環境中我們需要查看當前進程內執行緒的運行情況時需要使用Linux原生的 top -p PID -H來獲取執行緒資訊;當需要查看進程的GC情況時,則需要使用jstat 或 jconsole等工具來監控記憶體的變化;而此處dashboard控制台一鍵集成,想要實時觀察GC和執行緒資訊則再也不用連續的觀察多個面板了;

thread

介紹:通過使用dashboard獲取到當前所有的執行緒運行資訊後,使用thread 1列印當前ID為1的執行緒棧資訊

優勢:當生產環境一個執行緒CPU飆高,或者鎖死的情況時,我們常規的做法是 jstack 快速列印當前進程的執行緒堆棧資訊,然後再具體分析對應的堆棧日誌來依次觀察具體的問題點;而此處當我們使用dashboard捕獲到具體的異常執行緒時,直接使用Arthas 的thread命令便可以直接列印當前指定執行緒的棧資訊,快速定位具體哪塊方法體所引起的問題;

[arthas@23846]$ thread 1
"main" Id=1 TIMED_WAITING
    at java.lang.Thread.sleep(Native Method)
    at java.lang.Thread.sleep(Thread.java:340)
    at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
    at demo.MathGame.main(MathGame.java:17)

sc

介紹:查看當前JVM中所載入的類資訊,此處表示查看當前MatchGame類的具體資訊(支援正則匹配)

優勢:通過使用sc命令可以排查你當前項目中的某些類是否被載入進來,或者在Spring中某些依賴是否被正確載入等問題

[arthas@23846]$ sc -d *MathGame		(-d表示查看detail詳情,關於當前sc命令的options參數,可以使用 sc -h 獲取具體的參數格式)
 class-info        demo.MathGame (表示當前類的包路徑資訊)
 code-source       /opt/shengheApp/arthas/arthas-demo.jar(當前類載入自那個jar包中)
 name              demo.MathGame	
 isInterface       false		 (是否是介面)
 isAnnotation      false		(是否是註解)
 isEnum            false		(是否是枚舉等等)
 isAnonymousClass  false
 isArray           false
 isLocalClass      false
 isMemberClass     false
 isPrimitive       false
 isSynthetic       false
 simple-name       MathGame		(類簡稱)
 modifier          public	(當前類的訪問修飾符)
 annotation
 interfaces
 super-class       +-java.lang.Object	(當前類的父類)
 class-loader      +-sun.misc.Launcher$AppClassLoader@70dea4e(當前類載入自那個ClassLoader)
                     +-sun.misc.Launcher$ExtClassLoader@708ab80c
 classLoaderHash   70dea4e
Affect(row-cnt:1) cost in 7 ms.

jad

介紹:使用jad來反編譯程式碼,類似於我們桌面端常用的 jd-gui等工具

優勢:生產環境更新程式碼後,很可能會出現程式碼更新後不生效等問題(比如本地程式碼打包未重新編譯等),通過使用jad反編譯程式碼後,可以快速確認當前線上程式碼是否是本地的最新程式碼等問題;並且jad反編譯後的程式碼可讀性更強,相比於jdk自帶的javap反編譯命令要好很多

[arthas@23846]$ jad demo.MathGame

ClassLoader:
+-sun.misc.Launcher$AppClassLoader@70dea4e
  +-sun.misc.Launcher$ExtClassLoader@708ab80c
Location:
/opt/shengheApp/arthas/arthas-demo.jar
/*
 * Decompiled with CFR.
 */
package demo;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class MathGame {
    private static Random random = new Random();
    public int illegalArgumentCount = 0;
 	public List<Integer> primeFactors(int number) {
        if (number < 2) {
            ++this.illegalArgumentCount;
            throw new IllegalArgumentException("number is: " + number + ", need >= 2");
        }
        ArrayList<Integer> result = new ArrayList<Integer>();
        int i = 2;
        while (i <= number) {
            if (number % i == 0) {
                result.add(i);
                number /= i;
                i = 2;
                continue;
            }
            ++i;
        }
        return result;
    }

原創聲明:作者:Arnold.zhao 部落格園地址://www.cnblogs.com/zh94

watch(重要)

通過位元組碼增強技術來實現的,會在指定類的方法中插入一些切面來實現數據統計和觀測,因此在線上、預發使用時,請盡量明確需要觀測的類、方法以及條件,診斷結束要執行 stop 或將增強過的類執行 reset 命令。

介紹:方法執行數據觀測,可以輕鬆的觀察到當前指定方法的調用情況以及通過書寫特定的OGNL表達式來進行對應變數的查看,能觀察到的範圍為當前方法的:返回值、拋出異常、入參

關於OGNL表達式的說明可參考:

官網://commons.apache.org/proper/commons-ognl/language-guide.html

部落格://cloud.tencent.com/developer/article/1554323

重要說明:

  • 當前watch的命令實際上只是給當前所要被觀察的方法增加一個切面的程式碼來實現後續的統計;

  • 而我們通過切面則可以捕獲到當前被執行方法的以下參數:如方法的入參是什麼?方法的出參是什麼?方法的執行結果是否拋出異常,拋出的異常棧是什麼等資訊;

  • 那麼這些所有被捕獲到的觀察資訊,實際上都被封裝到了一個通用的通知對象Advice的類中,當前Advice類的屬性及包含了方法的入參,也包含了方法的出參等數據

  • 而我們所書寫的OGNL表達式,實際上就是針對於當前的Advice的類屬性而寫,比如此時OGNL表達式寫的是:{params,returnObj} ,那麼此OGNL所表示的含義則是輸出當前被觀察類的入參(params),和返回結果(returnObj)的內容;

關於當前Advice通知類的具體參數都有哪些,可以參考該鏈接://arthas.gitee.io/advice-class.html

watch命令格式如下:

參數名稱 參數說明
class-pattern 類名表達式匹配
method-pattern 方法名表達式匹配
express 觀察表達式(OGNL)
condition-express 條件表達式
-b 在方法調用之前觀察
-e 在方法異常之後觀察
-s 在方法返回之後觀察
-f 在方法結束之後(正常返回和異常返回)觀察
-E 開啟正則表達式匹配,默認為通配符匹配
-x value 輸出結果的屬性遍歷深度,默認為 1

優勢:想要調試某個線上服務的偶發性BUG,但是又不能重啟線上服務的情況下,通過對當前所需監控的方法以及各個被調用的嵌套方法都增加watch監控的方式以此來實現動態DEBUG的效果

劣勢:不可以在指定的程式碼行增加動態程式碼的方式來達到DEBUG的效果;BTrace可以實現更佳的伺服器線上DEBUG效果,但使用方式相對更加重一些

執行命令解讀:
watch demo.MathGame【指定類路徑】 primeFactors【指定被觀察方法名】 "{params,returnObj}"【指定OGNL表達式】 "params[0]<0" 【條件表達式,表示當前入參<0時則觸發檢測】 -x 3【指定輸出結果的遍歷深度】 -f【表示在方法結束之後觸發觀察】

[arthas@23846]$ watch demo.MathGame primeFactors "{params,returnObj}" "params[0]<0"  -x 3 -f
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 36 ms.
ts=2020-04-29 15:47:59; [cost=0.197494ms] result=@ArrayList[
    @Object[][
        @Integer[-56580],			(當前被觀察方法的入參)
    ],
    null,							(當前被觀察方法的出參)
]
ts=2020-04-29 15:48:03; [cost=0.073761ms] result=@ArrayList[
    @Object[][
        @Integer[-161310],			(當前被觀察方法的入參)
    ],
    null,							(當前被觀察方法的出參)
]

由於我們上面執行命令時設置的條件表達式是只針對 入參 < 0 的執行方法才進行輸出,所以以上兩個輸出的結果全部是入參為負數時的數據

reset

介紹:用於還原指定的增強類,使用watch等命令對指定的方法進行了相關debug診斷完以後,則需要使用reset進行類的還原

還原指定類:
[arthas@23846]$ reset demo.MathGame
Affect(class-cnt:0 , method-cnt:0) cost in 0 ms.

還原所有類:
[arthas@23846]$ reset
Affect(class-cnt:0 , method-cnt:0) cost in 1 ms.