1. 程式人生 > >Greys Java線上問題診斷工具

Greys Java線上問題診斷工具

摘要: 線上系統為何經常出錯?資料庫為何屢遭黑手?業務呼叫為何頻頻失敗?連環異常堆疊案,究竟是那次呼叫所為? 數百臺伺服器意外雪崩背後又隱藏著什麼?是軟體的扭曲還是硬體的淪喪? 走進科學帶你瞭解Greys, Java線上問題診斷工具。

greys-logo-readme.png


 

線上系統為何經常出錯?資料庫為何屢遭黑手?業務呼叫為何頻頻失敗?連環異常堆疊案,究竟是那次呼叫所為?
數百臺伺服器意外雪崩背後又隱藏著什麼?是軟體的扭曲還是硬體的淪喪?
走進科學帶你瞭解Greys, Java線上問題診斷工具。

 

main-pic





 

Greys的誕生

greys-logo.png

很早的時候,我們使用BTrace排查問題,在感嘆BTrace的強大之餘,也曾好幾次將線上系統折騰掛掉。2012年淘寶的聚石寫了HouseMD,將常用的幾個Btrace指令碼整合在一起形成一個獨立風格的應用,但其核心程式碼用的是Scala,我們沒這方面的程式設計維護經驗,所以只好豔羨HouseMD的才思敏捷而無法在其上增加功能。

 

於是乎,Greys誕生了!

PS:目前Greys僅支援Linux/Unix/Mac上的Java6+,Windows暫時無法支援

Greys是一個JVM程序執行過程中的異常診斷工具。 在不中斷程式執行的情況下輕鬆完成JVM相關問題排查工作。

和HouseMD一樣,Greys-Anatomy取名同名美劇“實習醫生格蕾”,目的是向前輩致敬。程式碼編寫的時候參考了BTrace和HouseMD兩個前輩的思路。

目標群體

  • 有時候突然一個問題反饋上來,需要入參才能完成定位,但恰恰沒有任何日誌。回去加上重新部署,一杯咖啡時間過去了,是不是很崩潰?

  • 當你經過反覆這樣幾次折騰之後變得聰明瞭,在自己的程式碼的所有入參和出參地方都加上debug日誌,但這次問題似乎暴露在別人的程式碼中了...是不是很無奈?

  • 突然遇到線上一個性能問題無法確定到底是哪個環節的耗時,只能反覆抓jstack猜,還有沒有辦法可以好好的過日子啦?

遇到以上問題時,你就是我們這類工具的目標客戶,此類工具能利用Java6的Instrumentation特性,動態增強你所指定的類,獲取你想要到的資訊。

軟體特點

  • ClassLoader隔離

    在設計和實現這款程式的時候,花費了非常多的精力在隔離目標類與Greys的ClassLoader隔離上。你可以放心大膽的使用Greys,而不用擔心Greys會干擾到現有業務程式碼所使用的三方類庫。

  • 執行時載入

    要求目標JVM在JDK6+的基礎上,且當前執行人擁有與目標JVM相同許可權。可以做到不中斷當前JVM而動態進行載入、問題分析定位。

  • 常用問題定位命令化

    Greys與BTrace、HouseMD等同類軟體最大的不同在於,她擁有我多年來業務程式碼疑難雜症定位的常用技術手段,並將這些排查思路和技巧命令化,將我的問題定位經驗Share給大家。

  • 表示式支援

    HouseMD相比BTrace最強大的地方就在於能快速指定攔截的類與方法,但卻無法支援對觀察到的物件進行展開、條件過濾等操作。BTrace的指令碼是自己所編寫,可以實現此類功能。但編寫學習成本很高,且容易出錯。

    表示式的引用能綜合這兩款軟體的特長同時彌補他們的不足。目前Greys所採用的是OGNL表示式。

  • 多使用者同時訪問

    遠端DEBUG最大的問題就在於,只允許一個人訪問DEBUG埠,而且一單斷點條件設定不當,很有可能將其他正常的業務請求攔下,影響其他使用者的使用。

    Greys採用的思路是做觀察者,其所設定的斷點不允許阻塞正常業務的流程,但你可以觀察到斷點所攔截到的所有資訊。

  • 高效能

    精心用ASM設計了位元組碼增強,核心的資料結構用陣列針對實際場景做裁剪優化。可以放心的用在高負載有求下的JVM環境。

  • 純Java編寫

    Greys定位是專業的JVM的業務問題定位工具,既然是JVM那我們所面對的大部分就是Java程式設計師。我希望能Share自己在編寫軟體時候的所有技巧與思路,讓更多的Java程式設計師能參與開發或從中受益。

    目前已經有非常多的熱心網友在給我的程式碼挑錯,非常感謝這些朋友的支援!

不適合的場景

