1. 程式人生 > >JVM系列十(虛擬機器效能監控神器 - BTrace).

JVM系列十(虛擬機器效能監控神器 - BTrace).

BTrace 是什麼?

BTrace 是一個動態安全的 Java 追蹤工具,它通過向執行中的 Java 程式植入位元組碼檔案,來對執行中的 Java 程式熱更新,方便的獲取程式執行時的資料資訊,並且,保證自己的消耗特別小,大部分情況下不會影響 Java 程式的效能。

BTrace 能幹什麼?

相信每一位開發都或多或少的幹過這檔子事:為了解決線上的一個 bug,不得不在程式碼中列印下入參、出引數據,然後再重啟伺服器,觀察日誌。BTrace 的出現就是為了解決這類事宜,BTrace 的最大好處,是可以通過自己編寫的指令碼,獲取應用的一切呼叫資訊,而不需要不斷的修改程式碼,然後重啟應用。

以下是 BTrace 的一些典型應用場景:

  • 服務慢,能找出慢在哪一步,哪個函式裡麼?
  • 誰呼叫了System.gc(),呼叫棧如何?
  • 誰構造了一個超大的 ArrayList?
  • 什麼樣的入參或物件屬性,導致丟擲了這個異常?或進入了這個處理分支?

BTrace 快速開始

下載最新的 BTrace releases 版本:https://github.com/btraceio/btrace/releases

解壓資料夾,在 <BTRACE_HOME>/bin 目錄下主要有兩個命令:一個是 btrace,一個是 btracec。

btrace

BTRACE_HOME/bin/btrace PID <trace_script>

btrace 將通過 JVM Attach API 連線到 的 java 應用程式,然後把指令碼繫結到應用程序,進行 AOP 式的程式碼植入。

btracec

BTRACE_HOME/bin/btracec <trace_script>

類似於 javac,btracec 命令是用來預編譯指令碼的,以此校驗指令碼語法的正確性,要不然等執行到線上才發現寫錯就尷尬了。

BTrace 指令碼

寫到這裡,唯一能阻礙我們繼續下去的,就是怎麼寫 BTrace 指令碼了。

首先,推薦在整合工具(IDEA、Eclipse)中編寫 BTrace 指令碼,引入 BTrace 的依賴:

        <dependency>
            <groupId>com.sun.tools.btrace</groupId>
            <artifactId>btrace-agent</artifactId>
            <version>1.2.3</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>D:\btace\libs\btrace-agent.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.sun.tools.btrace</groupId>
            <artifactId>btrace-boot</artifactId>
            <version>1.2.3</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>D:\btace\libs\btrace-boot.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.sun.tools.btrace</groupId>
            <artifactId>btrace-client</artifactId>
            <version>1.2.3</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>D:\btace\libs\btrace-client.jar</systemPath>
        </dependency>

先來看一個簡單的 Demo 示例:

@BTrace//表示這是一個BTrace跟蹤指令碼
public class Hello {

    @OnMethod(clazz = "org.jvm.demo.chapter4.btrace.BtraceCase", // 全類名
            method = "add", // 方法名
            location = @Location(Kind.RETURN) // 表示跟蹤某個類的某個方法,位置為方法返回處
    )
    public static void run(@Self Object self, int a, int b, // 入參,按順序定義
                           @Return int result, // 出參
                           @Duration long time // 方法耗時
    ) {
        BTraceUtils.print("列印入參, a = " + a + ",b=" + b);
        BTraceUtils.print("打印出參, result = " + result);
        BTraceUtils.print("列印耗時,time = " + time);
    }
}
btrace.bat 4284 src/main/java/org/jvm/demo/chapter4/btrace/Hello.java

BTrace 主要有兩類註解需要學習,一類是探測方法的註解,像上面的 @OnMethod 註解,類似的還有 @OnTimer、@OnError、@OnExit、@OnEvent、@OnLowMemory、@OnProbe 等等;另一類是探測方法引數的註解,像上面的 @Return、@Duration、@Self,類似的還有 @ProbeMethodName、@ProbeClassName、@TargetInstance、@TargetMethodOrField 等等

本文不過分說明 BTrace 的語法,私以為平常遇到什麼樣的業務場景,邊學邊用就是了,以下是官方的一些 BTrace 資料:

  • BTrace Github Wiki
  • BTrace User's Guide

由於 BTrace 的安全和效能考慮,一般情況下不允許在探查方法中呼叫 BTraceUtils 以外的其它方法,但可使用 unsafe 模式。

BTrace 植入過的程式碼,會一直在,直到應用重啟為止。所以即使 Btrace 退出了,業務函式每次執行時都會多出一次 Btrace 是否 Attach 狀態的判斷。

為了保證程式的安全,BTrace對編寫的指令碼進行了一些限制,比如不允許在指令碼中建立物件,不允許在指令碼中丟擲異常等,更詳細的限制請參考 BTrace 使用限制。



推薦閱讀:
  1. Btrace入門到熟練小工完全指南
  2. 如何在生產環境使用Btrace進行除錯
  3. BTrace使用小結