Java線上問題排查神器Arthas快速上手與原理淺談

前言

當你興沖沖地開始運行本身的Java項目時,你是否遇到過以下問題:java

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

之前,你碰到這些問題,解決的辦法大可能是,修改代碼,從新上線。可是在大公司裏,上線的流程是很是繁瑣的,若是爲了多加一行日誌而從新發布版本,無疑是很是折騰人的。mysql

如今,咱們有了更爲優雅的線上調試方法,來自阿里巴巴開源的Arthasgit

下圖是Arthas文檔中對於爲何要使用它的描述,我進行了精簡:

Java線上問題排查神器Arthas快速上手與原理淺談

好了,前言已經超過字數了,哈哈,在本篇文章裏,你可以瞭解:
  • Arthas使用實例:幫助你快速讓你上手,拯救你的低效率Debug
  • 使用Arthas解決具體問題:看一下Arthas幫我拯救了多少時間
  • 類似工具:看看線上Debug還有沒有別的工具可使用
  • 原理淺談:莫在浮沙築高閣!你須要大概瞭解下Arthas的原理

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

線上Debug神器Arthas

Arthas使用實例github

命令的詳細文檔請參考:

alibaba.github.io/arthas/comm…web

快速啓動面試

快速啓動它,你只須要兩行命令:sql

Java線上問題排查神器Arthas快速上手與原理淺談

Java線上問題排查神器Arthas快速上手與原理淺談

隨後,在界面出現的進程中,選擇你的程序序號,好比1apache

Java線上問題排查神器Arthas快速上手與原理淺談

這樣你就進入了arthas的控制檯tomcat

基本使用

Arthas有以下功能:

Java線上問題排查神器Arthas快速上手與原理淺談

1. 首先是我認爲的「上帝視角」指令:Dashboard

當前系統的實時數據面板,按 ctrl+c 退出。

當運行在Ali-tomcat時,會顯示當前tomcat的實時信息,如HTTP請求的qps, rt, 錯誤數, 線程池信息等等。

經過這些,你能夠對於整個程序進程有個直觀的數據監控。

Java線上問題排查神器Arthas快速上手與原理淺談

Java線上問題排查神器Arthas快速上手與原理淺談

2. 類加載問題相關指令

Java線上問題排查神器Arthas快速上手與原理淺談

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

經過SC咱們能夠看到咱們這個類的詳細信息,包括是從哪一個jar包讀取的,他是否是接口/枚舉類等,甚至包括他是從哪一個類加載器加載的。

Java線上問題排查神器Arthas快速上手與原理淺談

上圖中代碼:

Java線上問題排查神器Arthas快速上手與原理淺談

SC也能夠查看已加載的類,幫助你看是否有沒有歸入進來的類,尤爲是在Spring中,能夠判斷的你的依賴有沒有正確的進來。

Java線上問題排查神器Arthas快速上手與原理淺談

上圖中代碼:

Java線上問題排查神器Arthas快速上手與原理淺談

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

Java線上問題排查神器Arthas快速上手與原理淺談

上圖中代碼:

# 反編譯只顯示源碼
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. 方法運行相關指令

Java線上問題排查神器Arthas快速上手與原理淺談

watch:方法執行的數據觀測

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

Java線上問題排查神器Arthas快速上手與原理淺談

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

這個指令對於優化代碼很是的有用,能夠看出具體每一個方法執行的時間,若是是for循環等重複語句,還能看出n次循環中的最大耗時,最小耗時,和平均耗時,完美!

Java線上問題排查神器Arthas快速上手與原理淺談

tt:官方名爲時空隧道

這是我調試用的最多的指令,在你對某方法開啓tt後,會記錄下每一次的調用(你須要設置最大監控次數),而後你能夠在任什麼時候候會看這裏面的調用,包括出參,入參,運行耗時,是否異常等。很是強大。

Java線上問題排查神器Arthas快速上手與原理淺談

4. 線程調試相關指令

Java線上問題排查神器Arthas快速上手與原理淺談

thread相關命令:

Java線上問題排查神器Arthas快速上手與原理淺談

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

Java線上問題排查神器Arthas快速上手與原理淺談

thread -b:排查阻塞的線程

咱們代碼有時候設計的很差,會引起死鎖的問題,卡住整個線程執行,使用這個指令能夠輕鬆的找到問題線程,以及問題的執行語句。

Java線上問題排查神器Arthas快速上手與原理淺談

Java線上問題排查神器Arthas快速上手與原理淺談

  1. 強大的ognl表達式

衆所周知,通常來講,表達式都是調試工具裏最強的指令,哈哈。

Java線上問題排查神器Arthas快速上手與原理淺談

在Arthas中你能夠利用ognl表達式語言作不少事,好比執行某個方法,獲取某個信息,甚至進行修改。

Java線上問題排查神器Arthas快速上手與原理淺談

Java線上問題排查神器Arthas快速上手與原理淺談

甚至你能夠動態更換日誌輸出級別

Java線上問題排查神器Arthas快速上手與原理淺談

Java線上問題排查神器Arthas快速上手與原理淺談

使用Arthas解決具體問題1. 響應時間異常問題

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

Java線上問題排查神器Arthas快速上手與原理淺談

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

首先經過trace看異常報錯的方法,以後經過tt排查方法,發現入參進來後,竟然走錯了方法(由於多態),走到了返回null的方法中,因此致使了NPE空指針錯誤。

Java線上問題排查神器Arthas快速上手與原理淺談

Java線上問題排查神器Arthas快速上手與原理淺談

補充

Arthas還支持Web Console,詳見:

alibaba.github.io/arthas/web-…

Java線上問題排查神器Arthas快速上手與原理淺談

類似工具

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

Java線上問題排查神器Arthas快速上手與原理淺談

其餘的類似工具,還有jvm-sandbox,有興趣的朋友能夠去看看。

原理淺談

分爲三個部分:

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

Java線上問題排查神器Arthas快速上手與原理淺談

啓動

使用了阿里開源的組件cli,對參數進行了解析

com.taobao.arthas.boot.Bootstrap

Java線上問題排查神器Arthas快速上手與原理淺談

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

Java線上問題排查神器Arthas快速上手與原理淺談

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

經過反射的方式來啓動字符客戶端

Java線上問題排查神器Arthas快速上手與原理淺談

服務端——前置準備

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

Java線上問題排查神器Arthas快速上手與原理淺談

  • 首先解析入參,生成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

Java線上問題排查神器Arthas快速上手與原理淺談

上圖中代碼:

Java線上問題排查神器Arthas快速上手與原理淺談

Java線上問題排查神器Arthas快速上手與原理淺談

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

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

服務端——Command處理流程

  1. 不須要使用字節碼加強的命令
其中JVM相關的使用 java.lang.management 提供的管理接口,來查看具體的運行時數據。比較簡單,就不介紹了。
  1. 須要使用字節碼加強的命令
字節碼增長的命令統一繼承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鏈接,關鍵的代碼有下面幾步:

  1. 構造TelnetClient對象,並初始化
  2. 構造ConsoleReader對象,並初始化
  3. 調用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神器,小白也能夠輕鬆上手。

碼字不易,但願你們捧我的場,謝謝諸位。

關注我,私信回覆「資料」或者查看我主頁介紹便可獲取面試寶典《Java核心知識點整理.pdf》還有Java208道面試題(含答案)的免費領取方式!

相關文章
相關標籤/搜索