Greys並不萬能,我也沒有計劃讓她能成為萬能的問題定位工具。所以如果你在某些場合能用上更專業的工具,我會非常樂意推薦你使用。

  • 效能環境下的效能損耗定位

    效能分析需要有更專業的軟體,我自己常用的則是JProfiler(當然是付費的了)。Greys雖然效能損耗很小,但其分析的維度太少,所以只適合做簡單的效能損耗定位。當你用過專業的效能分析軟體之後,就會發現什麼叫專業!

  • 開發環境下的遠端DEBUG

    雖然Greys能取代部分的遠端DEBUG行為,但畢竟沒不像DEBUG工具那樣可以看到區域性變數的值,而且可操作性上也沒有JVM下Eclipse/IDEA等優秀的IDE自帶的DEBUG工具這麼人性化操作。

  • 線上環境大規模部署

    與BTrace一樣,Greys獲取到的許可權太高,如果線上大規模部署會遭受黑客的攻擊,而今天我為了實現簡單是沒有做過多的鑑權控制。

  • JDK類庫分析

    JDK的類庫存放在rt.jar中,啟動時載入到BootstrapClassLoader中(Hotspot-JVM),但由於Greys也是用Java語言所編寫,所以自身也用到了這些基礎類庫,預設情況下關閉了對這些類的增強。

    當然,對於Spring、ibatis、Tomcat等三方類庫是可以放心大膽使用的。

  • 其它不適合場景

    BTrace、HouseMD、Greys、JavOSize此類工具都會對Perm區、CodeCache(影響JIT)產生干擾,如果你的程式對這兩塊非常敏感,也請不要在這些場合下使用。

我們的座右銘

讓程式解決繁瑣的事情

特性功能

互動方式

  • 命令列互動

    因為很多場景下我們都是用在遠端問題分析中(本地我就直接DEBUG了)。一般Java都會使用在Linux/BSD等類UNIX作業系統下。所以命令列是我最開始不二的選擇,也是目前支援最成熟的互動方案。

  • 圖形介面互動

    2.x.x.x版本中將會支援WEB方式訪問,HTTP採用websocket與後臺服務進行互動,預計過年之後能釋出上線。

內建主要功能

  • 檢視已被JVM所載入的類、方法資訊

  • 方法執行監控

    呼叫量,成功失敗率,響應時間

  • 方法執行資料操作

    入參、返回值、異常資訊記錄與檢視;支援動作回放

  • 效能開銷渲染

    跟蹤指定路徑中的方法呼叫軌跡、耗時

  • 檢視方法呼叫堆疊

軟體特點

  • 純Java實現的開源專案
  • 安裝使用便捷,僅一個jar包
  • 可無需重啟JVM進行CT式診斷
  • 觀察變數的出入參
  • OGNL表示式展開變數、過濾條件,方便你檢視入參、出參、異常、當前物件的各種屬性細節
  • 常用分析命令整合,monitortrace
  • 時間隧道,tt命令能以時間維度紀錄下監控期內的每一次呼叫環境
  • 多人並行協作

    基於C/S架構的任務模式甚至能讓多人同時遠端到同一程序上執行不同的指令、指令碼,非常適合團隊一起進行線上問題排查與跟蹤。Greys採用純Java編寫並留有良好的擴充套件,如果你有需求,只要你會Java,就可以為你自己編寫想要的功能。 Greys最有利的武器是他的表示式,能讓你在感受到HouseMD整合功能便利的同時,也能發揮出自定義Btrace指令碼的靈活。

    多人協作

1. 應用管理員擁有JVM程序許可權,由他來首先在目標JVM上啟動Greys
2. 技術專家A和B平時沒有對應機器的許可權,但只要網路能訪問,他們可以通過指定ip:port直接訪問目標機器的JVM程序,彷彿在本地一般

Greys入門

軟體安裝

Greys支援線上安裝和本地安裝兩種安裝方案,安裝即可用,推薦使用線上安裝。

  • 線上安裝(推薦)

    請複製以下內容,並貼上到命令列中。

    curl -sLk http://ompc.oss.aliyuncs.com/greys/install.sh|sh
    

    命令將會下載的啟動指令碼檔案greys.sh到當前目錄,你可以放在任何地方或加入到$PATH

  • 本地安裝

    在某些情況下,目標伺服器無法訪問遠端阿里雲主機,此時你需要自行下載greys的安裝檔案。

  1. 下載最新版本的GREYS

    http://ompc.oss.aliyuncs.com/greys/release/greys-VERSION-bin.zip

    最新的***VERSION***版本請參考主頁資訊

  2. 解壓zip檔案後,執行以下命令

     cd greys
     sh ./install-local.sh
    

    即完成本地安裝。

常見安裝問題

  • 下載失敗

    通常這樣的原因你需要檢查你的網路是否暢通,核對是否能正確訪問這個網址

    http://ompc.oss.aliyuncs.com/greys/greys.sh

    downloading...
    download failed!
    
  • 沒有許可權

    安裝指令碼首先會將greys檔案從阿里雲伺服器上下載到當前執行指令碼的目錄,所以你必須要擁有當前目錄的寫許可權。

    permission denied, target directory is not writable.
    

啟動Greys

  • 引數說明

    ./greys.sh <PID>[@IP:PORT]
    
    • PID:目標Java程序ID(請確保執行當前執行命令的使用者必須有足夠的許可權操作對應的Java程序)
    • IP:目標伺服器IP地址,當遠端服務開啟之後,其他人可以通過指定IP的形式載入到對應目標機器的Java程序中,從而實現遠端協助。專門用於解決目標主機賬號沒有許可權,但對方兄弟卻非常需要你支援的時候。Greys允許多個使用者同時訪問,並且各自的命令不會相互干擾執行。
    • PORT:目標伺服器埠號,設計埠號的初心則是希望解決同臺機器上存在多個Java程序需要被Greys分析的情況,預設的埠號是3658,如果不做區分則會引起埠衝突。
  • 啟動範例

  • sudo支援

    成熟的線上管理環境一般都不會直接開放JVM部署使用者許可權給你,而是通過sudo-list來控制和監控使用者的越權操作。由於greys.sh指令碼中會對當前使用者的環境變數產生感知,所以需要加上-H引數

    sudo -u admin -H ./greys.sh 12345
    
  • TELNET的支援

    Greys支援通過telnet來訪問服務端,如果當你手頭的機器沒有安裝Greys的客戶端,你可以簡單的通過telnet命令來進行訪問。

    telnet 10.232.12.113 3658
    

    當然了,telnet命令和Greys自帶的Console在使用友好度上還是有一定的差距,不過解決應急之需沒有問題。

