java應用線上診斷神器--Arthas
前言
1、什麼是Arthas?
Arthas 是Alibaba開源的Java診斷工具,深受開發者喜愛(截止2020.9.19 github star是23K)。通過Arthas我們可以線上排查問題,無需重啟;動態跟蹤Java程式碼;實時監控JVM狀態。
2、Arthas有哪些特性
- 實時檢視系統的執行狀況
- 檢視函式呼叫的引數,返回值和異常
- 程式碼線上熱更新
- 秒解類衝突問題,定位類載入路徑
- 快速定位應用的熱點,生成火焰圖
- 線上診斷,點開網頁診斷線上應用
3、Arthas能幫我們解決什麼問題
當你遇到以下類似問題而束手無策時,Arthas可以幫助你解決:
- 這個類從哪個 jar 包載入的?為什麼會報各種類相關的 Exception?
- 我改的程式碼為什麼沒有執行到?難道是我沒 commit?分支搞錯了?
- 遇到問題無法在線上 debug,難道只能通過加日誌再重新發布嗎?
- 線上遇到某個使用者的資料處理有問題,但線上同樣無法 debug,線下無法重現!
- 是否有一個全域性視角來檢視系統的執行狀況?
- 有什麼辦法可以監控到JVM的實時執行狀態?
- 怎麼快速定位應用的熱點,生成火焰圖?
4、安裝
下載arthas-boot.jar,然後用java -jar的方式啟動:
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
本文的示例專案是執行在docker,因此就採用了另外的方式
docker exec -it ${containerId} /bin/bash -c "wget https://arthas.aliyun.com/arthas-boot.jar && java -jar arthas-boot.jar"
不過在執行的過程中,可能會出現
/bin/bash: wget: command not found
解決方案如下
進入容器的/bin/bash
docker exec -it ${containerId} /bin/bash
apt-get update
apt-get install wget
命令解讀
1、幫助命令相關
help(檢視命令幫助資訊
)
會列這個命令,源於個人習慣吧。每當學習一個新東西,都會習慣看下幫助,通讀一下
當你想了解具體命令的詳細用法,以thread為例,輸入
help thread
就會有詳細的thread引數、例子介紹。感覺本文的精華就是這個了,畢竟你想要其他命令,直接
help 命令
但為了水文,就再介紹幾類命令
2、jvm相關
dashboard(實時展示當前系統諸如執行緒、記憶體佔用、GC等資訊的面板,預設每個5秒重新整理一下面板)
注:按ctrl+c可以退出面板
jvm(檢視當前JVM資訊比如gc回收次數以及耗時等)
thread(檢視當前執行緒資訊,檢視執行緒的堆疊)
a、 檢視當前最忙的前N個執行緒並列印堆疊
thread -n 3
上述的命令實現的效果就和我們以往輸入
top -H -p pid
printf '%x\n'pid
jstack pid |grep 'nid' -C5 –color
類似
b、 thread -b, 找出當前阻塞其他執行緒的執行緒
注: 目前只支援找出synchronized關鍵字阻塞住的執行緒, 如果是java.util.concurrent.Lock, 目前還不支援
c、 thread --state ,檢視指定狀態的執行緒
3、日誌相關
logger(檢視logger資訊,更新logger level)
3.1、 檢視logger資訊
3.2、 動態更新logger level
修改日誌級別步驟
a、 查詢當前類的classloader hashcode
sc -d com.example.springdemo.user.service.impl.UserServiceImpl | grep classLoaderHash
b、 用OGNL獲取logger
ognl -c 31cefde0 '@com.example.springdemo.user.service.impl.UserServiceImpl@log'
從上圖可以知道com.example.springdemo.user.service.impl.UserServiceImpl@log實際使用的是logback。
可以看到level=null,則說明實際最終的level是從root logger裡來的。
c、 單獨設定UserServiceImpl的logger level
把日誌級別變更為warn
ognl -c 31cefde0 '@com.example.springdemo.user.service.impl.UserServiceImpl@log.setLevel(@ch.qos.logback.classic.Level@WARN)'
可以看出日誌級別已經改為warn
4、class/classloader相關
jad(反編譯指定已載入類的原始碼)
sc(檢視JVM已載入的類資訊)
mc(記憶體編譯器,編譯.java檔案生成.class)
redefine(載入外部的.class檔案,redefine jvm已載入的類)
為啥介紹這幾個,因為這幾個組合起來就可以實現動態線上更新程式碼了。其步驟如下
a、jad反編譯要更新的程式碼
jad --source-only com.example.springdemo.user.service.impl.UserServiceImpl > /tmp/UserServiceImpl.java
b、sc查詢載入要更新程式碼的ClassLoader
sc -d com.example.springdemo.user.service.impl.UserServiceImpl | grep classLoaderHash
c、儲存好/tmp/UserServiceImpl.java之後,使用mc(Memory Compiler)命令來編譯,並且通過--classLoaderClass引數指定ClassLoader
mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserServiceImpl.java -d /tmp
d、使用redefine命令重新載入新編譯好的UserServiceImpl.class
redefine /tmp/com/example/springdemo/user/service/impl/UserServiceImpl.class
5、監控相關
monitor(方法執行監控,可以監控方法的呼叫次數、成功次數、失敗次數、平均響應時間、失敗率)
注: 這是一個非實時返回命令,統計週期,預設值為120秒
monitor -c 5 com.example.springdemo.user.service.impl.UserServiceImpl getUserById
watch(觀察指定方法的呼叫情況。能觀察到的範圍為:返回值、丟擲異常、入參)
watch com.example.springdemo.user.service.impl.UserServiceImpl getUserById "{params,returnObj}" -x 2
watch引數說明
trace(方法內部呼叫路徑,並輸出方法路徑上的每個節點上耗時)
注: trace 能方便的幫助你定位和發現因 RT 高而導致的效能問題缺陷,但其每次只能跟蹤一級方法的呼叫鏈路。
trace com.example.springdemo.user.service.impl.UserServiceImpl getUserById
stack(輸出當前方法被呼叫的呼叫路徑)
stack com.example.springdemo.user.service.impl.UserServiceImpl getUserById
tt(方法執行資料的時空隧道,記錄下指定方法每次呼叫的入參和返回資訊,並能對這些不同的時間下呼叫進行觀測)
這個命令的厲害之處在於記錄下當前方法的每次呼叫環境現場,並能進行重放
tt -t com.example.springdemo.user.service.impl.UserServiceImpl getUserById
b、選擇一個index進行重放
tt -i 1000 -p
注:這些監控命令,都通過位元組碼增強技術來實現的,會在指定類的方法中插入一些切面來實現資料統計和觀測,因此在線上、預發使用時,請儘量明確需要觀測的類、方法以及條件,診斷結束要執行 stop 或將增強過的類執行 reset 命令。
總結
本文主要介紹Arthas的的一些用法,而這些方法在官網都有很詳細的介紹。如果對Arthas感興趣的朋友的,可以訪問官網
同時也推薦大家訪問
https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn
裡面除了可以線上實操Arthas還可以檢視相關使用者案例,有助於大家進一步上手Arthas