日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 线上问题排查神器 Arthas 快速上手与原理浅谈

發布時間:2025/3/20 java 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 线上问题排查神器 Arthas 快速上手与原理浅谈 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【Arthas 官方社區正在舉行征文活動,參加即有獎品拿哦~點擊投稿】

作者 | 楊楨棟,筆名叫蠻三刀把刀,是一名一線互聯網碼農,留美訪學一年,主要關注后端開發,數據安全,爬蟲,物聯網,邊緣計算等方向。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-41tKyI58-1591959097393)(https://ucc.alicdn.com/pic/developer-ecology/ea75481c92ea4c289fe9e64f771bd7b2.png)]

前言

當你興沖沖地開始運行自己的 Java 項目時,你是否遇到過如下問題:

  • 程序在穩定運行了,可是實現的功能點了沒反應。
  • 為了修復 Bug 而上線的新版本,上線后發現 Bug 依然在,卻想不通哪里有問題?
  • 想到可能出現問題的地方,卻發現那里沒打日志,沒法在運行中看到問題,只能加了日志輸出重新打包——部署——上線
  • 程序功能正常了,可是為啥響應時間這么慢,在哪里出現了問題?
  • 程序不但穩定運行,而且功能完美,但跑了幾天或者幾周過后,發現響應速度變慢了,是不是內存泄漏了?

以前,你碰到這些問題,解決的辦法大多是,修改代碼,重新上線。但是在大公司里,上線的流程是非常繁瑣的,如果為了多加一行日志而重新發布版本,無疑是非常折騰人的。

現在,我們有了更為優雅的線上調試方法 - 來自阿里巴巴開源的 Arthas。

下圖是 Arthas 文檔中對于為什么要使用它的描述,我進行了精簡:

好了,前言已經超過字數了,哈哈,在本篇文章里,你能夠了解:

  • Arthas 使用實例:幫助你快速讓你上手,拯救你的低效率 Debug
  • 使用 Arthas 解決具體問題:看一下 Arthas 幫我拯救了多少時間
  • 相似工具:看看線上 Debug 還有沒有別的工具可以使用
  • 原理淺談:莫在浮沙筑高閣!你需要大概了解下 Arthas 的原理

相信我,Arhas 絕對是你提升效率的利器,適合各種階段的開發者,尤其適合我這種剛入門的新人(天天上班寫 Bug 的人)。你不應該有這種東西是高階程序員才應該去使用的思想,放心大膽的去用吧!

線上 Debug 神器 Arthas

Arthas 使用實例

命令的詳細文檔請參考:alibaba.github.io/arthas/comm…

快速啟動

快速啟動它,你只需要兩行命令:

wget https://alibaba.github.io/arthas/arthas-boot.jar java -jar arthas-boot.jar

隨后,在界面出現的進程中,選擇你的程序序號,比如 1

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-lLNLPTam-1591959097404)(https://ucc.alicdn.com/pic/developer-ecology/c0dfb1ebdf10460e84d8a073a22c3b38.png)]

這樣你就進入了 arthas 的控制臺。

基本使用

Arthas 有如下功能:

1. 首先是我認為的“上帝視角”指令:Dashboard

當前系統的實時數據面板,按 ctrl+c 退出;
當運行在 Ali-tomcat 時,會顯示當前 tomcat 的實時信息,如 HTTP 請求的 qps, rt, 錯誤數, 線程池信息等等。

通過這些,你可以對于整個程序進程有個直觀的數據監控。


[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ddDhaKtX-1591959097408)(https://ucc.alicdn.com/pic/developer-ecology/af4c5ada52be41ffa3e6fedc94ad36d9.png)]

2. 類加載問題相關指令

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-vRBqZMwY-1591959097409)(https://ucc.alicdn.com/pic/developer-ecology/4c7ece4714074dd78644d1640a758c5f.png)]

SC:查看 JVM 已加載的類信息

通過 SC 我們可以看到我們這個類的詳細信息,包括是從哪個 jar 包讀取的,他是不是接口/枚舉類等,甚至包括他是從哪個類加載器加載的。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Il1vIaiM-1591959097410)(https://ucc.alicdn.com/pic/developer-ecology/f75d9726342641e9a747f9f6586744dd.png)]

上圖中代碼:

[arthas@37]$ sc -d *MathGameclass-info demo.MathGamecode-source /home/scrapbook/tutorial/arthas-demo.jarname demo.MathGameisInterface falseisAnnotation falseisEnum falseisAnonymousClass falseisArray falseisLocalClass falseisMemberClass falseisPrimitive falseisSynthetic falsesimple-name MathGamemodifier publicannotationinterfacessuper-class +-java.lang.Objectclass-loader +-sun.misc.Launcher$AppClassLoader@70dea4e+-sun.misc.Launcher$ExtClassLoader@69260973classLoaderHash 70dea4e

SC 也可以查看已加載的類,幫助你看是否有沒有納入進來的類,尤其是在 Spring 中,可以判斷的你的依賴有沒有正確的進來。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-9Cp8NZLW-1591959097411)(https://ucc.alicdn.com/pic/developer-ecology/e5c3a54daea749eea1aac6027c70b0a1.png)]

上圖中代碼:

# 查看JVM已加載的類信息 [arthas@37]$ sc javax.servlet.Filter com.example.demo.arthas.AdminFilterConfig$AdminFilter javax.servlet.Filter org.apache.tomcat.websocket.server.WsFilter org.springframework.boot.web.filter.OrderedCharacterEncodingFilter org.springframework.boot.web.filter.OrderedHiddenHttpMethodFilter org.springframework.boot.web.filter.OrderedHttpPutFormContentFilter org.springframework.boot.web.filter.OrderedRequestContextFilter org.springframework.web.filter.CharacterEncodingFilter org.springframework.web.filter.GenericFilterBean org.springframework.web.filter.HiddenHttpMethodFilter org.springframework.web.filter.HttpPutFormContentFilter org.springframework.web.filter.OncePerRequestFilter org.springframework.web.filter.RequestContextFilter org.springframework.web.servlet.resource.ResourceUrlEncodingFilter Affect(row-cnt:14) cost in 11 ms.# 查看已加載類的方法信息 [arthas@37]$ sm java.math.RoundingMode java.math.RoundingMode <init>(Ljava/lang/String;II)V java.math.RoundingMode values()[Ljava/math/RoundingMode; java.math.RoundingMode valueOf(I)Ljava/math/RoundingMode; java.math.RoundingMode valueOf(Ljava/lang/String;)Ljava/math/RoundingMode; Affect(row-cnt:4) cost in 6 ms.

jad:反編譯某個類,或者反編譯某個類的某個方法。

上圖中代碼:

# 反編譯只顯示源碼 jad --source-only com.Arthas # 反編譯某個類的某個方法 jad --source-only com.Arthas mysql [arthas@37]$ jad demo.MathGame ClassLoader: +-sun.misc.Launcher$AppClassLoader@70dea4e+-sun.misc.Launcher$ExtClassLoader@69260973 Location: /home/scrapbook/tutorial/arthas-demo.jar /** Decompiled with CFR.*/ package demo; import java.io.PrintStream; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.TimeUnit; public class MathGame {private static Random random = new Random();public int illegalArgumentCount = 0;public List<Integer> primeFactors(int number) {if (number < 2) {++this.illegalArgumentCount;throw new IllegalArgumentException("number is: " + number + ", need >= 2");}ArrayList<Integer> result = new ArrayList<Integer>();int i = 2;while (i <= number) {if (number % i == 0) {result.add(i);number /= i;i = 2;continue;}++i;}return result;}public static void main(String[] args) throws InterruptedException {MathGame game = new MathGame();do {game.run();TimeUnit.SECONDS.sleep(1L);} while (true);}public void run() throws InterruptedException {try {int number = random.nextInt() / 10000;List<Integer> primeFactors = this.primeFactors(number);MathGame.print(number, primeFactors);}catch (Exception e) {System.out.println(String.format("illegalArgumentCount:%3d, ", this.illegalArgumentCount) + e.getMessage());}}public static void print(int number, List<Integer> primeFactors) {StringBuffer sb = new StringBuffer(number + "=");for (int factor : primeFactors) {sb.append(factor).append('*');}if (sb.charAt(sb.length() - 1) == '*') {sb.deleteCharAt(sb.length() - 1);}System.out.println(sb);} } Affect(row-cnt:1) cost in 760 ms.

3. 方法運行相關指令

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-llekqmPX-1591959097412)(https://ucc.alicdn.com/pic/developer-ecology/ff3d5260259a4fefbee694aed63053c7.png)]

watch:方法執行的數據觀測

你可以通過 watch 指令,來監控某個類,監控后,運行下你的功能,復現下場景,arthas 會提供給你具體的出參和入參,幫助你排查故障。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-bp3XMjVd-1591959097414)(https://ucc.alicdn.com/pic/developer-ecology/3574b4dbf4634515bb26a2fb8906f5e4.png)]

trace:輸出方法調用路徑,并輸出耗時

這個指令對于優化代碼非常的有用,可以看出具體每個方法執行的時間,如果是 for 循環等重復語句,還能看出 n 次循環中的最大耗時,最小耗時,和平均耗時,完美!

tt:官方名為時空隧道

這是我調試用的最多的指令,在你對某方法開啟 tt 后,會記錄下每一次的調用(你需要設置最大監控次數),然后你可以在任何時候會看這里面的調用,包括出參,入參,運行耗時,是否異常等。非常強大。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Jyg65aet-1591959097416)(https://ucc.alicdn.com/pic/developer-ecology/5fd4208367894654926878bf57db9f52.png)]

4. 線程調試相關指令

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-x0zek059-1591959097416)(https://ucc.alicdn.com/pic/developer-ecology/f2be2bc7ebe940248ead196270ab16fb.png)]

thread 相關命令:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tT6YgR6o-1591959097417)(https://ucc.alicdn.com/pic/developer-ecology/3e943acf8a024c0dab0a332a0012d4da.png)]

thread -n:排列出 CPU 使用率 Top N 的線程。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Km433ilj-1591959097419)(https://ucc.alicdn.com/pic/developer-ecology/863ecbec00e843fc88859c7d8f04a6b5.png)]

thread -b:排查阻塞的線程

我們代碼有時候設計的不好,會引發死鎖的問題,卡住整個線程執行,使用這個指令可以輕松的找到問題線程,以及問題的執行語句。


5. 強大的 ognl 表達式

眾所周知,一般來說,表達式都是調試工具里最強的指令,哈哈。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-aeLKZnXD-1591959097421)(https://ucc.alicdn.com/pic/developer-ecology/9464499c4bf9426fa1bf7bba44cfc52c.png)]

在 Arthas 中你可以利用 ognl 表達式語言做很多事,比如執行某個方法,獲取某個信息,甚至進行修改。

[arthas@19856]$ ognl '@com.Arthas@hashSet' @HashSet[@String[count1],@String[count2],@String[count29],@String[count28],@String[count0],@String[count27],@String[count5],@String[count26],@String[count6],@String[count25],@String[count3],@String[count24],[arthas@19856]$ ognl '@com.Arthas@hashSet.add("test")' @Boolean[true] [arthas@19856]$ # 查看添加的字符 [arthas@19856]$ ognl '@com.Arthas@hashSet' | grep test@String[test], [arthas@19856]$

甚至你可以動態更換日志輸出級別。

$ ognl '@com.lz.test@LOGGER.logger.privateConfig' @PrivateConfig[loggerConfig=@LoggerConfig[root],loggerConfigLevel=@Level[INFO],intLevel=@Integer[400], ] $ ognl '@com.lz.test@LOGGER.logger.setLevel(@org.apache.logging.log4j.Level@ERROR)' null $ ognl '@com.lz.test@LOGGER.logger.privateConfig' @PrivateConfig[loggerConfig=@LoggerConfig[root],loggerConfigLevel=@Level[ERROR],intLevel=@Integer[200],]

使用 Arthas 解決具體問題

1. 響應時間異常問題

工作中遇到一個優化問題,系統中一個導出表格的功能,響應時間長達 2 分鐘,雖然給內部使用,但也不能這么夸張,用 trace 跟蹤下方法,發現是其中的手機號加解密函數占用了非常大的時間,幾千個手機號,進行了解密后加密的精彩操作,最終導致了兩分鐘的返回時間。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iCoG15s2-1591959097425)(https://ucc.alicdn.com/pic/developer-ecology/eccafa2a838a488a910b70b6aa4833e1.png)]

2. 某功能 Bug 導致服務器返回 500

首先通過 trace 看異常報錯的方法,之后通過 tt 排查方法,發現入參進來后,居然走錯了方法(因為多態),走到了返回 null 的方法中,所以導致了 NPE 空指針錯誤。


補充

Arthas 還支持 Web Console,詳見:alibaba.github.io/arthas/web-…

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-bmMpaTxL-1591959097427)(https://ucc.alicdn.com/pic/developer-ecology/34c2a0d4b1dc4d8eaf4d71e80b3f595c.png)]

相似工具

BTrace 一是個歷史比較久的工具,觀察下來 Arthas 其實和它的理念蠻相似的,相信 Arthas 也參考過 Btrace,作為一個學習樣例來開發 Arthas。詳細的優劣勢看圖:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-IeF2jzIy-1591959097429)(https://ucc.alicdn.com/pic/developer-ecology/9e9e5e7b50a54d3ebbbc4647aff71755.png)]

其他的相似工具,還有 jvm-sandbox,有興趣的朋友可以去看看。

原理淺談

分為三個部分:

  • 啟動
  • arthas 服務端代碼分析
  • arthas 客戶端代碼分析

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mSbPuDJl-1591959097430)(https://ucc.alicdn.com/pic/developer-ecology/120b20c2e6654383adcdb50c06e03ab2.png)]

啟動

使用了阿里開源的組件 cli,對參數進行了解析:com.taobao.arthas.boot.Bootstrap

在傳入參數中沒有 pid,則會調用本地 jps 命令,列出 java 進程。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-QxBvxSDK-1591959097431)(https://ucc.alicdn.com/pic/developer-ecology/47345b431bda4bb28e911cac6a5709be.png)]

進入主邏輯,會在用戶目錄下建立 .arthas 目錄,同時下載 arthas-core 和 arthas-agent 等 lib 文件,最后啟動客戶端和服務端。

通過反射的方式來啟動字符客戶端。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-7VQVae3p-1591959097432)(https://ucc.alicdn.com/pic/developer-ecology/3ffab59092af420393ad6557f007ccba.png)]

服務端——前置準備

看服務端啟動命令可以知道 從 arthas-core.jar開始啟動,arthas-core 的 pom.xml 文件里面指定了 mainClass 為 com.taobao.arthas.core.Arthas,使得程序啟動的時候從該類的 main 方法開始運行。

  • 首先解析入參,生成 com.taobao.arthas.core.config.Configure 類,包含了相關配置信息;
  • 使用 jdk-tools 里面的 VirtualMachine.loadAgent,其中第一個參數為 agent 路徑, 第二個參數向 jar 包中的 agentmain() 方法傳遞參數(此處為 agent-core.jar 包路徑和 config 序列化之后的字符串),加載 arthas-agent.jar 包;
  • 運行 arthas-agent.jar 包,指定了 Agent-Class為com.taobao.arthas.agent.AgentBootstrap。

上圖中代碼:

public class Arthas {private Arthas(String[] args) throws Exception {attachAgent(parse(args));}private Configure parse(String[] args) {// 省略非關鍵代碼,解析啟動參數作為配置,并填充到configure對象里面return configure;}private void attachAgent(Configure configure) throws Exception {// 省略非關鍵代碼,attach到目標進程virtualMachine = VirtualMachine.attach("" + configure.getJavaPid());virtualMachine.loadAgent(configure.getArthasAgent(),configure.getArthasCore() + ";" + configure.toString());}public static void main(String[] args) {new Arthas(args);} }

服務端——監聽客戶端請求

  • 如果是 exit,logout,quit,jobs,fg,bg,kill 等直接執行;
  • 如果是其他的命令,則創建 Job,并運行;
  • 創建 Job 時,會根據具體客戶端傳遞的命令,找到對應的 Command,并包裝成 Process, Process 再被包裝成 Job;
  • 運行 Job 時,反向先調用 Process,再找到對應的 Command,最終調用 Command 的 process 處理請求。

服務端——Command 處理流程

  • 不需要使用字節碼增強的命令
  • 其中 JVM 相關的使用 java.lang.management 提供的管理接口,來查看具體的運行時數據。比較簡單,就不介紹了。

  • 需要使用字節碼增強的命令
  • 字節碼增加的命令統一繼承 EnhancerCommand 類,process 方法里面調用 enhance 方法進行增強。調用 Enhancer 類 enhance 方法,該方法內部調用 inst.addTransformer 方法添加自定義的 ClassFileTransformer,這邊是 Enhancer 類。

    Enhancer 類使用 AdviceWeaver(繼承 ClassVisitor),用來修改類的字節碼。重寫了 visitMethod 方法,在該方法里面修改類指定的方法。visitMethod 方法里面使用了 AdviceAdapter(繼承了 MethodVisitor類),在 onMethodEnter 方法, onMethodExit 方法中,把 Spy 類對應的方法(ON_BEFORE_METHOD, ON_RETURN_METHOD, ON_THROWS_METHOD 等)編織到目標類的方法對應的位置。

    在前面 Spy 初始化的時候可以看到,這幾個方法其實指向的是 AdviceWeaver 類的 methodOnBegin, methodOnReturnEnd 等。在這些方法里面都會根據 adviceId 查找對應的 AdviceListener,并調用 AdviceListener 的對應的方法,比如 before,afterReturning, afterThrowing。

    客戶端

    客戶端代碼在 arthas-client 模塊里面,入口類是 com.taobao.arthas.client.TelnetConsole。

    主要使用 apache commons-net jar 進行 telnet 連接,關鍵的代碼有下面幾步:

  • 構造 TelnetClient 對象,并初始化
  • 構造 ConsoleReader 對象,并初始化
  • 調用 IOUtil.readWrite(telnet.getInputStream(), telnet.getOutputStream(), System.in, consoleReader.getOutput()) 處理各個流,一共有四個流:
    • telnet.getInputStream()
    • telnet.getOutputStream()
    • System.in
    • consoleReader.getOutput()
  • 請求時:從本地 System.in 讀取,發送到 telnet.getOutputStream(),即發送給遠程服務端。 響應時:從 telnet.getInputStream() 讀取遠程服務端發送過來的響應,并傳遞給 consoleReader.getOutput(),即在本地控制臺輸出。

    關于源碼,深入下去還有很多東西需要生啃,我也沒有消化得很好,大家可以繼續閱讀詳細資料。

    總結

    Arthas 是一個**線上 **Debug 神器,小白也可以輕松上手。

    一鍵安裝并啟動 Arthas

    • 方式一:通過 Cloud Toolkit 實現 Arthas 一鍵遠程診斷

    Cloud Toolkit 是阿里云發布的免費本地 IDE 插件,幫助開發者更高效地開發、測試、診斷并部署應用。通過插件,可以將本地應用一鍵部署到任意服務器,甚至云端(ECS、EDAS、ACK、ACR 和 小程序云等);并且還內置了 Arthas 診斷、Dubbo工具、Terminal 終端、文件上傳、函數計算 和 MySQL 執行器等工具。不僅僅有 IntelliJ IDEA 主流版本,還有 Eclipse、Pycharm、Maven 等其他版本。

    推薦使用 IDEA 插件下載 Cloud Toolkit 來使用 Arthas:http://t.tb.cn/2A5CbHWveOXzI7sFakaCw8

    • 方式二:直接下載

    地址:https://github.com/alibaba/arthas。

    參考文獻

    開源地址:
    github.com/alibaba/art…
    官方文檔:
    alibaba.github.io/arthas

    Arthas 征文活動火熱進行中

    Arthas 官方正在舉行征文活動,如果你有:

    • 使用 Arthas 排查過的問題
    • 對 Arthas 進行源碼解讀
    • 對 Arthas 提出建議
    • 不限,其它與 Arthas 有關的內容

    歡迎參加征文活動,還有獎品拿哦~點擊投稿

    “阿里巴巴云原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦云原生流行技術趨勢、云原生大規模的落地實踐,做最懂云原生開發者的公眾號?!?/p>

    總結

    以上是生活随笔為你收集整理的Java 线上问题排查神器 Arthas 快速上手与原理浅谈的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。