會話與任務

Greys是一個C/S架構的程式,所以當Client訪問到Server時,Server會維護一個session(會話),以及session的心跳、超時機制。事務(Tx)機制則是建立在session的基礎上,所有的命令互動都會建立一個事務,並且產生對應的佇列進行輸出緩衝。

事務伴隨著命令的生命週期而存在,命令分兩種:

  • 立即返回

    立即返回的命令定義是:敲下命令後Server端立即返回最終結果,後續無持續反饋資訊,釋放Client對輸入的鎖定,重新開放讓使用者輸入資訊,比如versionscsm等。

  • 等待中止

    等待中止的命令則是需要使用者主動輸入Ctrl+D完成的命令中止操作。命令執行後無法立即返回最終結果,而是不斷的將中間產生的輸出源源不斷的輸出到客戶端中,這種命令比如stackmonitor等。

    當session關閉時,所有掛在session的事務也會立即被關閉。

表示式

Greys相對於HouseMD、BTrace而言最靈活的地方就是在用表示式來靈活的支援不同的問題排查、分析場景。

表示式分兩種:條件表示式觀察表示式

  • 條件表示式

    條件表示式用在**使用表示式表達TRUE或FALSE**的場景,從1.6.0.6版本開始,tracestackttwatch命令都增加了條件表示式支援。

    條件表示式將會使用greys內建的表示式解析引擎,識別OGNL語法。

    特別指出的是,如果你書寫了一個錯誤的條件表示式,greys為了相容錯誤會解析為FALSE。

    以下是一些條件表示式使用的例子和預測結果

    條件表示式 預測結果 解析結果說明
    1==1 TRUE 條件表示式為真
    true TRUE 條件表示式為真
    @@@ FALSE 非法的條件表示式
    params==null FALSE 條件表示式為假
    false FALSE 條件表示式為假
    1!=1 FALSE 條件表示式為假
  • 觀察表示式

    觀察表示式用在**使用表示式表達輸出內容**的場景,尤其在watchtt命令中,觀察表示式非常至關重要。

    條件表示式將會使用greys內建的表示式解析引擎,識別OGNL語法,將表示式轉換為待輸出的物件。

    以下是一些觀察表示式使用的例子

    • 字串拼接

      clazz.name+"."+method.name
      
    • 數字運算

      clazz.name.length()+method.name.length()
      

表示式核心變數

無論是匹配表示式也好、觀察表示式也罷,他們核心判斷變數都是圍繞著一個greys中的通用通知物件Advice進行。

它的簡略程式碼結構如下

public class Advice {

    private final ClassLoader loader;
    private final Class<?> clazz;
    private final GaMethod method;
    private final Object target;
    private final Object[] params;
    private final Object returnObj;
    private final Throwable throwExp;
    private final boolean isBefore;
    private final boolean isThrow;
    private final boolean isReturn;

    // getter/setter  
}  

這裡列一個表格來說明不同變數的含義

變數名 變數解釋
loader 本次呼叫類所在的ClassLoader
clazz 本次呼叫類的Class引用
method 本次呼叫方法反射引用
target 本次呼叫類的例項
params 本次呼叫引數列表,這是一個數組,如果方法是無參方法則為空陣列
returnObj 本次呼叫返回的物件。當且僅當isReturn==true成立時候有效,表明方法呼叫是以正常返回的方式結束。如果當前方法無返回值void,則值為null
throwExp 本次呼叫丟擲的異常。當且僅當isThrow==true成立時有效,表明方法呼叫是以丟擲異常的方式結束。
isBefore 輔助判斷標記,當前的通知節點有可能是在方法一開始就通知,此時isBefore==true成立,同時isThrow==falseisReturn==false,因為在方法剛開始時,還無法確定方法呼叫將會如何結束。
isThrow 輔助判斷標記,當前的方法呼叫以拋異常的形式結束。
isReturn 輔助判斷標記,當前的方法呼叫以正常返回的形式結束。

所有變數都可以在表示式中直接使用,如果在表示式中編寫了不符合OGNL指令碼語法或者引入了不在表格中的變數,

  • 條件表示式檢索表示式而言,則一律當成false來處理

  • 觀察表示式而言,則放棄當前方法呼叫的處理(不輸出)

JDK類支援

JDK的類預設由BootstrapClassLoader負責載入,由於Greys自己也適用了大量的JDK類,所以我不建議使用Greys直接對JDK相關類進行增強、代理。

預設而言,Greys會拒絕執行關於JDK類的操作命令。你需顯式用options命令開啟。

ga?>options unsafe true
+--------+--------------+-------------+
| NAME   | BEFORE-VALUE | AFTER-VALUE |
+--------+--------------+-------------+
| unsafe | false        | true        |
+--------+--------------+-------------+
Affect(row-cnt:1) cost in 4 ms.
ga?>

模式匹配

