轉載本文需注明出處:微信公眾號EAWorld,違者必究。
什么是Arthas
Java 診斷利器 Arthas,是阿里的一款開源工具。Github-alibaba/arthas 上可以看到它的介紹。
在日常開發中,當我們發現應用的某個接口響應比較慢,這個時候想想要分析一下原因,找到代碼中耗時的部分,比較容易想到的是在接口鏈路的 IO 操作上下游打印時間日志,再根據幾個時間點的日志算出耗時長的 IO 操作。這種方式沒有問題,但是加日志需要發布,既繁瑣又低效,這個時候可以引入一些線上 debug 的工具,arthas 就是很好的一種,除了分析耗時,還可以打印調用棧、方法入參及返回,類加載情況,線程池狀態,系統參數等等,其實現原理是解析 JVM 在操作系統中的文件,大部分操作是只讀的,對服務進程沒有侵入性,因此可以放心使用。
Arthas能解決什么問題?
從我個人的使用經驗來看,Arthas至少幫我解決了以下幾個問題:
監控某方法查看其整個調用鏈路,從而找出某次調用的性能瓶頸。
反編譯某個類,查看線上的代碼是否與本地代碼一致,避免沒有提交代碼而導致的問題。
站在全局視角查看整個系統的運行情況,比如觀察內存增長、GC的情況。
在微服務架構背景下,通常本地沒有完整的環境,此時可以直接在測試環境監控某個方法傳入的參數是否正確,返回值是否正確。
快速開始
下載并啟動arthas
輸入以下命令啟動arthas程序
curl -O https://arthas.aliyun.com/arthas-demo.jarjava -jar arthas-demo.jar
選擇需要監控應用的進程編號,回車后Arthas會attach到目標進程上,并輸出日志:
容器中使用
docker exec -it arthas-demo /bin/sh -c "java -jar /opt/arthas/arthas-boot.jar"
甚至我們可以直接把arthas放到容器鏡像文件中:
COPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas
Arthas常用命令
下面簡要為大家介紹一下Arthas常用的幾個命令。
dashboard
使用dashboard命令會顯示以下信息:
1. 當前最繁忙的一些線程
2. 顯示應用當前使用的內存信息,包括堆內存、新生代伊甸區、老年代、非堆內存的使用情況。
3. 顯示程序的GC情況,包括YGC次數、總花費時間,FGC的次數、總花費時間。
4. 當前程序的一些信息,包括系統版本、JDK版本、程序運行時長等。
Thread
查看當前線程信息,查看線程的堆棧
// 查看 CPU 使用率 top n 的線程的棧,當前最忙的前 n 個線程:thread -n 3// 查看 5 秒內的 CPU 使用率 top n 的線程棧:thread -n 3 -i 5000
// 查看線程是否有阻塞:thread -b
watch
有時候我們不太方便進行本地調試,這個時候可以使用watch監控某個方法,然后點擊相關的功能,查看該方法的調用情況:
watch com.primeton.dgp.assets.controller.DsResourcePoolController getResourcePool "{params,returnObj}" -x 2
執行以上命令后,控制臺會hold在被監控的方法上,此時再次點擊頁面上的按鈕,控制臺就會打印此次的調用結果。
trace
trace 命令能主動搜索 class-pattern/method-pattern 對應的方法調用路徑,渲染和統計整個調用鏈路上的所有性能開銷和追蹤調用鏈路。通常我們用這個方法可以看到整個調用路徑的耗時,從而找出真正的性能瓶頸,幫助解決問題。
trace com.primeton.dgp.assets.controller.DsResourcePoolController getResourcePool
tt
tt方法執行數據的時空隧道,記錄下指定方法每次調用的入參和返回信息,并能對這些不同的時間下調用進行觀測,使用方法如下:
tt -t com.primeton.dgp.assets.controller.DsResourcePoolController getResourcePool
執行此命令后,arthas會記錄下指定方法的每次調用環境現場,并打印一些相關的信息,如調用時長、是否正常返回、是否拋出異常等。
顯示所有被記錄的調用列表
tt -l
重做一次調用。tt 命令由于保存了當時調用的所有現場信息,所以我們可以自己主動對一個 INDEX 編號的時間片自主發起一次調用,從而解放你的溝通成本。此時你需要 -p 參數。通過 --replay-times 指定 調用次數,通過 --replay-interval 指定多次調用間隔(單位ms, 默認1000ms)
tt -i 1001 -p --replay-times 3 --replay-interval 3000
jad
jad 命令將 JVM 中實際運行的 class 的 byte code 反編譯成 java 代碼,便于你理解業務邏輯;反編譯出來的源碼是帶語法高亮的,閱讀更方便。當我們看到某個方法的調用時長明顯過長,或者時空隧道中某方法拋出異常,這個時候就可以直接反編譯相關的方法,看看是否能找出原因。
其他
除了以上很常用的命令以外,arthas還有很多實用命令,大家可以參考官方文檔來使用
另外,每一個命令都支持-help參數,可以查看該命令的說明、參數,甚至包括了使用例子,可以說是非常貼心了
案例
案例1
我們準備了一個簡單的springboot應用,應用內有一個Controller,返回一個字符串,代碼如下:
@RestControllerpublic class DemoController {
@GetMapping(value = "/getDemo")public String getDemo(){return "demo 1"; }}
啟動程序,訪問剛剛準備好的controller得到了下面的結果
接下來我們要嘗試在沒有源碼的情況下修改demo controller的返回值,并在不重啟應用的情況下,使我們修改的返回值生效。
首先啟動arthas并織入到剛才的demo,然后反編譯DemoController到臨時文件夾。
jad --source-only com.example.arthas.DemoController > /tmp/DemoController.java
接下來我們用vim修改反編譯出來的代碼
查詢加載原有DemoController類的ClassLoader
sc -d com.example.arthas.DemoController
重新編譯修改后的類
mc -c 685f4c2e /tmp/DemoController.java
重新加載修改后的類
redefine -c 685f4c2e /opt/arthas/demo/com/example/arthas/DemoController.class
此時,無需重啟應用,我們重新訪問剛才的controller,會發現返回結果已經成功更改了。
案例2
某燃氣系統由于被眾多地區的燃氣公司所使用,所以版本繁多,經歷過很多輪的測試,其中比較耗時的當屬性能測試了。以往性能測試工作通常耗時很長,主要是性能測試人員并不一定熟悉項目代碼,導致壓力測試出現問題的時候不容易找到問題的所在。
在本次的表具接口的性能測試中,我們使用Arthas工具進行故障的快速定位,大幅減少了性能測試的時間,達到了很好的效果。
本次壓力測試的過程中我們發現,當并發達到一定數量的時候系統會卡死,大量新的請求會超時。使用dashboard查看發現系統的大量線程處于block或者wating中。
使用trace命令,將壓力測試的方法進行監控,并保存到日志文件中,接著重新跑一輪壓力測試。
trace -n 150000 com.towngas.tcis.interfaces.nb.NbInfoServlet getService >> tt-2020-10-17-NbServlet-getService
監控日志,當用戶數達到500+的時候果然發現了問題
繼續使用trace命令跟蹤,發現了可能出現問題的方法
使用jad命令反編譯該代碼可以看到HttpClient并沒有被立即關閉,使用release的釋放后關閉通常沒有問題,但是釋放資源有一個過程通常是180秒,所以如果短時間有大量接口調用,會導致打開的socket連接數量超過系統設定值。找到原因后問題得以順利解決,壓力測試得以順利完成。
小結
本次的分享為大家介紹了Arthas的基本概念與基礎的使用方法。更為詳細的使用方法、命令的更多參數,還請查看Arthas的官方文檔。
關于作者:李云濤,普元高級開發工程師,擅長性能調優、微服務、容器、消息隊列等技術。先后參與郵儲銀行Java開發平臺、中移總ERP流程平臺、中煤信息技術中臺等平臺的的架構設計與平臺研發工作。
-
代碼
+關注
關注
30文章
4753瀏覽量
68368 -
編譯
+關注
關注
0文章
654瀏覽量
32813
發布評論請先 登錄
相關推薦
評論