BTrace原理概述

概述

Btrace是一種安全、動態跟蹤分析一個運行中的Java應用程序的工具。 
BTrace動態地向目標應用程序的字節碼注入追蹤代碼(字節碼追蹤),這些追蹤字節碼追蹤代碼使用Java語言表達,也就是BTrace的腳本。

組件說明

1. BtraceClient :

爲我們使用的btrace的本地api,一般我們使用的bin/btrace會在本地啓動一個btrace jvm,其內部使用了Java Complier Api, JVMTI技術,以及創建了一個socket。

Java Complier Api:將我們傳遞的監控的java源文件動態編譯成.class文件 

JVMTI:主要是利用了java 1.6之後的VirtaulMachine技術,動態的attach到一個已啓動的jvm上,爲他去啓動一個BtraceAgent。該Agent會爲BtraceClient啓動一個server socket進行通訊。(多進程之間的通訊)

本地socket:BtraceClient和BtraceAgent之間的數據通訊,比如生成的.class發送到BtraceAgent,還有一些Event事件等等。BtraceAgent同樣可以將服務端print()的數據通過socket的方式回傳給BtraceClient進行打印


2. BtraceAgent:

爲我們在目標jvm上植入的btrace agent實現。主要是Instrumentation技術, asm字節碼處理技術。

BtraceAgent的啓動可以有兩種方式:BtaceClient動態attach後進行啓動,另一種就是在目標jvm啓動之前添加agent參數進行啓動。

BtraceAgent會啓動一個server socket,與BtraceClient客戶端進行交互,客戶端可以將監控的.class文件通過socket發送,同樣也可以在jvm啓動時直接指定對應本地的.class做爲監控腳本。

BtraceAgent在接受到監控指令後,會遍歷當前所有已經加載的class類,挨個進行匹配檢查,並生成相應的監控字節碼(監控方法)。

btrace支持的jdk版本

java 1.4以及之前 : 不支持,Instrument在jdk 1.5之後纔出現。 
java 1.5 : 必須手動在jvm啓動時添加btrace-agent.jar,因爲VirtualMachine是在jdk 1.6之後纔出現。 
java 1.6 : 推薦使用

btrace的支持的script方式

1.client上的.java文件 
會進行動態編譯,會有比較多的語法限制,btrace一堆的你不能做的事 
2.client上的.class文件 
沒什麼好講的,自己寫Btrace script時導入btrace-client.jar,寫好後生成一個.class文件,再通過btrace pid Btrace.class進行啓動。 
3.remote上的.class文件 
修改btrace-client中的Client類,支持script和scriptDir的一些參數提交。 
在remote機器上放置對應的btrace.class文件

btrace的使用是否會對java進程造成影響?(影響是肯定的,不過影響不大)

1.裝載時的影響: 
btrace每次使用,都會重新load所監控的class。當然如果OnMethod不匹配,是不會被重新裝載。所以跟你的OnMethod的匹配規則很有關係,如果使用java.lang.Object。那就死定了。 
2.退出後的影響: 
btrace監控每次退出後,原先所有的class都不會被恢復,你的所有的監控代碼依然一直在運行 。

抓取了下btrace改寫過後的類(也可以通過jvisualvm的btrace插件dump出修改類):
public InstrumentServer(String ip, String port) 

$btrace$com$agapple$btrace$Instrumentor$InstrumentTracer$bufferMonitor(this); 
this.ip = ip; 
this.port = port; 
}

private static void $btrace$com$agapple$btrace$Instrumentor$InstrumentTracer$bufferMonitor(@Self Object arg0) 

if (!BTraceRuntime.enter(InstrumentTracer.runtime)) return;

  try { Field ipField = BTraceUtils.field("com.agapple.btrace.Instrumentor.InstrumentServer", "ip"); 
Field portField = BTraceUtils.field("com.agapple.btrace.Instrumentor.InstrumentServer", "port");

String ip = (String)BTraceUtils.get(ipField, self); 
String port = (String)BTraceUtils.get(portField, self); 
BTraceUtils.println(BTraceUtils.strcat(BTraceUtils.strcat(BTraceUtils.strcat("ip : ", BTraceUtils.str(ip)), " port : "), BTraceUtils.str(port))); 
BTraceRuntime.leave(); return; } catch (Throwable localThrowable) { BTraceRuntime.handleException(localThrowable); 


注意其中的if (!BTraceRuntime.enter(InstrumentTracer.runtime)) return; 
再看一下BTraceRuntime中對應方法的實現:
private volatile boolean disabled;

public static boolean enter(BTraceRuntime current) 

if (current.disabled) return false; 
return map.enter(current); 

每次執行你的監控代碼之前會先進行一個判斷,判斷當前是否處於監控中。你的客戶端發起了exit指令後,該方法判斷false,直接return。
所以btrace使用退出後會讓你的代碼多走了一個方法調用+一個對象屬性判斷,所以說影響還是非常的少。


btrace諸多的使用限制(設置unsafe=true可突破限制)

can not create new objects. 
can not create new arrays. 
can not throw exceptions. 
can not catch exceptions. 
can not make arbitrary instance or static method calls - only the public static methods of com.sun.btrace.BTraceUtils class or methods declared in the same program may be called from a BTrace program. 
(pre 1.2) can not have instance fields and methods. Only static public void returning methods are allowed for a BTrace class. And all fields have to be static. 
can not assign to static or instance fields of target program’s classes and objects. But, BTrace class can assign to it’s own static fields (“trace state” can be mutated). 
can not have outer, inner, nested or local classes. 
can not have synchronized blocks or synchronized methods. 
can not have loops (for, while, do..while) 
can not extend arbitrary class (super class has to be java.lang.Object) 
can not implement interfaces. 
can not contains assert statements. 
can not use class literals.

說明:

在btrace-client和btrace-agent分別都有對諸多限制的檢查。 

正因爲btrace有這諸多的限制,纔可以讓我們的監控代碼可以更加的放心,這也正是btrace能普及的一個很重要的原因。 

btrace可突破對應的限制。不是非常建議,因爲上文中提出即使btrace client退出後,服務端一直會運行btrace script。所以一旦有寫的動作,會是一個長期持續的過程。

參考文檔

https://github.com/btraceio/btrace

https://blog.csdn.net/conquer0715/article/details/51781206

http://www.iteye.com/topic/1005918

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章