一些命令需要對類、方法進行模式匹配過濾,從1.5.4.6及其之後的版本之後,Greys預設支援萬用字元匹配,目前僅支援*?兩個萬用字元,正則表示式需要顯式指定-E引數啟用。

  • 模式匹配舉例

    • sc命令的正則表示式匹配

      sc com\.apache\.commons\.lang\.StringUtils
      
    • 1.5.4.6及其之後的版本中將會預設使用萬用字元表示式

      sc com.apache.commons.lang.StringUtils
      sc *lang.StringUtils
      
    • 若想繼續使用正則表示式匹配,需要顯式-E引數啟用

      sc -E com\.apache\.commons\.lang\.StringUtils
      sc -E com\..*StringUtils
      
  • 支援模式匹配的命令

    所有需要模式匹配的命令都支援引數-E,他們分別是:scsmstackmonitorwatchtttrace

Greys命令詳解

命令清單

命令 說明
help 檢視命令的幫助文件,每個命令和引數都有很詳細的說明
sc 檢視JVM已載入的類資訊
sm 檢視已載入的方法資訊
monitor 方法執行監控
trace 渲染方法內部呼叫路徑,並輸出方法路徑上的每個節點上耗時
ptrace 強化版的trace命令。通過指定渲染路徑,並可記錄下路徑中所有方法的入參、返值;與tt命令聯動。
watch 方法執行資料觀測
tt 方法執行資料的時空隧道,記錄下指定方法每次呼叫的入參和返回資訊,並能對這些不同的時間下呼叫進行觀測
stack 輸出當前方法被呼叫的呼叫路徑
version 輸出當前目標Java程序所載入的Greys版本號
quit 退出greys客戶端
shutdown 關閉greys服務端
reset 重置增強類,將被greys增強過的類全部還原
session 檢視當前會話
jvm 檢視當前JVM的資訊

help命令

