阿里在GitHub上的開源工具javascript
https://github.com/oldmanpushcart/greys-anatomycss
摘要: 線上系統爲什麼常常出錯?數據庫爲什麼屢遭黑手?業務調用爲什麼頻頻失敗?連環異常堆棧案,到底是那次調用所爲? 數百臺服務器意外雪崩背後又隱藏着什麼?是軟件的扭曲仍是硬件的淪喪? 走進科學帶你瞭解Greys, Java線上問題診斷工具。前端
線上系統爲什麼常常出錯?數據庫爲什麼屢遭黑手?業務調用爲什麼頻頻失敗?連環異常堆棧案,到底是那次調用所爲?
數百臺服務器意外雪崩背後又隱藏着什麼?是軟件的扭曲仍是硬件的淪喪?
走進科學帶你瞭解Greys, Java線上問題診斷工具。java
很早的時候,咱們使用BTrace排查問題,在感嘆BTrace的強大之餘,也曾好幾回將線上系統折騰掛掉。2012年淘寶的聚石寫了HouseMD,將經常使用的幾個Btrace腳本整合在一塊兒造成一個獨立風格的應用,但其核心代碼用的是Scala,咱們沒這方面的編程維護經驗,因此只好豔羨HouseMD的才思敏捷而沒法在其上增長功能。linux
因而乎,Greys誕生了! |
PS:目前Greys僅支持Linux/Unix/Mac上的Java6+,Windows暫時沒法支持nginx
Greys是一個JVM進程執行過程當中的異常診斷工具。 在不中斷程序執行的狀況下輕鬆完成JVM相關問題排查工做。git
和HouseMD同樣,Greys-Anatomy取名同名美劇「實習醫生格蕾」,目的是向前輩致敬。代碼編寫的時候參考了BTrace和HouseMD兩個前輩的思路。程序員
有時候忽然一個問題反饋上來,須要入參才能完成定位,但偏偏沒有任何日誌。回去加上從新部署,一杯咖啡時間過去了,是否是很崩潰?github
當你通過反覆這樣幾回折騰以後變得聰明瞭,在本身的代碼的全部入參和出參地方都加上debug
日誌,但此次問題彷佛暴露在別人的代碼中了...是否是很無奈?web
忽然遇到線上一個性能問題沒法肯定究竟是哪一個環節的耗時,只能反覆抓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所加載的類、方法信息
方法執行監控
調用量,成功失敗率,響應時間
方法執行數據操做
入參、返回值、異常信息記錄與查看;支持動做回放
性能開銷渲染
跟蹤指定路徑中的方法調用軌跡、耗時
查看方法調用堆棧
monitor
、trace
等tt
命令能以時間維度紀錄下監控期內的每一次調用環境多人並行協做
基於C/S架構的任務模式甚至能讓多人同時遠程到同一進程上執行不一樣的指令、腳本,很是適合團隊一塊兒進行線上問題排查與跟蹤。Greys採用純Java編寫並留有良好的擴展,若是你有需求,只要你會Java,就能夠爲你本身編寫想要的功能。 Greys最有利的武器是他的表達式,能讓你在感覺到HouseMD集成功能便利的同時,也能發揮出自定義Btrace腳本的靈活。
1. 應用管理員擁有JVM進程權限,由他來首先在目標JVM上啓動Greys 2. 技術專家A和B平時沒有對應機器的權限,但只要網絡能訪問,他們能夠經過指定ip:port直接訪問目標機器的JVM進程,彷彿在本地通常
Greys支持在線安裝和本地安裝兩種安裝方案,安裝便可用,推薦使用在線安裝。
在線安裝(推薦)
請複製如下內容,並粘貼到命令行中。
curl -sLk http://ompc.oss.aliyuncs.com/greys/install.sh|sh
命令將會下載的啓動腳本文件greys.sh
到當前目錄,你能夠放在任何地方或加入到$PATH
中
本地安裝
在某些狀況下,目標服務器沒法訪問遠程阿里雲主機,此時你須要自行下載greys的安裝文件。
下載最新版本的GREYS
http://ompc.oss.aliyuncs.com/greys/release/greys-VERSION-bin.zip
最新的***VERSION***版本請參考主頁信息
解壓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.sh <PID>[@IP:PORT]
啓動範例
若是不指定**IP**和**PORT**,默認是**127.0.0.1**和**3658**
./greys.sh 12345
等價於
./greys.sh 12345@127.0.0.1
等價於
./greys.sh 12356@127.0.0.1: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對輸入的鎖定,從新開放讓用戶輸入信息,好比version
、sc
、sm
等。
等待停止
等待停止的命令則是須要用戶主動輸入Ctrl+D
完成的命令停止操做。命令執行後沒法當即返回最終結果,而是不斷的將中間產生的輸出源源不斷的輸出到客戶端中,這種命令好比stack
、monitor
等。
當session關閉時,全部掛在session的事務也會當即被關閉。
Greys相對於HouseMD、BTrace而言最靈活的地方就是在用表達式來靈活的支持不一樣的問題排查、分析場景。
表達式分兩種:條件表達式
與觀察表達式
條件表達式
條件表達式用在**使用表達式表達TRUE或FALSE**的場景,從1.6.0.6
版本開始,trace
、stack
、tt
、watch
命令都增長了條件表達式支持。
條件表達式將會使用greys內置的表達式解析引擎,識別OGNL語法。
特別指出的是,若是你書寫了一個錯誤的條件表達式,greys爲了兼容錯誤會解析爲FALSE。
如下是一些條件表達式使用的例子和預測結果
條件表達式 | 預測結果 | 解析結果說明 |
---|---|---|
1==1 | TRUE | 條件表達式爲真 |
true | TRUE | 條件表達式爲真 |
@@@ | FALSE | 非法的條件表達式 |
params==null | FALSE | 條件表達式爲假 |
false | FALSE | 條件表達式爲假 |
1!=1 | FALSE | 條件表達式爲假 |
觀察表達式
觀察表達式用在**使用表達式表達輸出內容**的場景,尤爲在watch
和tt
命令中,觀察表達式很是相當重要。
條件表達式將會使用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==false 和isReturn==false ,由於在方法剛開始時,還沒法肯定方法調用將會如何結束。 |
isThrow | 輔助判斷標記,當前的方法調用以拋異常的形式結束。 |
isReturn | 輔助判斷標記,當前的方法調用以正常返回的形式結束。 |
全部變量均可以在表達式中直接使用,若是在表達式中編寫了不符合OGNL腳本語法或者引入了不在表格中的變量,
對條件表達式
、檢索表達式
而言,則一概當成false
來處理
對觀察表達式
而言,則放棄當前方法調用的處理(不輸出)
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
,他們分別是:sc
、sm
、stack
、monitor
、watch
、tt
、trace
命令 | 說明 |
---|---|
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
命令會是你第一個在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 | | | |