1、是什么
你是否曾遇到過生產環境出問題,但無法進行問題線上定位,只能想辦法在開發環境重現問題???
Arthas是Alibaba開源的JAVA診斷工具。
2、可以解決什么?
(1)這個類從哪個jar包加載的?為什么會報各種類相關的Exception。
(2)更改的代碼為什么沒執行?
(3)無法線上debug的問題
(4)線上某個數據有問題,但無法線上debug,線下無法重現。
(5)是否有一個全局視角來查看系統的運行狀況?
(6)有什么辦法可以監控到JVM的實時運行狀態?
3、基本使用
(1)啟動arthas-boot
下載arthas-boot.jar,再用java -jar啟動
wget https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar
-h:表示輸出幫助信息
arthas-boot.jar是Arthas的啟動程序,啟動后,會列出所有的java進程。
如果想跟進某個java進程,只需要輸入對應的序號即可,Arthas會attach到目標進程上,并輸出日志。
(2)查看dashboard
輸入dashboard,會展示當前進程的信息
(3)通過sysenv命令獲取進程的Main class
$ sysenv | grep MAIN
JAVA_MAIN_CLASS_71560 demo.MathGame
(4)通過jad來反編譯某個類
jad 類的全限定名
(5)watch
通過watch命令來查看某個類的某個方法的返回值
watch 類的全限定名 方法名 returnObj
例如:
watch demo.MathGame primeFactors returnObj
4、進階使用
基礎命令
- help——查看命令幫助信息
- cls——清空當前屏幕區域
- session——查看當前會話的信息
- reset——重置增強類,將被 Arthas 增強過的類全部還原,Arthas 服務端關閉時會重置所有增強過的類
- version——輸出當前目標 Java 進程所加載的 Arthas 版本號
- history——打印命令歷史
- quit——退出當前 Arthas 客戶端,其他 Arthas 客戶端不受影響
- shutdown——關閉 Arthas 服務端,所有 Arthas 客戶端全部退出
- keymap——Arthas快捷鍵列表及自定義快捷鍵
jvm相關
- dashboard——當前系統的實時數據面板
- thread——查看當前 JVM 的線程堆棧信息
- jvm——查看當前 JVM 的信息
- sysprop——查看和修改JVM的系統屬性
- sysenv——查看JVM的環境變量
- New!getstatic——查看類的靜態屬性
class/classloader相關
- sc——查看JVM已加載的類信息
- sm——查看已加載類的方法信息
- dump——dump 已加載類的 byte code 到特定目錄
- redefine——加載外部的.class文件,redefine到JVM里
- jad——反編譯指定已加載類的源碼
- classloader——查看classloader的繼承樹,urls,類加載信息,使用classloader去getResource
monitor/watch/trace相關
請注意,這些命令,都通過字節碼增強技術來實現的,會在指定類的方法中插入一些切面來實現數據統計和觀測,因此在線上、預發使用時,請盡量明確需要觀測的類、方法以及條件,診斷結束要執行 shutdown 或將增強過的類執行 reset 命令。
- monitor——方法執行監控
- watch——方法執行數據觀測
- trace——方法內部調用路徑,并輸出方法路徑上的每個節點上耗時
- stack——輸出當前方法被調用的調用路徑
- tt——方法執行數據的時空隧道,記錄下指定方法每次調用的入參和返回信息,并能對這些不同的時間下調用進行觀測
options
options——查看或設置Arthas全局開關
管道
Arthas支持使用管道對上述命令的結果進行進一步的處理,如sm org.Apache.log4j.Logger | grep
- grep——搜索滿足條件的結果
- plaintext——將命令的結果去除顏色
- wc——按行統計輸出結果
后臺異步任務
當線上出現偶發的問題,比如需要watch某個條件,而這個條件一天可能才會出現一次時,異步后臺任務就派上用場了,詳情請參考這里
使用 > 將結果重寫向到日志文件,使用 & 指定命令是后臺運行,session斷開不影響任務執行(生命周期默認為1天) jobs——列出所有job kill——強制終止任務 fg——將暫停的任務拉到前臺執行 bg——將暫停的任務放到后臺執行
Web Console
通過websocket連接Arthas。
Web Console
其他特性
- 異步命令支持
- 執行結果存日志
- 批處理的支持
- ognl表達式的用法說明
5、命令詳細
(1)jad
反編譯已加載類的源碼
jad 命令將 JVM 中實際運行的 class 的 byte code 反編譯成 java 代碼,便于你理解業務邏輯;
- 在 Arthas Console 上,反編譯出來的源碼是帶語法高亮的,閱讀更方便
- 當然,反編譯出來的 java 代碼可能會存在語法錯誤,但不影響你進行閱讀理解
class-pattern 類名表達式匹配
[c:] 類所屬 ClassLoader 的 hashcode
[E] 開啟正則表達式匹配,默認為通配符匹配
1、反編譯指定方法
jad 類的全限定名 方法
例如:
- 反編譯某個類
- 反編譯某個類的某個方法
(2)watch
方法執行數據監測
讓你能方便的觀察到指定方法的調用情況。能觀察到的范圍為:返回值、拋出異常、入參,通過編寫 OGNL 表達式進行對應變量的查看。
參數:
class-pattern 類名表達式匹配
method-pattern 方法名表達式匹配
express 觀察表達式
condition-express 條件表達式
[b] 在方法調用之前觀察
[e] 在方法異常之后觀察
[s] 在方法返回之后觀察
[f] 在方法結束之后(正常返回和異常返回)觀察
[E] 開啟正則表達式匹配,默認為通配符匹配
[x:] 指定輸出結果的屬性遍歷深度,默認為 1
這里重點要說明的是觀察表達式,觀察表達式的構成主要由 ognl 表達式組成,所以你可以這樣寫"{params,returnObj}",只要是一個合法的 ognl 表達式,都能被正常支持。
「1、觀察方法出參和返回值」
$ watch com.liusy.arthas_demo.controller.ArthasController test "{params,returnObj}" -x 2
「2、觀察方法入參」
$ watch com.liusy.arthas_demo.controller.ArthasController test "{params,returnObj}" -x 2 -b
「3、同時觀察方法調用前和方法返回后」
$ watch com.liusy.arthas_demo.controller.ArthasController test "{params,returnObj}" -x 2 -b -s
「4、調整-x的值,觀察具體的方法參數值」x表示層級數
$ watch com.liusy.arthas_demo.controller.ArthasController test "{params,returnObj}" -x 3
「5、條件表達式的例子」
$ watch com.liusy.arthas_demo.controller.ArthasController test "{params, returnObj}" "params[0].id == 1" -x 2
只有滿足條件的調用,才會有響應
「6、觀察異常信息」
$ watch com.liusy.arthas_demo.controller.ArthasController test "{params, throwExp}" -e -x 2
「7、按照耗時進行過濾」
$ watch com.liusy.arthas_demo.controller.ArthasController test "{params,returnObj}" #cost>200 -x 3
?
#cost>200(單位是ms)表示只有當耗時大于200ms時才會輸出,過濾掉執行時間小于200ms的調用
?
「8、觀察當前對象中的全局屬性」
$ watch com.liusy.arthas_demo.controller.ArthasController test 'target'
如果想查看方法運行前后,當前對象中的全局屬性,可以使用target關鍵字,代表當前對象
然后使用target.field_name訪問當前對象的某個全局屬性
$ watch com.liusy.arthas_demo.controller.ArthasController test 'target.service'
(3)trace
方法內部調用路徑,并輸出方法路徑上的每個節點上耗時
trace 命令能主動搜索 class-pattern/method-pattern 對應的方法調用路徑,渲染和統計整個調用鏈路上的所有性能開銷和追蹤調用鏈路。
class-pattern 類名表達式匹配
method-pattern 方法名表達式匹配
condition-express 條件表達式
[E] 開啟正則表達式匹配,默認為通配符匹配
[n:] 命令執行次數
#cost 方法執行耗時
例如:
trace com.liusy.arthas_demo.controller.ArthasController test
按照耗時過濾:
trace com.liusy.arthas_demo.controller.ArthasController test #cost>1
(4)stack
輸出當前方法被調用的調用路徑
很多時候我們都知道一個方法被執行,但這個方法被執行的路徑非常多,或者你根本就不知道這個方法是從那里被執行了,此時你需要的是 stack 命令。
class-pattern 類名表達式匹配
method-pattern 方法名表達式匹配
condition-express 條件表達式
[E] 開啟正則表達式匹配,默認為通配符匹配
[n:] 執行次數限制
例如:
按照耗時查詢,只會打印出耗時小于30ms的堆棧情況
stack com.liusy.arthas_demo.controller.ArthasController test #cost<30
(5)sc
查看jvm已加載的類信息
Search-Class” 的簡寫,這個命令能搜索出所有已經加載到 JVM 中的 Class 信息,這個命令支持的參數有 [d]、[E]、[f] 和 [x:]。
參數說明:
class-pattern 類名表達式匹配
method-pattern 方法名表達式匹配
[d] 輸出當前類的詳細信息,包括這個類所加載的原始文件來源、類的聲明、加載的ClassLoader等詳細信息。如果一個類被多個ClassLoader所加載,則會出現多次
[E] 開啟正則表達式匹配,默認為通配符匹配
[f] 輸出當前類的成員變量信息(需要配合參數-d一起使用)
[x:] 指定輸出靜態變量時屬性的遍歷深度,默認為 0,即直接使用 toString 輸出
?
class-pattern支持全限定名,如com.liusy.demo,也支持com/liusy/demo這樣的格式.
?
?
sc 默認開啟了子類匹配功能,也就是說所有當前類的子類也會被搜索出來,想要精確的匹配,請打開options disable-sub-class true開關
?
1、查看類的靜態變量信息
sc -df 類的全限定名
(6)sm
查看已加載類的方法信息
“Search-Method” 的簡寫,這個命令能搜索出所有已經加載了 Class 信息的方法信息。
sm 命令只能看到由當前類所聲明 (declaring) 的方法,父類則無法看到。
class-pattern 類名表達式匹配
method-pattern 方法名表達式匹配
[d] 展示每個方法的詳細信息
[E] 開啟正則表達式匹配,默認為通配符匹配
(7)dashboard
當前進程的實時數據面板(包括內存,線程等信息),按ctrl+c退出。
數據說明:
ID: Java級別的線程ID,注意這個ID不能跟jstack中的nativeID一一對應
NAME: 線程名
GROUP: 線程組名
PRIORITY: 線程優先級, 1~10之間的數字,越大表示優先級越高
STATE: 線程的狀態
CPU%: 線程消耗的cpu占比,采樣100ms,將所有線程在這100ms內的cpu使用量求和,再算出每個線程的cpu使用占比。
TIME: 線程運行總時間,數據格式為分:秒
INTERRUPTED: 線程當前的中斷位狀態
DAEMON: 是否是daemon線程
(8)Thread
查看當前線程信息,查看線程的堆棧。
參數說明:
id 線程id
[n:] 指定最忙的前N個線程并打印堆棧
[b] 找出當前阻塞其他線程的線程
[i <value>] 指定cpu占比統計的采樣間隔,單位為毫秒
1、一鍵展示當前最忙的前n個線程并打印堆棧。
thread -n 3
2、不帶參數時,顯示所有線程的信息
3、顯示指定線程的運行堆棧
therad id
4、找出當前阻塞其他線程的線程
thread -b
目前只支持找出synchronized關鍵字阻塞住的線程, 如果是java.util.concurrent.Lock, 目前還不支持
5、指定采樣時間間隔
thread -i 時間
例如:thread -n 3 -i 1000
(9)jvm
查看當前JVM信息
信息說明:
THREAD相關
COUNT: JVM當前活躍的線程數
DAEMON-COUNT: JVM當前活躍的守護線程數
PEAK-COUNT: 從JVM啟動開始曾經活著的最大線程數
STARTED-COUNT: 從JVM啟動開始總共啟動過的線程次數
DEADLOCK-COUNT: JVM當前死鎖的線程數
文件描述符相關
MAX-FILE-DESCRIPTOR-COUNT:JVM進程最大可以打開的文件描述符數
OPEN-FILE-DESCRIPTOR-COUNT:JVM當前打開的文件描述符數
(10)sysprop
查看當前jvm的系統屬性(system property)
1、查看所有屬性
sysprop
2、查看某個屬性
sysprop java.version
3、修改某個屬性值
sysprop key value
(11)sysenv
查看當前jvm的環境屬性(system environment variables)
1、查看所有環境變量
sysenv
2、查看單個環境變量
sysenv USER
(12)getstatic
可以查看類的靜態屬性
getstatic class_name field_name
如果該靜態屬性是一個復雜對象,還可以支持在該屬性上通過ognl表示進行遍歷,過濾,訪問對象的內部屬性等操作。
例如,假設n是一個Map,Map的Key是一個Enum,我們想過濾出Map中Key為某個Enum的值,可以寫如下命令
$ getstatic com.alibaba.arthas.Test n 'entrySet().iterator.{? #this.key.name()=="STOP"}'
field: n
@ArrayList[
@Node[STOP=bbb],
]
(13)ognl
執行ognl表達式
參數說明:
express 執行的表達式
[c:] 執行表達式的 ClassLoader 的 hashcode,默認值是SystemClassLoader
[x] 結果對象的展開層次,默認值1
1、調用靜態函數
ognl '@java.lang.System@out.println("hello")'
2、獲取靜態類的靜態字段
ognl '@demo.MathGame@random'
3、執行多行表達式,賦值給臨時變量,返回一個list
$ ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}'
@ArrayList[
@String[/opt/java/8.0.181-zulu/jre],
@String[OpenJDK Runtime Environment],
]
(14)dump
dump已加載類的bytecode到特定目錄
參數說明:
class-pattern 類名表達式匹配
[c:] 類所屬 ClassLoader 的 hashcode
[E] 開啟正則表達式匹配,默認為通配符匹配
(15)classloader
查看classloader的繼承樹,urls,類加載信息
classloader 命令將 JVM 中所有的classloader的信息統計出來,并可以展示繼承樹,urls等。
可以讓指定的classloader去getResources,打印出所有查找到的resources的url。對于ResourceNotFoundException比較有用。
參數說明:
參數名稱 參數說明
[l] 按類加載實例進行統計
[t] 打印所有ClassLoader的繼承樹
[a] 列出所有ClassLoader加載的類,請謹慎使用
[c:] ClassLoader的hashcode
[c: r:] 用ClassLoader去查找resource
1、按類加載類型查看統計信息
classloader
2、按類加載實例查看統計信息
classloader -l
3、查看ClassLoader的繼承樹
classloader -t
4、查看URLClassLoader實際的urls
classloader -c 5ffe9775
5、使用ClassLoader去查找resource
$ classloader -c 226b143b -r META-INF/MANIFEST.MF
6、 查找類的class文件:
$ classloader -c 1b6d3586 -r java/lang/String.class
(16)redefine
加載外部的.class文件,redefine jvm已加載的類。
[c:] ClassLoader的hashcode
[p:] 外部的.class文件的完整路徑,支持多個
例如:redefine -p /tmp/Test.class
(17)monitor
方法執行監控
對匹配 class-pattern/method-pattern的類、方法的調用進行監控。
monitor 命令是一個非實時返回命令.
實時返回命令是輸入之后立即返回,而非實時返回的命令,則是不斷的等待目標 Java 進程返回信息,直到用戶輸入 Ctrl+C 為止。
服務端是以任務的形式在后臺跑任務,植入的代碼隨著任務的中止而不會被執行,所以任務關閉后,不會對原有性能產生太大影響,而且原則上,任何Arthas命令不會引起原有業務邏輯的改變。
監控維度:
timestamp 時間戳
class Java類
method 方法(構造方法、普通方法)
total 調用次數
success 成功次數
fail 失敗次數
rt 平均RT
fail-rate 失敗率
參數:
class-pattern 類名表達式匹配
method-pattern 方法名表達式匹配
[E] 開啟正則表達式匹配,默認為通配符匹配
[c:] 統計周期,默認值為120秒
例如:
$ monitor -c 5 com.alibaba.sample.petstore.web.store.module.screen.ItemList execute
(18)tt
方法執行數據的時空隧道,記錄下指定方法每次調用的入參和返回信息,并能對這些不同的時間下調用進行觀測
watch 雖然很方便和靈活,但需要提前想清楚觀察表達式的拼寫,這對排查問題而言要求太高,因為很多時候我們并不清楚問題出自于何方,只能靠蛛絲馬跡進行猜測。
這個時候如果能記錄下當時方法調用的所有入參和返回值、拋出的異常會對整個問題的思考與判斷非常有幫助。
于是乎,TimeTunnel 命令就誕生了。
- 命令參數解析
- -t
tt 命令有很多個主參數,-t 就是其中之一。這個參數的表明希望記錄下類 *Test 的 print 方法的每次執行情況。
- -n 3
當你執行一個調用量不高的方法時可能你還能有足夠的時間用 CTRL+C 中斷 tt 命令記錄的過程,但如果遇到調用量非常大的方法,瞬間就能將你的 JVM 內存撐爆。
此時你可以通過 -n 參數指定你需要記錄的次數,當達到記錄次數時 Arthas 會主動中斷tt命令的記錄過程,避免人工操作無法停止的情況。
INDEX 時間片段記錄編號,每一個編號代表著一次調用,后續tt還有很多命令都是基于此編號指定記錄操作,非常重要。
TIMESTAMP 方法執行的本機時間,記錄了這個時間片段所發生的本機時間
COST(ms) 方法執行的耗時
IS-RET 方法是否以正常返回的形式結束
IS-EXP 方法是否以拋異常的形式結束
OBJECT 執行對象的hashCode(),注意,曾經有人誤認為是對象在JVM中的內存地址,但很遺憾他不是。但他能幫助你簡單的標記當前執行方法的類實體
CLASS 執行的類名
METHOD 執行的方法名
(19)options
全局開關
名稱默認值描述unsafefalse是否支持對系統級別的類進行增強,打開該開關可能導致把JVM搞掛,請慎重選擇!dumpfalse是否支持被增強了的類dump到外部文件中,如果打開開關,class文件會被dump到/${Application dir}/arthas-class-dump/目錄下,具體位置詳見控制臺輸出batch-re-transformtrue是否支持批量對匹配到的類執行retransform操作json-formatfalse是否支持json化的輸出disable-sub-classfalse是否禁用子類匹配,默認在匹配目標類的時候會默認匹配到其子類,如果想精確匹配,可以關閉此開關debug-for-asmfalse打印ASM相關的調試信息save-resultfalse是否打開執行結果存日志功能,打開之后所有命令的運行結果都將保存到/home/admin/logs/arthas/arthas.log中job-timeout1d異步后臺任務的默認超時時間,超過這個時間,任務自動停止;比如設置 1d, 2h, 3m, 25s,分別代表天、小時、分、秒
例如,想打開執行結果存日志功能,輸入如下命令即可:
$ options save-result true