help命令會是你第一個在Greys中使用的命令,也會是今後使用最頻繁的命令之一,當你在使用的過程中有任何不熟悉的疑問,請直接help吧~

  • 檢視命令清單

    進入Greys的歡迎介面後,所有命令都可以通過help獲取幫助。此時你直接輸入一個help,Greys則會返回所有命令的大概用途介紹。

    ga?>help
    +----------+----------------------------------------------------------------------------------+
    |       sc | Search all the classes loaded by JVM                                             |
    +----------+----------------------------------------------------------------------------------+
    |       sm | Search the method of classes loaded by JVM                                       |
    +----------+----------------------------------------------------------------------------------+
    |  monitor | Monitor the execution of specified Class and its method                          |
    +----------+----------------------------------------------------------------------------------+
    |    watch | Display the details of specified class and method                                |
    +----------+----------------------------------------------------------------------------------+
    |       tt | Time Tunnel                                                                      |
    +----------+----------------------------------------------------------------------------------+
    |    stack | Display the stack trace of specified class and method                            |
    +----------+----------------------------------------------------------------------------------+
    |   ptrace | Display the detailed thread path stack of specified class and method             |
    +----------+----------------------------------------------------------------------------------+
    |    trace | Display the detailed thread stack of specified class and method                  |
    +----------+----------------------------------------------------------------------------------+
    |  session | Display current session information                                              |
    +----------+----------------------------------------------------------------------------------+
    |     quit | Quit Greys console                                                               |
    +----------+----------------------------------------------------------------------------------+
    |  version | Display Greys version                                                            |
    +----------+----------------------------------------------------------------------------------+
    |      jvm | Display the target JVM information                                               |
    +----------+----------------------------------------------------------------------------------+
    |    reset | Reset all the enhanced classes                                                   |
    +----------+----------------------------------------------------------------------------------+
    | shutdown | Shut down Greys server and exit the console                                      |
    +----------+----------------------------------------------------------------------------------+
    |     help | Display Greys Help                                                               |
    +----------+----------------------------------------------------------------------------------+
    Affect(row-cnt:1) cost in 9 ms.
    ga?>
    

    嗯,囋囋,我知道我的英文翻譯很爛,就不用吐槽了。期望能有人能幫我重新打理英文的幫助介面和英文xwiki,小生感激不盡!

  • 檢視命令詳細幫助

    help命令同時也支援對其他命令的一個解釋說明,比如我們鍵入help watch,greys將會返回watch命令的所有引數解釋、用法介紹等詳細資訊。

    ga?>help watch
    +---------+----------------------------------------------------------------------------------+
    |   USAGE | -[bfesx:En:] class-pattern method-pattern express condition-express              |
    |         | Display the details of specified class and method                                |
    +---------+----------------------------------------------------------------------------------+
    | OPTIONS |              [b] | Watch before invocation                                       |
    |         | -----------------+-------------------------------------------------------------- |
    |         |              [f] | Watch after invocation                                        |
    |         | -----------------+-------------------------------------------------------------- |
    |         |              [e] | Watch after throw exception                                   |
    |         | -----------------+-------------------------------------------------------------- |
    |         |              [s] | Watch after successful invocation                             |
    |         | -----------------+-------------------------------------------------------------- |
    |         |             [x:] | Expand level of object (0 by default)                         |
    |         | -----------------+-------------------------------------------------------------- |
    |         |              [E] | Enable regular expression to match (wildcard matching by def  |
    |         |                  | ault)                                                         |
    |         | -----------------+-------------------------------------------------------------- |
    |         |             [n:] | Threshold of execution times                                  |
    |         | -----------------+-------------------------------------------------------------- |
    |         |    class-pattern | Path and classname of Pattern Matching                        |
    |         | -----------------+-------------------------------------------------------------- |
    |         |   method-pattern | Method of Pattern Matching                                    |
    |         | -----------------+-------------------------------------------------------------- |
    |         |          express | express, write by OGNL.                                       |
    |         |                  |                                                               |
    |         |                  | FOR EXAMPLE    params[0]                                      |
    |         |                  |     params[0]+params[1]                                       |
    |         |                  |     returnObj                                                 |
    |         |                  |     throwExp                                                  |
    |         |                  |     target                                                    |
    |         |                  |     clazz                                                     |
    |         |                  |     method                                                    |
    |         |                  |                                                               |
    |         |                  | THE STRUCTURE                                                 |
    |         |                  |           target : the object                                 |
    |         |                  |            clazz : the object's class                         |
    |         |                  |           method : the constructor or method                  |
    |         |                  |     params[0..n] : the parameters of method                   |
    |         |                  |        returnObj : the returned object of method              |
    |         |                  |         throwExp : the throw exception of method              |
    |         |                  |         isReturn : the method ended by return                 |
    |         |                  |          isThrow : the method ended by throwing exception     |
    |         | -----------------+-------------------------------------------------------------- |
    |         |  condition-expre | Conditional expression by OGNL                                |
    |         |               ss |                                                               |
    |         |                  | FOR EXAMPLE                                                   |
    |         |                  |      TRUE : 1==1                                              |
    |         |                  |      TRUE : true                                              |
    |         |                  |     FALSE : false                                             |
    |         |                  |      TRUE : params.length>=0                                  |
    |         |                  |     FALSE : 1==2                                              |
    |         |                  |                                                               |
    |         |                  | THE STRUCTURE                                                 |
    |         |                  |           target : the object                                 |
    |         |                  |            clazz : the object's class                         |
    |         |                  |           method : the constructor or method                  |
    |         |                  |     params[0..n] : the parameters of method                   |
    |         |                  |        returnObj : the returned object of method              |
    |         |                  |         throwExp : the throw exception of method              |
    |         |                  |         isReturn : the method ended by return                 |
    |         |                  |          isThrow : the method ended by throwing exception     |
    +---------+----------------------------------------------------------------------------------+
    | EXAMPLE | watch -Eb org\.apache\.commons\.lang\.StringUtils isBlank params[0]              |
    |         | watch -b org.apache.commons.lang.StringUtils isBlank params[0]                   |
    |         | watch -f org.apache.commons.lang.StringUtils isBlank returnObj                   |
    |         | watch -bf *StringUtils isBlank params[0]                                         |
    |         | watch *StringUtils isBlank params[0]                                             |
    |         | watch *StringUtils isBlank params[0] params[0].length==1                         |
    +---------+----------------------------------------------------------------------------------+
    Affect(row-cnt:1) cost in 15 ms.
    ga?>
    
  • 幫助資訊組成

    幫助文件分成**Useage**、**Options**、**Example**三個區域,分別是**用途說明**、**引數列表**、**實際例子**

    ga?>help session
    +---------+----------------------------------------------------------------------------------+
    |   USAGE | -[c:]                                                                            |
    |         | Display current session information                                              |
    +---------+----------------------------------------------------------------------------------+
    | OPTIONS |             [c:] | Modify the character set of session                           |
    +---------+----------------------------------------------------------------------------------+
    | EXAMPLE | session                                                                          |
    |         | session -c GBK                                                                   |
    |         | session -c UTF-8                                                                 |
    +---------+----------------------------------------------------------------------------------+
    Affect(row-cnt:1) cost in 2 ms.
    ga?>
    
  • 引數選項說明

    • []中的引數為選填項,比如[d],意思是該命令可接受一個名稱為d的選填引數,且不用引數值。
    • [:]中的引數則為選填,但有值的引數,比如[c:]
    • class-patternmethod-pattern,這兩個引數為隱性引數,即在輸入的時候不需要特意宣告引數。class-pattern類路徑.類名稱的表示式匹配,method-pattern則為方法名的表示式匹配。

sc命令

“Search-Class”的簡寫,這個命令能搜尋出所有已經載入到JVM中的Class資訊。

  • 引數說明

    引數名稱 引數說明
    class-pattern 類名錶達式匹配
    method-pattern 方法名錶達式匹配
    [d] 輸出當前類的詳細資訊,包括這個類所載入的原始檔案來源、類的宣告、載入的e2ClassLoader等詳細資訊。
    如果一個類被多個ClassLoader所載入,則會出現多次
    [f] 輸出當前類的成員變數資訊
    [E] 支援正則表示式匹配
  • 使用參考

    ga?>sc -df *alibaba.Address
    +------------------+-----------------------------------------------+
    |       class-info | com.alibaba.Address                           |
    +------------------+-----------------------------------------------+
    |      code-source | /Users/vlinux/temp/agent-test/target/         |
    +------------------+-----------------------------------------------+
    |             name | com.alibaba.Address                           |
    +------------------+-----------------------------------------------+
    |      isInterface | false                                         |
    +------------------+-----------------------------------------------+
    |     isAnnotation | false                                         |
    +------------------+-----------------------------------------------+
    |           isEnum | false                                         |
    +------------------+-----------------------------------------------+
    | isAnonymousClass | false                                         |
    +------------------+-----------------------------------------------+
    |          isArray | false                                         |
    +------------------+-----------------------------------------------+
    |     isLocalClass | false                                         |
    +------------------+-----------------------------------------------+
    |    isMemberClass | false                                         |
    +------------------+-----------------------------------------------+
    |      isPrimitive | false                                         |
    +------------------+-----------------------------------------------+
    |      isSynthetic | false                                         |
    +------------------+-----------------------------------------------+
    |      simple-name | Address                                       |
    +------------------+-----------------------------------------------+
    |         modifier | public                                        |
    +------------------+-----------------------------------------------+
    |       annotation |                                               |
    +------------------+-----------------------------------------------+
    |       interfaces |                                               |
    +------------------+-----------------------------------------------+
    |      super-class | com.alibaba.CountObject                       |
    |                  |   `-java.lang.Object                          |
    +------------------+-----------------------------------------------+
    |     class-loader | [email protected]     |
    |                  |   `[email protected] |
    +------------------+-----------------------------------------------+
    |           fields | modifier : private                            |
    |                  |     type : java.lang.String                   |
    |                  |     name : username                           |
    |                  |                                               |
    |                  | modifier : private                            |
    |                  |     type : int                                |
    |                  |     name : addressId                          |
    |                  |                                               |
    |                  | modifier : private                            |
    |                  |     type : java.lang.String                   |
    |                  |     name : addressName                        |
    |                  |                                               |
    +------------------+-----------------------------------------------+
    Affect(row-cnt:1) cost in 9 ms.
    ga?>
    

