Greys Java在线问题诊断工具
摘要:?線上系統(tǒng)為何經(jīng)常出錯(cuò)?數(shù)據(jù)庫(kù)為何屢遭黑手?業(yè)務(wù)調(diào)用為何頻頻失敗?連環(huán)異常堆棧案,究竟是那次調(diào)用所為? 數(shù)百臺(tái)服務(wù)器意外雪崩背后又隱藏著什么?是軟件的扭曲還是硬件的淪喪? 走進(jìn)科學(xué)帶你了解Greys, Java線上問(wèn)題診斷工具。
?
線上系統(tǒng)為何經(jīng)常出錯(cuò)?數(shù)據(jù)庫(kù)為何屢遭黑手?業(yè)務(wù)調(diào)用為何頻頻失敗?連環(huán)異常堆棧案,究竟是那次調(diào)用所為?
數(shù)百臺(tái)服務(wù)器意外雪崩背后又隱藏著什么?是軟件的扭曲還是硬件的淪喪?
走進(jìn)科學(xué)帶你了解Greys, Java線上問(wèn)題診斷工具。
?
?
Greys的誕生
| 很早的時(shí)候,我們使用BTrace排查問(wèn)題,在感嘆BTrace的強(qiáng)大之余,也曾好幾次將線上系統(tǒng)折騰掛掉。2012年淘寶的聚石寫了HouseMD,將常用的幾個(gè)Btrace腳本整合在一起形成一個(gè)獨(dú)立風(fēng)格的應(yīng)用,但其核心代碼用的是Scala,我們沒(méi)這方面的編程維護(hù)經(jīng)驗(yàn),所以只好艷羨HouseMD的才思敏捷而無(wú)法在其上增加功能。 ? 于是乎,Greys誕生了! |
PS:目前Greys僅支持Linux/Unix/Mac上的Java6+,Windows暫時(shí)無(wú)法支持
Greys是一個(gè)JVM進(jìn)程執(zhí)行過(guò)程中的異常診斷工具。 在不中斷程序執(zhí)行的情況下輕松完成JVM相關(guān)問(wèn)題排查工作。
和HouseMD一樣,Greys-Anatomy取名同名美劇“實(shí)習(xí)醫(yī)生格蕾”,目的是向前輩致敬。代碼編寫的時(shí)候參考了BTrace和HouseMD兩個(gè)前輩的思路。
目標(biāo)群體
-
有時(shí)候突然一個(gè)問(wèn)題反饋上來(lái),需要入?yún)⒉拍芡瓿啥ㄎ?#xff0c;但恰恰沒(méi)有任何日志。回去加上重新部署,一杯咖啡時(shí)間過(guò)去了,是不是很崩潰?
-
當(dāng)你經(jīng)過(guò)反復(fù)這樣幾次折騰之后變得聰明了,在自己的代碼的所有入?yún)⒑统鰠⒌胤蕉技由蟙ebug日志,但這次問(wèn)題似乎暴露在別人的代碼中了...是不是很無(wú)奈?
-
突然遇到線上一個(gè)性能問(wèn)題無(wú)法確定到底是哪個(gè)環(huán)節(jié)的耗時(shí),只能反復(fù)抓jstack猜,還有沒(méi)有辦法可以好好的過(guò)日子啦?
遇到以上問(wèn)題時(shí),你就是我們這類工具的目標(biāo)客戶,此類工具能利用Java6的Instrumentation特性,動(dòng)態(tài)增強(qiáng)你所指定的類,獲取你想要到的信息。
軟件特點(diǎn)
-
ClassLoader隔離
在設(shè)計(jì)和實(shí)現(xiàn)這款程序的時(shí)候,花費(fèi)了非常多的精力在隔離目標(biāo)類與Greys的ClassLoader隔離上。你可以放心大膽的使用Greys,而不用擔(dān)心Greys會(huì)干擾到現(xiàn)有業(yè)務(wù)代碼所使用的三方類庫(kù)。
-
運(yùn)行時(shí)加載
要求目標(biāo)JVM在JDK6+的基礎(chǔ)上,且當(dāng)前執(zhí)行人擁有與目標(biāo)JVM相同權(quán)限。可以做到不中斷當(dāng)前JVM而動(dòng)態(tài)進(jìn)行加載、問(wèn)題分析定位。
-
常用問(wèn)題定位命令化
Greys與BTrace、HouseMD等同類軟件最大的不同在于,她擁有我多年來(lái)業(yè)務(wù)代碼疑難雜癥定位的常用技術(shù)手段,并將這些排查思路和技巧命令化,將我的問(wèn)題定位經(jīng)驗(yàn)Share給大家。
-
表達(dá)式支持
HouseMD相比BTrace最強(qiáng)大的地方就在于能快速指定攔截的類與方法,但卻無(wú)法支持對(duì)觀察到的對(duì)象進(jìn)行展開(kāi)、條件過(guò)濾等操作。BTrace的腳本是自己所編寫,可以實(shí)現(xiàn)此類功能。但編寫學(xué)習(xí)成本很高,且容易出錯(cuò)。
表達(dá)式的引用能綜合這兩款軟件的特長(zhǎng)同時(shí)彌補(bǔ)他們的不足。目前Greys所采用的是OGNL表達(dá)式。
-
多用戶同時(shí)訪問(wèn)
遠(yuǎn)程DEBUG最大的問(wèn)題就在于,只允許一個(gè)人訪問(wèn)DEBUG端口,而且一單斷點(diǎn)條件設(shè)置不當(dāng),很有可能將其他正常的業(yè)務(wù)請(qǐng)求攔下,影響其他用戶的使用。
Greys采用的思路是做觀察者,其所設(shè)置的斷點(diǎn)不允許阻塞正常業(yè)務(wù)的流程,但你可以觀察到斷點(diǎn)所攔截到的所有信息。
-
高性能
精心用ASM設(shè)計(jì)了字節(jié)碼增強(qiáng),核心的數(shù)據(jù)結(jié)構(gòu)用數(shù)組針對(duì)實(shí)際場(chǎng)景做裁剪優(yōu)化。可以放心的用在高負(fù)載有求下的JVM環(huán)境。
-
純Java編寫
Greys定位是專業(yè)的JVM的業(yè)務(wù)問(wèn)題定位工具,既然是JVM那我們所面對(duì)的大部分就是Java程序員。我希望能Share自己在編寫軟件時(shí)候的所有技巧與思路,讓更多的Java程序員能參與開(kāi)發(fā)或從中受益。
目前已經(jīng)有非常多的熱心網(wǎng)友在給我的代碼挑錯(cuò),非常感謝這些朋友的支持!
不適合的場(chǎng)景
Greys并不萬(wàn)能,我也沒(méi)有計(jì)劃讓她能成為萬(wàn)能的問(wèn)題定位工具。所以如果你在某些場(chǎng)合能用上更專業(yè)的工具,我會(huì)非常樂(lè)意推薦你使用。
-
性能環(huán)境下的性能損耗定位
性能分析需要有更專業(yè)的軟件,我自己常用的則是JProfiler(當(dāng)然是付費(fèi)的了)。Greys雖然性能損耗很小,但其分析的維度太少,所以只適合做簡(jiǎn)單的性能損耗定位。當(dāng)你用過(guò)專業(yè)的性能分析軟件之后,就會(huì)發(fā)現(xiàn)什么叫專業(yè)!
-
開(kāi)發(fā)環(huán)境下的遠(yuǎn)程DEBUG
雖然Greys能取代部分的遠(yuǎn)程DEBUG行為,但畢竟沒(méi)不像DEBUG工具那樣可以看到局部變量的值,而且可操作性上也沒(méi)有JVM下Eclipse/IDEA等優(yōu)秀的IDE自帶的DEBUG工具這么人性化操作。
-
線上環(huán)境大規(guī)模部署
與BTrace一樣,Greys獲取到的權(quán)限太高,如果線上大規(guī)模部署會(huì)遭受黑客的攻擊,而今天我為了實(shí)現(xiàn)簡(jiǎn)單是沒(méi)有做過(guò)多的鑒權(quán)控制。
-
JDK類庫(kù)分析
JDK的類庫(kù)存放在rt.jar中,啟動(dòng)時(shí)加載到BootstrapClassLoader中(Hotspot-JVM),但由于Greys也是用Java語(yǔ)言所編寫,所以自身也用到了這些基礎(chǔ)類庫(kù),默認(rèn)情況下關(guān)閉了對(duì)這些類的增強(qiáng)。
當(dāng)然,對(duì)于Spring、ibatis、Tomcat等三方類庫(kù)是可以放心大膽使用的。
-
其它不適合場(chǎng)景
BTrace、HouseMD、Greys、JavOSize此類工具都會(huì)對(duì)Perm區(qū)、CodeCache(影響JIT)產(chǎn)生干擾,如果你的程序?qū)@兩塊非常敏感,也請(qǐng)不要在這些場(chǎng)合下使用。
我們的座右銘
讓程序解決繁瑣的事情
特性功能
交互方式
-
命令行交互
因?yàn)楹芏鄨?chǎng)景下我們都是用在遠(yuǎn)程問(wèn)題分析中(本地我就直接DEBUG了)。一般Java都會(huì)使用在Linux/BSD等類UNIX操作系統(tǒng)下。所以命令行是我最開(kāi)始不二的選擇,也是目前支持最成熟的交互方案。
-
圖形界面交互
在2.x.x.x版本中將會(huì)支持WEB方式訪問(wèn),HTTP采用websocket與后臺(tái)服務(wù)進(jìn)行交互,預(yù)計(jì)過(guò)年之后能發(fā)布上線。
內(nèi)置主要功能
-
查看已被JVM所加載的類、方法信息
-
方法執(zhí)行監(jiān)控
調(diào)用量,成功失敗率,響應(yīng)時(shí)間
-
方法執(zhí)行數(shù)據(jù)操作
入?yún)ⅰ⒎祷刂怠惓P畔⒂涗浥c查看;支持動(dòng)作回放
-
性能開(kāi)銷渲染
跟蹤指定路徑中的方法調(diào)用軌跡、耗時(shí)
-
查看方法調(diào)用堆棧
軟件特點(diǎn)
- 純Java實(shí)現(xiàn)的開(kāi)源項(xiàng)目
- 安裝使用便捷,僅一個(gè)jar包
- 可無(wú)需重啟JVM進(jìn)行CT式診斷
- 觀察變量的出入?yún)?/li>
- OGNL表達(dá)式展開(kāi)變量、過(guò)濾條件,方便你查看入?yún)ⅰ⒊鰠ⅰ惓!?dāng)前對(duì)象的各種屬性細(xì)節(jié)
- 常用分析命令集成,monitor、trace等
- 時(shí)間隧道,tt命令能以時(shí)間維度紀(jì)錄下監(jiān)控期內(nèi)的每一次調(diào)用環(huán)境
-
多人并行協(xié)作
基于C/S架構(gòu)的任務(wù)模式甚至能讓多人同時(shí)遠(yuǎn)程到同一進(jìn)程上執(zhí)行不同的指令、腳本,非常適合團(tuán)隊(duì)一起進(jìn)行線上問(wèn)題排查與跟蹤。Greys采用純Java編寫并留有良好的擴(kuò)展,如果你有需求,只要你會(huì)Java,就可以為你自己編寫想要的功能。 Greys最有利的武器是他的表達(dá)式,能讓你在感受到HouseMD集成功能便利的同時(shí),也能發(fā)揮出自定義Btrace腳本的靈活。
Greys入門
軟件安裝
Greys支持在線安裝和本地安裝兩種安裝方案,安裝即可用,推薦使用在線安裝。
-
在線安裝(推薦)
請(qǐng)復(fù)制以下內(nèi)容,并粘貼到命令行中。
curl -sLk http://ompc.oss.aliyuncs.com/greys/install.sh|sh命令將會(huì)下載的啟動(dòng)腳本文件greys.sh到當(dāng)前目錄,你可以放在任何地方或加入到$PATH中
-
本地安裝
在某些情況下,目標(biāo)服務(wù)器無(wú)法訪問(wèn)遠(yuǎn)程阿里云主機(jī),此時(shí)你需要自行下載greys的安裝文件。
下載最新版本的GREYS
http://ompc.oss.aliyuncs.com/greys/release/greys-VERSION-bin.zip
最新的***VERSION***版本請(qǐng)參考主頁(yè)信息
解壓zip文件后,執(zhí)行以下命令
cd greyssh ./install-local.sh即完成本地安裝。
常見(jiàn)安裝問(wèn)題
-
下載失敗
通常這樣的原因你需要檢查你的網(wǎng)絡(luò)是否暢通,核對(duì)是否能正確訪問(wèn)這個(gè)網(wǎng)址
http://ompc.oss.aliyuncs.com/greys/greys.sh
downloading... download failed! -
沒(méi)有權(quán)限
安裝腳本首先會(huì)將greys文件從阿里云服務(wù)器上下載到當(dāng)前執(zhí)行腳本的目錄,所以你必須要擁有當(dāng)前目錄的寫權(quán)限。
permission denied, target directory is not writable.
啟動(dòng)Greys
-
參數(shù)說(shuō)明
./greys.sh <PID>[@IP:PORT]- PID:目標(biāo)Java進(jìn)程ID(請(qǐng)確保執(zhí)行當(dāng)前執(zhí)行命令的用戶必須有足夠的權(quán)限操作對(duì)應(yīng)的Java進(jìn)程)
- IP:目標(biāo)服務(wù)器IP地址,當(dāng)遠(yuǎn)程服務(wù)開(kāi)啟之后,其他人可以通過(guò)指定IP的形式加載到對(duì)應(yīng)目標(biāo)機(jī)器的Java進(jìn)程中,從而實(shí)現(xiàn)遠(yuǎn)程協(xié)助。專門用于解決目標(biāo)主機(jī)賬號(hào)沒(méi)有權(quán)限,但對(duì)方兄弟卻非常需要你支援的時(shí)候。Greys允許多個(gè)用戶同時(shí)訪問(wèn),并且各自的命令不會(huì)相互干擾執(zhí)行。
- PORT:目標(biāo)服務(wù)器端口號(hào),設(shè)計(jì)端口號(hào)的初心則是希望解決同臺(tái)機(jī)器上存在多個(gè)Java進(jìn)程需要被Greys分析的情況,默認(rèn)的端口號(hào)是3658,如果不做區(qū)分則會(huì)引起端口沖突。
-
啟動(dòng)范例
-
如果不指定**IP**和**PORT**,默認(rèn)是**127.0.0.1**和**3658**
./greys.sh 12345等價(jià)于
./greys.sh 12345@127.0.0.1等價(jià)于
./greys.sh 12356@127.0.0.1:3658
-
-
sudo支持
成熟的線上管理環(huán)境一般都不會(huì)直接開(kāi)放JVM部署用戶權(quán)限給你,而是通過(guò)sudo-list來(lái)控制和監(jiān)控用戶的越權(quán)操作。由于greys.sh腳本中會(huì)對(duì)當(dāng)前用戶的環(huán)境變量產(chǎn)生感知,所以需要加上-H參數(shù)
sudo -u admin -H ./greys.sh 12345 -
TELNET的支持
Greys支持通過(guò)telnet來(lái)訪問(wèn)服務(wù)端,如果當(dāng)你手頭的機(jī)器沒(méi)有安裝Greys的客戶端,你可以簡(jiǎn)單的通過(guò)telnet命令來(lái)進(jìn)行訪問(wèn)。
telnet 10.232.12.113 3658當(dāng)然了,telnet命令和Greys自帶的Console在使用友好度上還是有一定的差距,不過(guò)解決應(yīng)急之需沒(méi)有問(wèn)題。
會(huì)話與任務(wù)
Greys是一個(gè)C/S架構(gòu)的程序,所以當(dāng)Client訪問(wèn)到Server時(shí),Server會(huì)維護(hù)一個(gè)session(會(huì)話),以及session的心跳、超時(shí)機(jī)制。事務(wù)(Tx)機(jī)制則是建立在session的基礎(chǔ)上,所有的命令交互都會(huì)創(chuàng)建一個(gè)事務(wù),并且產(chǎn)生對(duì)應(yīng)的隊(duì)列進(jìn)行輸出緩沖。
事務(wù)伴隨著命令的生命周期而存在,命令分兩種:
-
立即返回
立即返回的命令定義是:敲下命令后Server端立即返回最終結(jié)果,后續(xù)無(wú)持續(xù)反饋信息,釋放Client對(duì)輸入的鎖定,重新開(kāi)放讓用戶輸入信息,比如version、sc、sm等。
-
等待中止
等待中止的命令則是需要用戶主動(dòng)輸入Ctrl+D完成的命令中止操作。命令執(zhí)行后無(wú)法立即返回最終結(jié)果,而是不斷的將中間產(chǎn)生的輸出源源不斷的輸出到客戶端中,這種命令比如stack、monitor等。
當(dāng)session關(guān)閉時(shí),所有掛在session的事務(wù)也會(huì)立即被關(guān)閉。
表達(dá)式
Greys相對(duì)于HouseMD、BTrace而言最靈活的地方就是在用表達(dá)式來(lái)靈活的支持不同的問(wèn)題排查、分析場(chǎng)景。
表達(dá)式分兩種:條件表達(dá)式與觀察表達(dá)式
-
條件表達(dá)式
條件表達(dá)式用在**使用表達(dá)式表達(dá)TRUE或FALSE**的場(chǎng)景,從1.6.0.6版本開(kāi)始,trace、stack、tt、watch命令都增加了條件表達(dá)式支持。
條件表達(dá)式將會(huì)使用greys內(nèi)置的表達(dá)式解析引擎,識(shí)別OGNL語(yǔ)法。
特別指出的是,如果你書(shū)寫了一個(gè)錯(cuò)誤的條件表達(dá)式,greys為了兼容錯(cuò)誤會(huì)解析為FALSE。
以下是一些條件表達(dá)式使用的例子和預(yù)測(cè)結(jié)果
條件表達(dá)式預(yù)測(cè)結(jié)果解析結(jié)果說(shuō)明 1==1 TRUE 條件表達(dá)式為真 true TRUE 條件表達(dá)式為真 @@@ FALSE 非法的條件表達(dá)式 params==null FALSE 條件表達(dá)式為假 false FALSE 條件表達(dá)式為假 1!=1 FALSE 條件表達(dá)式為假 -
觀察表達(dá)式
觀察表達(dá)式用在**使用表達(dá)式表達(dá)輸出內(nèi)容**的場(chǎng)景,尤其在watch和tt命令中,觀察表達(dá)式非常至關(guān)重要。
條件表達(dá)式將會(huì)使用greys內(nèi)置的表達(dá)式解析引擎,識(shí)別OGNL語(yǔ)法,將表達(dá)式轉(zhuǎn)換為待輸出的對(duì)象。
以下是一些觀察表達(dá)式使用的例子
-
字符串拼接
clazz.name+"."+method.name -
數(shù)字運(yùn)算
clazz.name.length()+method.name.length()
-
表達(dá)式核心變量
無(wú)論是匹配表達(dá)式也好、觀察表達(dá)式也罷,他們核心判斷變量都是圍繞著一個(gè)greys中的通用通知對(duì)象Advice進(jìn)行。
它的簡(jiǎn)略代碼結(jié)構(gòu)如下
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 }這里列一個(gè)表格來(lái)說(shuō)明不同變量的含義
| loader | 本次調(diào)用類所在的ClassLoader |
| clazz | 本次調(diào)用類的Class引用 |
| method | 本次調(diào)用方法反射引用 |
| target | 本次調(diào)用類的實(shí)例 |
| params | 本次調(diào)用參數(shù)列表,這是一個(gè)數(shù)組,如果方法是無(wú)參方法則為空數(shù)組 |
| returnObj | 本次調(diào)用返回的對(duì)象。當(dāng)且僅當(dāng)isReturn==true成立時(shí)候有效,表明方法調(diào)用是以正常返回的方式結(jié)束。如果當(dāng)前方法無(wú)返回值void,則值為null |
| throwExp | 本次調(diào)用拋出的異常。當(dāng)且僅當(dāng)isThrow==true成立時(shí)有效,表明方法調(diào)用是以拋出異常的方式結(jié)束。 |
| isBefore | 輔助判斷標(biāo)記,當(dāng)前的通知節(jié)點(diǎn)有可能是在方法一開(kāi)始就通知,此時(shí)isBefore==true成立,同時(shí)isThrow==false和isReturn==false,因?yàn)樵诜椒▌傞_(kāi)始時(shí),還無(wú)法確定方法調(diào)用將會(huì)如何結(jié)束。 |
| isThrow | 輔助判斷標(biāo)記,當(dāng)前的方法調(diào)用以拋異常的形式結(jié)束。 |
| isReturn | 輔助判斷標(biāo)記,當(dāng)前的方法調(diào)用以正常返回的形式結(jié)束。 |
所有變量都可以在表達(dá)式中直接使用,如果在表達(dá)式中編寫了不符合OGNL腳本語(yǔ)法或者引入了不在表格中的變量,
-
對(duì)條件表達(dá)式、檢索表達(dá)式而言,則一律當(dāng)成false來(lái)處理
-
對(duì)觀察表達(dá)式而言,則放棄當(dāng)前方法調(diào)用的處理(不輸出)
JDK類支持
JDK的類默認(rèn)由BootstrapClassLoader負(fù)責(zé)加載,由于Greys自己也適用了大量的JDK類,所以我不建議使用Greys直接對(duì)JDK相關(guān)類進(jìn)行增強(qiáng)、代理。
默認(rèn)而言,Greys會(huì)拒絕執(zhí)行關(guān)于JDK類的操作命令。你需顯式用options命令打開(kāi)。
ga?>options unsafe true +--------+--------------+-------------+ | NAME | BEFORE-VALUE | AFTER-VALUE | +--------+--------------+-------------+ | unsafe | false | true | +--------+--------------+-------------+ Affect(row-cnt:1) cost in 4 ms. ga?>模式匹配
一些命令需要對(duì)類、方法進(jìn)行模式匹配過(guò)濾,從1.5.4.6及其之后的版本之后,Greys默認(rèn)支持通配符匹配,目前僅支持*和?兩個(gè)通配符,正則表達(dá)式需要顯式指定-E參數(shù)激活。
-
模式匹配舉例
-
原sc命令的正則表達(dá)式匹配
sc com\.apache\.commons\.lang\.StringUtils -
在1.5.4.6及其之后的版本中將會(huì)默認(rèn)使用通配符表達(dá)式
sc com.apache.commons.lang.StringUtils sc *lang.StringUtils -
若想繼續(xù)使用正則表達(dá)式匹配,需要顯式-E參數(shù)激活
sc -E com\.apache\.commons\.lang\.StringUtils sc -E com\..*StringUtils
-
-
支持模式匹配的命令
所有需要模式匹配的命令都支持參數(shù)-E,他們分別是:sc、sm、stack、monitor、watch、tt、trace
Greys命令詳解
命令清單
| help | 查看命令的幫助文檔,每個(gè)命令和參數(shù)都有很詳細(xì)的說(shuō)明 |
| sc | 查看JVM已加載的類信息 |
| sm | 查看已加載的方法信息 |
| monitor | 方法執(zhí)行監(jiān)控 |
| trace | 渲染方法內(nèi)部調(diào)用路徑,并輸出方法路徑上的每個(gè)節(jié)點(diǎn)上耗時(shí) |
| ptrace | 強(qiáng)化版的trace命令。通過(guò)指定渲染路徑,并可記錄下路徑中所有方法的入?yún)ⅰ⒎抵?#xff1b;與tt命令聯(lián)動(dòng)。 |
| watch | 方法執(zhí)行數(shù)據(jù)觀測(cè) |
| tt | 方法執(zhí)行數(shù)據(jù)的時(shí)空隧道,記錄下指定方法每次調(diào)用的入?yún)⒑头祷匦畔?#xff0c;并能對(duì)這些不同的時(shí)間下調(diào)用進(jìn)行觀測(cè) |
| stack | 輸出當(dāng)前方法被調(diào)用的調(diào)用路徑 |
| version | 輸出當(dāng)前目標(biāo)Java進(jìn)程所加載的Greys版本號(hào) |
| quit | 退出greys客戶端 |
| shutdown | 關(guān)閉greys服務(wù)端 |
| reset | 重置增強(qiáng)類,將被greys增強(qiáng)過(guò)的類全部還原 |
| session | 查看當(dāng)前會(huì)話 |
| jvm | 查看當(dāng)前JVM的信息 |
help命令
help命令會(huì)是你第一個(gè)在Greys中使用的命令,也會(huì)是今后使用最頻繁的命令之一,當(dāng)你在使用的過(guò)程中有任何不熟悉的疑問(wèn),請(qǐng)直接help吧~
-
查看命令清單
進(jìn)入Greys的歡迎界面后,所有命令都可以通過(guò)help獲取幫助。此時(shí)你直接輸入一個(gè)help,Greys則會(huì)返回所有命令的大概用途介紹。
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,小生感激不盡!
-
查看命令詳細(xì)幫助
help命令同時(shí)也支持對(duì)其他命令的一個(gè)解釋說(shuō)明,比如我們鍵入help watch,greys將會(huì)返回watch命令的所有參數(shù)解釋、用法介紹等詳細(xì)信息。
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**三個(gè)區(qū)域,分別是**用途說(shuō)明**、**參數(shù)列表**、**實(shí)際例子**
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?> -
參數(shù)選項(xiàng)說(shuō)明
- []中的參數(shù)為選填項(xiàng),比如[d],意思是該命令可接受一個(gè)名稱為d的選填參數(shù),且不用參數(shù)值。
- [:]中的參數(shù)則為選填,但有值的參數(shù),比如[c:]
- class-pattern/method-pattern,這兩個(gè)參數(shù)為隱性參數(shù),即在輸入的時(shí)候不需要特意聲明參數(shù)。class-pattern為類路徑.類名稱的表達(dá)式匹配,method-pattern則為方法名的表達(dá)式匹配。
sc命令
“Search-Class”的簡(jiǎn)寫,這個(gè)命令能搜索出所有已經(jīng)加載到JVM中的Class信息。
-
參數(shù)說(shuō)明
參數(shù)名稱參數(shù)說(shuō)明 class-pattern 類名表達(dá)式匹配 method-pattern 方法名表達(dá)式匹配 [d] 輸出當(dāng)前類的詳細(xì)信息,包括這個(gè)類所加載的原始文件來(lái)源、類的聲明、加載的e2ClassLoader等詳細(xì)信息。
如果一個(gè)類被多個(gè)ClassLoader所加載,則會(huì)出現(xiàn)多次[f] 輸出當(dāng)前類的成員變量信息 [E] 支持正則表達(dá)式匹配 -
使用參考
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 | sun.misc.Launcher$AppClassLoader@2a139a55 | | | `-sun.misc.Launcher$ExtClassLoader@5fb20bfd | +------------------+-----------------------------------------------+ | 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”的簡(jiǎn)寫,這個(gè)命令能搜索出所有已經(jīng)加載了Class信息的方法信息。
-
參數(shù)說(shuō)明
參數(shù)名稱參數(shù)說(shuō)明 class-pattern 類名表達(dá)式匹配 method-pattern 方法名表達(dá)式匹配 [d] 展示每個(gè)方法的詳細(xì)信息 [E] 支持正則表達(dá)式匹配 -
使用參考
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命令
對(duì)匹配class-pattern/method-pattern的類.方法的調(diào)用進(jìn)行監(jiān)控。
monitor命令是介紹到的第一個(gè)非實(shí)時(shí)返回命令,實(shí)時(shí)返回命令是輸入之后立即返回,而非實(shí)時(shí)返回的命令,則是不斷的等待目標(biāo)Java進(jìn)程返回信息,直到用戶輸入Ctrl+D為止。服務(wù)端是以任務(wù)的形式在后臺(tái)跑任務(wù),植入的代碼隨著任務(wù)的中止而被不會(huì)被執(zhí)行,所以任務(wù)關(guān)閉后,不會(huì)對(duì)原有性能產(chǎn)生太大影響,而且原則上,任何Greys的命令也不會(huì)引起任何原有業(yè)務(wù)邏輯的改變。
-
監(jiān)控的維度說(shuō)明
監(jiān)控項(xiàng)說(shuō)明 timestamp 時(shí)間戳 class Java類 method 方法(構(gòu)造方法、普通方法) total 調(diào)用次數(shù) success 成功次數(shù) fail 失敗次數(shù) rt 平均RT fail-rate 失敗率 -
參數(shù)說(shuō)明
方法擁有一個(gè)命名參數(shù)[c:],意思是統(tǒng)計(jì)周期(cycle of output),擁有一個(gè)整形的參數(shù)值
參數(shù)名稱參數(shù)說(shuō)明 [c:] 統(tǒng)計(jì)周期,默認(rèn)值為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命令
命令能主動(dòng)搜索class-pattern/method-pattern所渲染的方法調(diào)用路徑,渲染和統(tǒng)計(jì)整個(gè)調(diào)用鏈路上的所有性能開(kāi)銷和追蹤調(diào)用鏈路。
-
參數(shù)說(shuō)明
參數(shù)名稱參數(shù)說(shuō)明 class-pattern 類名表達(dá)式匹配 method-pattern 方法名表達(dá)式匹配 condition-express 條件表達(dá)式 [n:] 命令執(zhí)行次數(shù) [E] 支持正則表達(dá)式匹配 -
注意事項(xiàng)
trace能方便的幫助你定位和發(fā)現(xiàn)因RT高而導(dǎo)致的性能問(wèn)題缺陷,但其每次只能跟蹤一級(jí)方法的調(diào)用鏈路,目前暫時(shí)沒(méi)有精力去解決往下幾個(gè)層級(jí)的調(diào)用。如果真有需求可以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()是不是很眼熟,沒(méi)錯(cuò),在JProfiler等收費(fèi)軟件中你曾經(jīng)見(jiàn)識(shí)類似的功能,這里你將可以通過(guò)命令就能打印出指定調(diào)用路徑。
[10,1ms]的含義,10所代表的含義是:當(dāng)前節(jié)點(diǎn)的整體耗時(shí);1的含義是:當(dāng)前節(jié)點(diǎn)在當(dāng)前步驟的耗時(shí);兩者之間用逗號(hào)分割,單位為毫秒。
ptrace命令
-
命令解釋
命令為trace命令的強(qiáng)化版,通過(guò)指定渲染路徑來(lái)完成對(duì)方法執(zhí)行路徑的渲染過(guò)程
命令能主動(dòng)搜索tracing-path-pattern所渲染的路徑,渲染和統(tǒng)計(jì)整個(gè)調(diào)用鏈路上的所有性能開(kāi)銷和追蹤調(diào)用鏈路。
-
參數(shù)說(shuō)明
參數(shù)名稱參數(shù)說(shuō)明 class-pattern 類名表達(dá)式匹配 method-pattern 方法名表達(dá)式匹配 condition-express 條件表達(dá)式 [t] 記錄下渲染路徑上所有方法的入?yún)⑴c返回值,記錄下的返回值可以與tt命令聯(lián)動(dòng) [n:] 命令執(zhí)行次數(shù) [E] 支持正則表達(dá)式匹配 [path:] 渲染路徑表達(dá)式匹配,該參數(shù)可多次使用 [Epath:] 正則表達(dá)式渲染路徑表達(dá)式匹配,該參數(shù)可多次使用 -
使用例子
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命令
能方便的讓你觀察到指定方法的調(diào)用情況。能觀察到的范圍為:返回值、拋出異常、入?yún)?#xff0c;通過(guò)編寫OGNL表達(dá)式進(jìn)行對(duì)應(yīng)變量的查看。
-
參數(shù)說(shuō)明
watch的參數(shù)比較多,主要是因?yàn)樗茉?個(gè)不同的場(chǎng)景觀察對(duì)象
參數(shù)名稱參數(shù)說(shuō)明 class-pattern 類名表達(dá)式匹配 method-pattern 方法名表達(dá)式匹配 condition-express 條件表達(dá)式 express 觀察表達(dá)式 [b] 在**方法調(diào)用之前**觀察 [e] 在**方法異常之后**觀察 [s] 在**方法返回之后**觀察 [f] 在**方法結(jié)束之后**(正常返回和異常返回)觀察 這里重點(diǎn)要說(shuō)明的是觀察表達(dá)式,觀察表達(dá)式的構(gòu)成主要由OGNL表達(dá)式組成,所以你可以這樣寫params[0]+"$"+target,只要是一個(gè)合法的OGNL表達(dá)式,都能被正常支持。
觀察的維度也比較多,主要體現(xiàn)在參數(shù)advice的數(shù)據(jù)結(jié)構(gòu)上。Advice參數(shù)最主要是封裝了通知節(jié)點(diǎn)的所有信息。參考表達(dá)式核心變量中關(guān)于該節(jié)點(diǎn)的描述。
-
使用參考
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這里需要說(shuō)明的一個(gè)參數(shù)x,這個(gè)參數(shù)決定了輸出的結(jié)果的層級(jí)遍歷輸出對(duì)象,當(dāng)加上這個(gè)參數(shù)之后,greys會(huì)將輸出的對(duì)象按照指定層級(jí)進(jìn)行剝開(kāi)。-x 1表明展開(kāi)第1層級(jí)。
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[ username=@String[dukun], addressId=@Integer[3244], addressName=@String[ADDRESS], ]
tt命令
時(shí)間隧道命令是我在使用watch命令進(jìn)行問(wèn)題排查的時(shí)候衍生出來(lái)的想法。watch雖然很方便和靈活,但需要提前想清楚觀察表達(dá)式的拼寫,這對(duì)排查問(wèn)題而言要求太高,因?yàn)楹芏鄷r(shí)候我們并不清楚問(wèn)題出自于何方,只能靠蛛絲馬跡進(jìn)行猜測(cè)。
這個(gè)時(shí)候如果能記錄下當(dāng)時(shí)方法調(diào)用的所有入?yún)⒑头祷刂怠伋龅漠惓?huì)對(duì)整個(gè)問(wèn)題的思考與判斷非常有幫助。
于是乎,TimeTunnel命令就誕生了。
-
記錄方法的調(diào)用
-
基本用法
對(duì)于一個(gè)最基本的使用來(lái)說(shuō),就是記錄下當(dāng)前方法的每次調(diào)用環(huán)境現(xiàn)場(chǎng)。
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?> -
命令參數(shù)解析
-
-t
tt命令有很多個(gè)主參數(shù),-t就是其中之一。這個(gè)參數(shù)的表明希望記錄下類*Test的print方法的每次執(zhí)行情況。
-
-n 3
當(dāng)你執(zhí)行一個(gè)調(diào)用量不高的方法時(shí)可能你還能有足夠的時(shí)間用CTRL+D中斷tt命令記錄的過(guò)程,但如果遇到調(diào)用量非常大的方法,瞬間就能將你的JVM內(nèi)存撐爆。
此時(shí)你可以通過(guò)-n參數(shù)指定你需要記錄的次數(shù),當(dāng)達(dá)到記錄次數(shù)時(shí)greys會(huì)主動(dòng)中斷tt命令的記錄過(guò)程,避免人工操作無(wú)法停止的情況。
-
-
-
表格字段說(shuō)明
表格字段字段解釋 INDEX 時(shí)間片段記錄編號(hào),每一個(gè)編號(hào)代表著一次調(diào)用,后續(xù)tt還有很多命令都是基于此編號(hào)指定記錄操作,非常重要。 PROCESS-ID 過(guò)程編號(hào),我們認(rèn)為同一個(gè)線程的一次同步調(diào)用為一個(gè)過(guò)程 TIMESTAMP 方法執(zhí)行的本機(jī)時(shí)間,記錄了這個(gè)時(shí)間片段所發(fā)生的本機(jī)時(shí)間 COST(ms) 方法執(zhí)行的耗時(shí) IS-RET 方法是否以正常返回的形式結(jié)束 IS-EXP 方法是否以拋異常的形式結(jié)束 OBJECT 執(zhí)行對(duì)象的hashCode(),注意,曾經(jīng)有人誤認(rèn)為是對(duì)象在JVM中的無(wú)力內(nèi)存地址,但很遺憾他不是。但他能幫助你簡(jiǎn)單的標(biāo)記當(dāng)前執(zhí)行方法的類實(shí)體 CLASS 執(zhí)行的類名 METHOD 執(zhí)行的方法名 -
條件表達(dá)式
不知道大家是否有在使用過(guò)程中遇到以下困惑
- 似乎很難區(qū)分出重載的方法
- 我只需要觀察特定參數(shù),但是tt卻全部都給我記錄了下來(lái)
-
解決方法重載
tt -t *Test print params[0].length==1
通過(guò)制定參數(shù)個(gè)數(shù)的形式解決不同的方法簽名,如果參數(shù)個(gè)數(shù)一樣,你還可以這樣寫
tt -t *Test print 'params[1].class == Integer.class'
-
解決指定參數(shù)
tt -t *Test print params[0].mobile=="13989838402"
-
檢索調(diào)用記錄
當(dāng)你用tt記錄了一大片的時(shí)間片段之后,你希望能從中篩選出自己需要的時(shí)間片段,這個(gè)時(shí)候你就需要對(duì)現(xiàn)有記錄進(jìn)行檢索。
假設(shè)我們有這些記錄
ga?>tt -l +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | INDEX | PROCESS-ID | TIMESTAMP | COST(ms) | IS-RET | IS-EXP | OBJECT | CLASS | METHOD | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | 1047 | 1020 | 2015-12-06 17:03:00 | 1 | true | false | 0x2062a3d | AgentTest | printUser | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | 1048 | 1021 | 2015-12-06 17:03:01 | 0 | true | false | 0x2062a3d | AgentTest | printUser | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | 1049 | 1022 | 2015-12-06 17:03:01 | 1 | true | false | 0x2062a3d | AgentTest | printAddress | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | 1050 | 1023 | 2015-12-06 17:03:01 | 0 | true | false | 0x2062a3d | AgentTest | printUser | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | 1051 | 1024 | 2015-12-06 17:03:02 | 1 | true | false | 0x2062a3d | AgentTest | printUser | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | 1052 | 1025 | 2015-12-06 17:03:02 | 1 | false | true | 0x2062a3d | AgentTest | printAddress | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | 1053 | 1026 | 2015-12-06 17:03:02 | 0 | true | false | 0x2062a3d | AgentTest | printUser | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | 1054 | 1027 | 2015-12-06 17:03:03 | 0 | true | false | 0x2062a3d | AgentTest | printUser | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | 1055 | 1028 | 2015-12-06 17:03:03 | 0 | false | true | 0x2062a3d | AgentTest | printAddress | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | 1056 | 1029 | 2015-12-06 17:03:03 | 0 | true | false | 0x2062a3d | AgentTest | printUser | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ Affect(row-cnt:10) cost in 3 ms. ga?>我需要篩選出printAddress方法的調(diào)用信息
ga?>tt -s method.name=="printAddress" +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | INDEX | PROCESS-ID | TIMESTAMP | COST(ms) | IS-RET | IS-EXP | OBJECT | CLASS | METHOD | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | 1049 | 1022 | 2015-12-06 17:03:01 | 1 | true | false | 0x2062a3d | AgentTest | printAddress | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | 1052 | 1025 | 2015-12-06 17:03:02 | 1 | false | true | 0x2062a3d | AgentTest | printAddress | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ | 1055 | 1028 | 2015-12-06 17:03:03 | 0 | false | true | 0x2062a3d | AgentTest | printAddress | +----------+------------+----------------------+------------+----------+----------+-----------------+--------------------------------+--------------------------------+ Affect(row-cnt:3) cost in 8 ms. ga?>你需要一個(gè)-s參數(shù)。同樣的,搜索表達(dá)式的核心對(duì)象依舊是Advice對(duì)象。
-
查看調(diào)用信息
對(duì)于具體一個(gè)時(shí)間片的信息而言,你可以通過(guò)-i參數(shù)后邊跟著對(duì)應(yīng)的INDEX編號(hào)查看到他的詳細(xì)信息。
ga?>tt -i 1055 +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | INDEX | 1055 | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | PROCESS-ID | 1028 | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | GMT-CREATE | 2015-12-06 17:03:03 | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | COST(ms) | 0 | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | OBJECT | 0x2062a3d | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | CLASS | com.alibaba.AgentTest | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | METHOD | printAddress | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | IS-RETURN | false | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | IS-EXCEPTION | true | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | PARAMETERS[0] | 3789 | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | THROW-EXCEPTION | com.alibaba.AddressException: java.lang.RuntimeException: test | | | at com.alibaba.manager.DefaultAddressManager.toStringPass1(DefaultAddressManager.java:22) | | | at com.alibaba.manager.DefaultAddressManager.toString(DefaultAddressManager.java:15) | | | at com.alibaba.AgentTest.printAddress(AgentTest.java:80) | | | at com.alibaba.AgentTest.access$300(AgentTest.java:7) | | | at com.alibaba.AgentTest$3.null(Unknown Source) | | | Caused by: java.lang.RuntimeException: test | | | at com.alibaba.manager.DefaultAddressManager.throwRuntimeException(DefaultAddressManager.java:39) | | | at com.alibaba.manager.DefaultAddressManager.toStringPass2(DefaultAddressManager.java:29) | | | at com.alibaba.manager.DefaultAddressManager.toStringPass1(DefaultAddressManager.java:20) | | | ... 4 more | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | STACK | thread_name="agent-test-address-printer" thread_id=0xb;is_daemon=false;priority=5; | | | @com.alibaba.AgentTest.access$300() | | | at com.alibaba.AgentTest$3.null(null:-1) | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ Affect(row-cnt:1) cost in 7 ms. ga?> -
重做一次調(diào)用
當(dāng)你少少做了一些調(diào)整之后,你可能需要前端系統(tǒng)重新觸發(fā)一次你的調(diào)用,此時(shí)得求爺爺告奶奶的需要前端配合聯(lián)調(diào)的同學(xué)再次發(fā)起一次調(diào)用。而有些場(chǎng)景下,這個(gè)調(diào)用不是這么好觸發(fā)的。
tt命令由于保存了當(dāng)時(shí)調(diào)用的所有現(xiàn)場(chǎng)信息,所以我們可以自己主動(dòng)對(duì)一個(gè)INDEX編號(hào)的時(shí)間片自主發(fā)起一次調(diào)用,從而解放你的溝通成本。此時(shí)你需要-p參數(shù)。
ga?>tt -i 1055 -p +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | INDEX | 1055 | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | PROCESS-ID | 1028 | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | GMT-CREATE | 2015-12-06 17:03:03 | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | COST(ms) | 1 | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | OBJECT | 0x2062a3d | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | CLASS | com.alibaba.AgentTest | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | METHOD | printAddress | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | IS-RETURN | true | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | IS-EXCEPTION | false | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | PARAMETERS[0] | 3789 | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | RETURN-OBJ | 1 | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ | STACK | thread_name="ga-command-execute-daemon" thread_id=0x22;is_daemon=true;priority=9; | | | @com.github.ompc.greys.core.command.TimeTunnelCommand$6.action() | | | at com.github.ompc.greys.core.server.DefaultCommandHandler.execute(DefaultCommandHandler.java:210) | | | at com.github.ompc.greys.core.server.DefaultCommandHandler.executeCommand(DefaultCommandHandler.java:87) | | | at com.github.ompc.greys.core.server.GaServer$4.run(GaServer.java:332) | | | at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) | | | at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) | | | at java.lang.Thread.run(Thread.java:745) | +-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ Time fragment[1055] successfully replayed. Affect(row-cnt:1) cost in 2 ms. ga?>你會(huì)發(fā)現(xiàn)結(jié)果雖然一樣,但調(diào)用的路徑發(fā)生了變化,有原來(lái)的程序發(fā)起變成了greys自己的內(nèi)部線程發(fā)起的調(diào)用了。
得益于Greys的ClassLoader隔離策略,Greys在內(nèi)部自己發(fā)起線程請(qǐng)求調(diào)用的時(shí)候,依然采用的是目標(biāo)類所歸屬的ClassLoader,所以在OSGI、Tomcat容器等場(chǎng)景下,Greys依然能正確的重做此次調(diào)用。
-
需要強(qiáng)調(diào)的點(diǎn)
從1.6.0.6版本之后,應(yīng)廣大婦女群眾的要求,增加了條件表達(dá)式,這樣你可以通過(guò)簡(jiǎn)單的條件表達(dá)式解決上邊的困惑。
條件表達(dá)式也是用OGNL來(lái)編寫,核心的判斷對(duì)象依然是Advice對(duì)象。
除了tt命令之外,watch、trace、stack命令也都支持條件表達(dá)式
ThreadLocal信息丟失
很多框架偷偷的將一些環(huán)境變量信息塞到了發(fā)起調(diào)用線程的ThreadLocal中,由于調(diào)用線程發(fā)生了變化,這些ThreadLocal線程信息無(wú)法通過(guò)greys保存,所以這些信息將會(huì)丟失。
一些常見(jiàn)的CASE比如:阿里鷹眼系統(tǒng)的TraceId、阿里全鏈路平臺(tái)的壓測(cè)流量標(biāo)記位。
引用的對(duì)象
需要強(qiáng)調(diào)的是,tt命令是將當(dāng)前環(huán)境的對(duì)象引用保存起來(lái),但僅僅也只能保存一個(gè)引用而已。如果方法內(nèi)部對(duì)入?yún)⑦M(jìn)行了變更,或者返回的對(duì)象經(jīng)過(guò)了后續(xù)的處理,那么在tt查看的時(shí)候?qū)o(wú)法看到當(dāng)時(shí)最準(zhǔn)確的值。這也是為什么watch命令存在的意義。
stack命令
很多時(shí)候我們都知道一個(gè)方法被執(zhí)行,但這個(gè)方法被執(zhí)行的路徑非常多。或者你根本就不知道這個(gè)方法是從那里被執(zhí)行了,正在郁悶,正在彷徨。此時(shí)你需要的是stack命令。
-
參數(shù)說(shuō)明
參數(shù)名稱參數(shù)說(shuō)明 class-pattern 類名表達(dá)式匹配 method-pattern 方法名表達(dá)式匹配 condition-express 條件表達(dá)式 [n:] 命令執(zhí)行次數(shù) [E] 支持正則表達(dá)式匹配 -
使用例子
ga?>stack com.alibaba.manager.DefaultAddressManager newAddress Press Ctrl+D to abort. Affect(class-cnt:1 , method-cnt:1) cost in 36 ms. thread_name="agent-test-address-printer" thread_id=0xb;is_daemon=false;priority=5; @java.lang.reflect.Method.invoke()at com.alibaba.manager.DefaultAddressManager.newAddress(DefaultAddressManager.java:-1)at com.alibaba.AgentTest.printAddress(AgentTest.java:73)at com.alibaba.AgentTest.access$300(AgentTest.java:7)at com.alibaba.AgentTest$3.null(null:-1)
version命令
這估計(jì)是最好理解的一個(gè)命令了,輸出當(dāng)前Greys的版本號(hào),這里輸出的版本號(hào)不是Client的版本,而是當(dāng)前加載到目標(biāo)Java進(jìn)程中的Greys版本。
quit命令
這里說(shuō)明下與shutdown命令的區(qū)別,quit命令僅僅是將客戶端關(guān)閉,而不會(huì)將目標(biāo)Java進(jìn)程中的與Greys的Server關(guān)閉。所以如果僅僅是希望簡(jiǎn)單的推出Greys控制臺(tái),則使用quit命令足矣。
一旦Greys控制臺(tái)退出,控制臺(tái)所綁定的Session將會(huì)被關(guān)閉,Session上所有存活的事務(wù)也都會(huì)被中止并釋放。
shutdown命令
命令執(zhí)行后將會(huì)完成兩件事:
-
關(guān)閉Greys在目標(biāo)Java所加載的Socket服務(wù),所占用的端口將會(huì)被釋放,同時(shí),本地的Greys控制臺(tái)也因?yàn)檫h(yuǎn)程Socket關(guān)閉而主動(dòng)退出。
-
重置所有被Greys所增強(qiáng)的類。同reset命令。
reset命令
重置指定被Greys所增強(qiáng)的類。
session命令
會(huì)話命令是在1.6版本之后新增,整個(gè)命令的定位是維護(hù)好會(huì)話級(jí)的參數(shù)。目前可修改的就一個(gè)字符集。
-
參數(shù)說(shuō)明
參數(shù)名稱參數(shù)說(shuō)明 [c:] 指定會(huì)話字符集 -
使用例子
-
直接查看會(huì)話信息
ga?>session +------------+------------------+ | JAVA_PID | 8609 | +------------+------------------+ | SESSION_ID | 2 | +------------+------------------+ | DURATION | 300000 | +------------+------------------+ | CHARSET | UTF-8 | +------------+------------------+ | PROMPT | ga?> | +------------+------------------+ | FROM | /127.0.0.1:58186 | +------------+------------------+ | TO | /127.0.0.1:3658 | +------------+------------------+ Affect(row-cnt:1) cost in 0 ms. ga?> -
修改字符集
ga?>session -c GBK change charset before[UTF-8] -> new[GBK] Affect(row-cnt:1) cost in 26 ms.
-
jvm命令
查看當(dāng)前JVM的信息,無(wú)參數(shù)。
ga?>jvm +--------------------+-----------------------------------------------------------------------------------------------------+ | CATEGORY | INFO | +--------------------+-----------------------------------------------------------------------------------------------------+ | RUNTIME | MACHINE-NAME : 25428@vlinux-air.local | | | JVM-START-TIME : 2015-06-16 22:12:20 | | | MANAGEMENT-SPEC-VERSION : 1.2 | | | SPEC-NAME : Java Virtual Machine Specification | | | SPEC-VENDOR : Oracle Corporation | | | SPEC-VERSION : 1.8 | | | VM-NAME : Java HotSpot(TM) 64-Bit Server VM | | | VM-VENDOR : Oracle Corporation | | | VM-VERSION : 25.25-b02 | | | INPUT-ARGUMENTS : [] | | | CLASS-PATH : . | | | BOOT-CLASS-PATH : /Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home/jre/li | | | b/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Conte | | | nts/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_25.j | | | dk/Contents/Home/jre/lib/sunrsasign.jar:/Library/Java/JavaVirtualMachin | | | es/jdk1.8.0_25.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVir | | | tualMachines/jdk1.8.0_25.jdk/Contents/Home/jre/lib/jce.jar:/Library/Jav | | | a/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home/jre/lib/charsets.ja | | | r:/Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home/jre/l | | | ib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/H | | | ome/jre/classes | | | LIBRARY-PATH : /Users/vlinux/Library/Java/Extensions:/Library/Java/Extensions:/Networ | | | k/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java | | | :. | +--------------------+-----------------------------------------------------------------------------------------------------+ | CLASS-LOADING | LOADED-CLASS-COUNT : 3045 | | | TOTAL-LOADED-CLASS-COUNT : 3045 | | | UNLOADED-CLASS-COUNT : 0 | | | IS-VERBOSE : false | +--------------------+-----------------------------------------------------------------------------------------------------+ | COMPILATION | NAME : HotSpot 64-Bit Tiered Compilers | | | TOTAL-COMPILE-TIME : 8903(ms) | +--------------------+-----------------------------------------------------------------------------------------------------+ | GARBAGE-COLLECTORS | PS Scavenge : 4/40(ms) | | | [count/time] | | | PS MarkSweep : 0/0(ms) | | | [count/time] | +--------------------+-----------------------------------------------------------------------------------------------------+ | MEMORY-MANAGERS | CodeCacheManager : Code Cache | | | Metaspace Manager : Metaspace | | | Compressed Class Space | | | PS Scavenge : PS Eden Space | | | PS Survivor Space | | | PS MarkSweep : PS Eden Space | | | PS Survivor Space | | | PS Old Gen | +--------------------+-----------------------------------------------------------------------------------------------------+ | MEMORY | HEAP-MEMORY-USAGE : 163053568/134217728/1908932608/54796080 | | | [committed/init/max/used] | | | NO-HEAP-MEMORY-USAGE : 32571392/2555904/-1/31757608 | | | [committed/init/max/used] | | | PENDING-FINALIZE-COUNT : 0 | +--------------------+-----------------------------------------------------------------------------------------------------+ | OPERATING-SYSTEM | OS : Mac OS X | | | ARCH : x86_64 | | | PROCESSORS-COUNT : 4 | | | LOAD-AVERAGE : 2.50634765625 | | | VERSION : 10.10.3 | +--------------------+-----------------------------------------------------------------------------------------------------+ | THREAD | COUNT : 8 | | | DAEMON-COUNT : 7 | | | LIVE-COUNT : 9 | | | STARTED-COUNT : 19 | +--------------------+-----------------------------------------------------------------------------------------------------+ Affect cost in 22 ms.常見(jiàn)問(wèn)題答疑
安裝問(wèn)題
安裝失敗
$:>curl -sLk http://ompc.oss.aliyuncs.com/greys/install.sh|ksh downloading... greys.zip.43678 download file failed!-
問(wèn):
為什么我在安裝Greys的時(shí)候失敗了?
-
答:
Greys的安裝腳本首先先從阿里云上下載greys.zip,然后進(jìn)行解壓、安裝。所以必須要求執(zhí)行安裝腳本的用戶必須有對(duì)當(dāng)前目錄的寫權(quán)限,一般出現(xiàn)這個(gè)問(wèn)題,可以檢查網(wǎng)絡(luò)、磁盤空間以及當(dāng)前目錄是否有寫權(quán)限。
-
問(wèn):
如果我在/tmp/目錄下執(zhí)行安裝腳本,請(qǐng)問(wèn)Greys會(huì)怎么安裝?
-
答:
安裝在/tmp/greys/目錄下,該目錄下一共有三個(gè)重要文件
- /tmp/greys/greys-agent.jar
- /tmp/greys/greys-core.jar
-
/tmp/greys/greys.sh
其中g(shù)reys-core.jar為greys的程序主體,啟動(dòng)類、加載類都在這個(gè)jar包當(dāng)中;greys-agent.jar則為目標(biāo)JVM的加載引導(dǎo)程序;greys.sh為一個(gè)可執(zhí)行腳本,為Greys的啟動(dòng)腳本。
-
問(wèn):
安裝的Greys如何進(jìn)行刪除?
-
答:
Greys是一個(gè)綠色環(huán)保軟件,不會(huì)修改你的注冊(cè)表,但會(huì)在$HOME目錄下創(chuàng)建隱藏目錄$HOME/.greys,用于保存不同的版本和Jline的歷史命令,你可以直接刪除。
啟動(dòng)問(wèn)題
-
問(wèn):
我在啟動(dòng)Greys的時(shí)候報(bào)這樣的錯(cuò)誤
$:> ./greys.sh 11064start greys failed, because : Operation not permitted -
答:
Greys要求執(zhí)行執(zhí)行啟動(dòng)命令的用戶必須擁有和目標(biāo)進(jìn)程ID同樣的權(quán)限(在這個(gè)Case中,目標(biāo)進(jìn)程ID為11064),否則JVM將無(wú)法掛載Greys對(duì)應(yīng)的jar包
-
問(wèn):
我在啟動(dòng)Greys的時(shí)候報(bào)這樣的錯(cuò)誤
$:> ./greys.sh 11063start greys failed, because : No such process -
答:
目標(biāo)進(jìn)程ID不存在。報(bào)這樣的錯(cuò)誤,請(qǐng)核對(duì)你的目標(biāo)進(jìn)程是否存在。
-
答:
目標(biāo)進(jìn)程ID不是JVM進(jìn)程,或目標(biāo)JVM進(jìn)程不支持加載操作,比如低于JDK6的版本等。
一般遇到這種問(wèn)題一定要非常小心謹(jǐn)慎的執(zhí)行,如果對(duì)方進(jìn)程編程不嚴(yán)謹(jǐn),很可能會(huì)讓對(duì)方進(jìn)程CORE掉。上次我就弄死了個(gè)nginx的worker -_-!!
-
問(wèn):
啟動(dòng)之后就什么反應(yīng)也沒(méi)有,也沒(méi)有出現(xiàn)預(yù)期的ga?>提示符
-
答:
很有可能你的3658端口已經(jīng)被別的進(jìn)程占據(jù),請(qǐng)核對(duì)你當(dāng)前機(jī)器所開(kāi)的端口
netstat -anp|grep LIST解決方案也很簡(jiǎn)單,換個(gè)端口
./greys.sh 4567@127.0.0.1:6666
sudo -u方式啟動(dòng)報(bào)權(quán)限不足
請(qǐng)給你的sudo命令加上-H參數(shù)
sudo -u admin -H ./greys.sh 4567使用問(wèn)題
哪些命令會(huì)導(dǎo)致性能問(wèn)題
Greys的大部分命令性能開(kāi)銷都非常低廉,當(dāng)然前提是一次性操作的類不要太多。
是否能增強(qiáng)由BootstrapClassLoader所加載的類
當(dāng)然是可以的,但默認(rèn)我*封印*了這個(gè)能力。主要是Greys自己也使用了大量BootstrapClassLoader所加載的類,如果處理不好極其容易造成故障。
你可以通過(guò)隱藏命令options激活這個(gè)功能
ga?>options unsafe true +--------+--------------+-------------+ | NAME | BEFORE-VALUE | AFTER-VALUE | +--------+--------------+-------------+ | unsafe | false | true | +--------+--------------+-------------+ Affect(row-cnt:1) cost in 2 ms.接下來(lái)你可以嘗試增強(qiáng)系統(tǒng)類了
ga?>monitor -c 5 java.lang.String substring Press Ctrl+D or Ctrl+X to abort. Affect(class-cnt:1 , method-cnt:2) cost in 35 ms. +---------------------+------------------+-----------+-------+---------+------+------+-----------+ | timestamp | class | method | total | success | fail | rt | fail-rate | +---------------------+------------------+-----------+-------+---------+------+------+-----------+ | 2015-06-16 23:44:54 | java.lang.String | substring | 30 | 30 | 0 | 0.23 | 0.00% | +---------------------+------------------+-----------+-------+---------+------+------+-----------+但我話就放在這里,隨意增強(qiáng)系統(tǒng)類。后果自負(fù)!
其他問(wèn)題
Greys支持將信息輸出到文件中么?
支持,不過(guò)要做一些小命令。
./greys.sh 4567|tee -a ./greys.logGreys能使用在Sun JDK5的版本么?
很遺憾抱歉的說(shuō),不行。
Greys的原理和Btrace一樣,依賴了JDK6+提供的Instumentation特性,所以必須要求目標(biāo)的JDK環(huán)境是**JDK6及其以上的版本**。
理論上Greys應(yīng)該能在各種實(shí)現(xiàn)了SUN標(biāo)準(zhǔn)的各種JVM實(shí)現(xiàn)中運(yùn)行,比如JRockit、Zing等,但我自己沒(méi)有機(jī)會(huì)嘗試,若有朋友能提供環(huán)境能進(jìn)行測(cè)試并反饋測(cè),我將不勝感激。
JRE中由于缺少tools.jar,所以無(wú)法直接運(yùn)行Greys,需要稍作一些修改。同樣的也沒(méi)有需求要在JRE中運(yùn)行Greys,我這里也偷個(gè)懶,留給其他有需要的人來(lái)實(shí)現(xiàn)吧。
程序中是否有彩蛋?
有,我當(dāng)初做這個(gè)軟件的唯一目的就是希望能快速定位問(wèn)題,然后好陪她逛街。為了不忘記這個(gè)初心,我將這位她的英文名作為命令整合到了Greys中,可以嘗試找找!
維護(hù)信息
當(dāng)前版本
1.7.3.0
項(xiàng)目維護(hù)者
- 李夏馳
- 姜小逸又胖了
版本管理
-
多版本管理
從1.7.x.x版本開(kāi)始,greys.sh腳本支持自動(dòng)更新,在網(wǎng)絡(luò)允許的情況下會(huì)自動(dòng)監(jiān)測(cè)遠(yuǎn)程服務(wù)器上是否存在可升級(jí)的最新版本。
若網(wǎng)絡(luò)不可達(dá)(網(wǎng)絡(luò)隔離的環(huán)境)則需要進(jìn)行本地安裝。本地安裝也一樣會(huì)納入到多版本管理識(shí)別范圍。
-
大版本兼容性問(wèn)題
大版本之間不做任何兼容性保障,比如1.7.x.x版本的客戶端不保證能訪問(wèn)1.6.x.x啟動(dòng)的服務(wù)端。
版本號(hào)說(shuō)明
主版本.大版本.小版本.漏洞修復(fù)
-
主版本
這個(gè)版本更新說(shuō)明程序架構(gòu)體系進(jìn)行了重大升級(jí),比如之前的0.1版升級(jí)到1.0版本,整個(gè)軟件的架構(gòu)從單機(jī)版升級(jí)到了SOCKET多機(jī)版。并將Greys的性質(zhì)進(jìn)行的確定:Java版的HouseMD,但要比前輩們更強(qiáng)。
-
大版本
程序的架構(gòu)設(shè)計(jì)進(jìn)行重大改造,但不影響用戶對(duì)這款軟件的定位。
-
小版本
增加新的命令和功能
-
漏洞修復(fù)
對(duì)現(xiàn)有版本進(jìn)行漏洞修復(fù)和增強(qiáng)
版本升級(jí)說(shuō)明
- 主版本、大版本之間不做任何向下兼容的承諾。即0.1版本的Client不保證一定能正常訪問(wèn)1.0版本的Server。
- 小版本不兼容的功能會(huì)在版本升級(jí)中指出
- 漏洞修復(fù)保證所有功能向下兼容
寫在后邊
心路感悟
我編寫和維護(hù)這款軟件已經(jīng)5年了,5年中Greys也從0.1版本一直重構(gòu)到現(xiàn)在的1.7。在這個(gè)過(guò)程中我得到了許多人的幫助與建議,并在年底我計(jì)劃發(fā)布2.0版本,將開(kāi)放Greys的底層通訊協(xié)議,支持websocket訪問(wèn)。
多年的問(wèn)題排查經(jīng)驗(yàn)我沒(méi)有過(guò)多的分享,一個(gè)Java程序員個(gè)中的苦悶也無(wú)從分享,一切我都融入到了這款軟件的命令中,希望這些沉淀能幫助到可能需要到的你少走一些彎路,同時(shí)我也非常期待你們對(duì)她的反饋,這樣我將感到非常開(kāi)心和有成就感。
幫助我們
Greys的成長(zhǎng)需要大家的幫助。
?
-
分享你使用Greys的經(jīng)驗(yàn)
我非常希望能得到大家的使用反饋和經(jīng)驗(yàn)分享,如果你有,請(qǐng)將分享文章敏感信息脫敏之后郵件給我:oldmanpushcart@gmail.com,我將會(huì)分享給更多的同行。
-
幫助我完善代碼或文檔
一款軟件再好,也需要詳細(xì)的幫助文檔;一款軟件再完善,也有很多坑要埋。今天我的精力非常有限,希望能得到大家共同的幫助。
-
?
-
聯(lián)系我們
?
有問(wèn)題阿里同事可以通過(guò)旺旺找到我,阿里外的同事可以通過(guò)我的微博聯(lián)系到我。今晚的杭州大雪紛飛,明天西湖應(yīng)該非常的美麗,大家晚安。
菜鳥(niǎo)-杜琨(dukun@alibaba-inc.com)
from:?https://yq.aliyun.com/articles/2390
總結(jié)
以上是生活随笔為你收集整理的Greys Java在线问题诊断工具的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 阿里P7/P8学习路线图——技术封神之路
- 下一篇: Java SE 6 新特性 Instr