sm命令

“Search-Method”的簡寫,這個命令能搜尋出所有已經載入了Class資訊的方法資訊。

  • 引數說明

    引數名稱 引數說明
    class-pattern 類名錶達式匹配
    method-pattern 方法名錶達式匹配
    [d] 展示每個方法的詳細資訊
    [E] 支援正則表示式匹配
  • 使用參考

    ga?>sm -d *alibaba.Address *
    +-----------------------------+-------------------------------------------------+
    | DECLARED-CLASS              | VISIBLE-METHOD                                  |
    +-----------------------------+-------------------------------------------------+
    | com.alibaba.Address         | declaring-class : class com.alibaba.Address     |
    |                             |     method-name : getAddressId                  |
    |                             |        modifier : public                        |
    |                             |      annotation :                               |
    |                             |      parameters :                               |
    |                             |          return : int                           |
    |                             |      exceptions :                               |
    +-----------------------------+-------------------------------------------------+
    | com.alibaba.Address         | declaring-class : class com.alibaba.Address     |
    |                             |     method-name : getAddressName                |
    |                             |        modifier : public                        |
    |                             |      annotation :                               |
    |                             |      parameters :                               |
    |                             |          return : java.lang.String              |
    |                             |      exceptions :                               |
    +-----------------------------+-------------------------------------------------+
    | com.alibaba.Address         | declaring-class : class com.alibaba.CountObject |
    |   `-com.alibaba.CountObject |     method-name : finalize                      |
    |                             |        modifier : protected                     |
    |                             |      annotation :                               |
    |                             |      parameters :                               |
    |                             |          return : void                          |
    |                             |      exceptions : java.lang.Throwable           |
    +-----------------------------+-------------------------------------------------+
    | com.alibaba.Address         | declaring-class : class com.alibaba.CountObject |
    |   `-com.alibaba.CountObject |     method-name : count                         |
    |                             |        modifier : public                        |
    |                             |      annotation :                               |
    |                             |      parameters :                               |
    |                             |          return : int                           |
    |                             |      exceptions :                               |
    +-----------------------------+-------------------------------------------------+
    Affect(row-cnt:4) cost in 9 ms.
    ga?>
    

monitor命令

對匹配class-patternmethod-pattern的類.方法的呼叫進行監控。

monitor命令是介紹到的第一個非實時返回命令,實時返回命令是輸入之後立即返回,而非實時返回的命令,則是不斷的等待目標Java程序返回資訊,直到使用者輸入Ctrl+D為止。服務端是以任務的形式在後臺跑任務,植入的程式碼隨著任務的中止而被不會被執行,所以任務關閉後,不會對原有效能產生太大影響,而且原則上,任何Greys的命令也不會引起任何原有業務邏輯的改變。

  • 監控的維度說明

    監控項 說明
    timestamp 時間戳
    class Java類
    method 方法(構造方法、普通方法)
    total 呼叫次數
    success 成功次數
    fail 失敗次數
    rt 平均RT
    fail-rate 失敗率
  • 引數說明

    方法擁有一個命名引數[c:],意思是統計週期(cycle of output),擁有一個整形的引數值

    引數名稱 引數說明
    [c:] 統計週期,預設值為120秒
  • 使用參考

    ga?>monitor -c 5 *alibaba*Test printAddress
    Press Ctrl+D to abort.
    Affect(class-cnt:1 , method-cnt:1) cost in 22 ms.
    +-----------+-------+--------+-------+---------+------+-----------+------------+------------+------------+
    | TIMESTAMP | CLASS | METHOD | TOTAL | SUCCESS | FAIL | FAIL-RATE | AVG-RT(ms) | MIN-RT(ms) | MAX-RT(ms) |
    +-----------+-------+--------+-------+---------+------+-----------+------------+------------+------------+
    
    +---------------------+-----------------------+--------------+-------+---------+------+-----------+------------+------------+------------+
    | TIMESTAMP           | CLASS                 | METHOD       | TOTAL | SUCCESS | FAIL | FAIL-RATE | AVG-RT(ms) | MIN-RT(ms) | MAX-RT(ms) |
    +---------------------+-----------------------+--------------+-------+---------+------+-----------+------------+------------+------------+
    | 2015-12-06 16:34:56 | com.alibaba.AgentTest | printAddress | 5     | 3       | 2    | 40.00%    | 0.20       | 0          | 1          |
    +---------------------+-----------------------+--------------+-------+---------+------+-----------+------------+------------+------------+
    
    +---------------------+-----------------------+--------------+-------+---------+------+-----------+------------+------------+------------+
    | TIMESTAMP           | CLASS                 | METHOD       | TOTAL | SUCCESS | FAIL | FAIL-RATE | AVG-RT(ms) | MIN-RT(ms) | MAX-RT(ms) |
    +---------------------+-----------------------+--------------+-------+---------+------+-----------+------------+------------+------------+
    | 2015-12-06 16:35:01 | com.alibaba.AgentTest | printAddress | 5     | 3       | 2    | 40.00%    | 0.00       | 0          | 0          |
    +---------------------+-----------------------+--------------+-------+---------+------+-----------+------------+------------+------------+
    
    ga?>
    
    

trace命令

命令能主動搜尋class-patternmethod-pattern所渲染的方法呼叫路徑,渲染和統計整個呼叫鏈路上的所有效能開銷和追蹤呼叫鏈路。

  • 引數說明

    引數名稱 引數說明
    class-pattern 類名錶達式匹配
    method-pattern 方法名錶達式匹配
    condition-express 條件表示式
    [n:] 命令執行次數
    [E] 支援正則表示式匹配
  • 注意事項

    trace能方便的幫助你定位和發現因RT高而導致的效能問題缺陷,但其每次只能跟蹤一級方法的呼叫鏈路,目前暫時沒有精力去解決往下幾個層級的呼叫。如果真有需求可以Issues我。

  • 使用參考

    ga?>trace com.alibaba.manager.DefaultAddressManager toStringPass2
    Press Ctrl+D to abort.
    Affect(class-cnt:1 , method-cnt:1) cost in 19 ms.
    `---+Tracing for : thread_name="agent-test-address-printer" thread_id=0xb;is_daemon=false;priority=5;
    `---+[0,0ms]com.alibaba.manager.DefaultAddressManager:toStringPass2()
        +---[0,0ms]com.alibaba.Address:getAddressId()
        +---[0,0ms]com.alibaba.Address:getAddressId()
        +---[0,0ms]java.lang.Integer:valueOf()
        +---[0,0ms]com.alibaba.Address:getAddressName()
        +---[0,0ms]com.alibaba.Address:count()
        +---[0,0ms]java.lang.Integer:valueOf()
        `---[0,0ms]java.lang.String:format()
    

    是不是很眼熟,沒錯,在JProfiler等收費軟體中你曾經見識類似的功能,這裡你將可以通過命令就能打印出指定呼叫路徑。

    [10,1ms]的含義,10所代表的含義是:當前節點的整體耗時;1的含義是:當前節點在當前步驟的耗時;兩者之間用逗號分割,單位為毫秒。

ptrace命令

  • 命令解釋

    命令為trace命令的強化版,通過指定渲染路徑來完成對方法執行路徑的渲染過程

    命令能主動搜尋tracing-path-pattern所渲染的路徑,渲染和統計整個呼叫鏈路上的所有效能開銷和追蹤呼叫鏈路。

  • 引數說明

    引數名稱 引數說明
    class-pattern 類名錶達式匹配
    method-pattern 方法名錶達式匹配
    condition-express 條件表示式
    [t] 記錄下渲染路徑上所有方法的入參與返回值,記錄下的返回值可以與tt命令聯動
    [n:] 命令執行次數
    [E] 支援正則表示式匹配
    [path:] 渲染路徑表示式匹配,該引數可多次使用
    [Epath:] 正則表示式渲染路徑表示式匹配,該引數可多次使用
  • 使用例子

    ga?>ptrace -t *alibaba*Test printAddress --path=*alibaba*
    Press Ctrl+D to abort.
    Affect(class-cnt:10 , method-cnt:36) cost in 148 ms.
    `---+pTracing for : thread_name="agent-test-address-printer" thread_id=0xb;is_daemon=false;priority=5;process=1004;
    `---+[2,2ms]com.alibaba.AgentTest:printAddress(); index=1021;
        +---+[1,1ms]com.alibaba.manager.DefaultAddressManager:newAddress(); index=1014;
        |   +---[1,1ms]com.alibaba.CountObject:<init>(); index=1012;
        |   `---[1,0ms]com.alibaba.Address:<init>(); index=1013;
        +---+[2,1ms]com.alibaba.manager.DefaultAddressManager:toString(); index=1020;
        |   +---+[2,1ms]com.alibaba.manager.DefaultAddressManager:toStringPass1(); index=1019;
        |   |   +---+[2,1ms]com.alibaba.manager.DefaultAddressManager:toStringPass2(); index=1017;
        |   |   |   +---[1,0ms]com.alibaba.Address:getAddressId(); index=1015;
        |   |   |   +---+[1,0ms]com.alibaba.manager.DefaultAddressManager:throwRuntimeException(); index=1016;
        |   |   |   |   `---[1,0ms]throw:java.lang.RuntimeException
        |   |   |   `---[1,0ms]throw:java.lang.RuntimeException
        |   |   +---[2,0ms]com.alibaba.AddressException:<init>(); index=1018;
        |   |   `---[2,0ms]throw:com.alibaba.AddressException
        |   `---[2,0ms]throw:com.alibaba.AddressException
        `---[2,0ms]throw:com.alibaba.AddressException
    +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
    |    INDEX | PROCESS-ID |            TIMESTAMP |   COST(ms) |   IS-RET |   IS-EXP |          OBJECT |                          CLASS |                         METHOD |
    +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
    |     1012 |       1004 |  2015-12-06 16:46:49 |          0 |     true |    false |        0x943cff |                    CountObject |                         <init> |
    +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
    |     1013 |       1004 |  2015-12-06 16:46:49 |          0 |     true |    false |        0x943cff |                        Address |                         <init> |
    +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
    |     1014 |       1004 |  2015-12-06 16:46:49 |          1 |     true |    false |      0x6833b8a5 |          DefaultAddressManager |                     newAddress |
    +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
    |     1015 |       1004 |  2015-12-06 16:46:49 |          0 |     true |    false |        0x943cff |                        Address |                   getAddressId |
    +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
    |     1016 |       1004 |  2015-12-06 16:46:49 |          0 |    false |     true |      0x6833b8a5 |          DefaultAddressManager |          throwRuntimeException |
    +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
    |     1017 |       1004 |  2015-12-06 16:46:49 |          0 |    false |     true |      0x6833b8a5 |          DefaultAddressManager |                  toStringPass2 |
    +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
    |     1018 |       1004 |  2015-12-06 16:46:49 |          0 |     true |    false |      0x67e7a923 |               AddressException |                         <init> |
    +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
    |     1019 |       1004 |  2015-12-06 16:46:49 |          1 |    false |     true |      0x6833b8a5 |          DefaultAddressManager |                  toStringPass1 |
    +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
    |     1020 |       1004 |  2015-12-06 16:46:49 |          1 |    false |     true |      0x6833b8a5 |          DefaultAddressManager |                       toString |
    +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
    |     1021 |       1004 |  2015-12-06 16:46:49 |          2 |    false |     true |       0x2062a3d |                      AgentTest |                   printAddress |
    +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
    

watch命令

能方便的讓你觀察到指定方法的呼叫情況。能觀察到的範圍為:返回值丟擲異常入參,通過編寫OGNL表示式進行對應變數的檢視。

  • 引數說明

    watch的引數比較多,主要是因為它能在4個不同的場景觀察物件

    引數名稱 引數說明
    class-pattern 類名錶達式匹配
    method-pattern 方法名錶達式匹配
    condition-express 條件表示式
    express 觀察表示式
    [b] 在**方法呼叫之前**觀察
    [e] 在**方法異常之後**觀察
    [s] 在**方法返回之後**觀察
    [f] 在**方法結束之後**(正常返回和異常返回)觀察

    這裡重點要說明的是觀察表示式,觀察表示式的構成主要由OGNL表示式組成,所以你可以這樣寫params[0]+"$"+target,只要是一個合法的OGNL表示式,都能被正常支援。

    觀察的維度也比較多,主要體現在引數advice的資料結構上。Advice引數最主要是封裝了通知節點的所有資訊。參考表示式核心變數中關於該節點的描述。

  • 使用參考

    ga?>watch -b *Test printAddress '"params[0]="+params[0]'
    Press Ctrl+D to abort.
    Affect(class-cnt:1 , method-cnt:1) cost in 32 ms.
    params[0]=3163
    params[0]=3164
    params[0]=3165
    params[0]=3166
    

    這裡需要說明的一個引數x,這個引數決定了輸出的結果的層級遍歷輸出物件,當加上這個引數之後,greys會將輸出的物件按照指定層級進行剝開。-x 1表明展開第1層級。

    ga?>watch -s com.alibaba.manager.DefaultAddressManager newAddress returnObj -x 1
    Press Ctrl+D to abort.
    Affect(class-cnt:1 , method-cnt:1) cost in 34 ms.
    @Address[
    [email protected][dukun],
    [email protected][3244],
    [email protected][ADDRESS],
    ]
    

tt命令

時間隧道命令是我在使用watch命令進行問題排查的時候衍生出來的想法。watch雖然很方便和靈活,但需要提前想清楚觀察表示式的拼寫,這對排查問題而言要求太高,因為很多時候我們並不清楚問題出自於何方,只能靠蛛絲馬跡進行猜測。

這個時候如果能記錄下當時方法呼叫的所有入參和返回值、丟擲的異常會對整個問題的思考與判斷非常有幫助。

於是乎,TimeTunnel命令就誕生了。

  • 記錄方法的呼叫

    • 基本用法

      對於一個最基本的使用來說,就是記錄下當前方法的每次呼叫環境現場。

      ga?>tt -t -n 3 *Test printAddress
      Press Ctrl+D to abort.
      Affect(class-cnt:1 , method-cnt:1) cost in 33 ms.
      +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
      |    INDEX | PROCESS-ID |            TIMESTAMP |   COST(ms) |   IS-RET |   IS-EXP |          OBJECT |                          CLASS |                         METHOD |
      +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
      |     1036 |       1009 |  2015-12-06 16:57:06 |          1 |    false |     true |       0x2062a3d |                      AgentTest |                   printAddress |
      +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
      |     1037 |       1010 |  2015-12-06 16:57:07 |          0 |    false |     true |       0x2062a3d |                      AgentTest |                   printAddress |
      +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
      |     1038 |       1011 |  2015-12-06 16:57:08 |          0 |     true |    false |       0x2062a3d |                      AgentTest |                   printAddress |
      +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+
      ga?>
      
    • 命令引數解析