目標羣體
BTRACE好強大,也曾技癢想做一個更便捷、更適合自己的問題定位工具,既可支持線上鏈路監控排查,也可支持單機版問題定位。
有時候突然一個問題反饋上來,需要入參才能完成定位,但恰恰沒有任何日誌,甚至出現在別人的代碼裏,好想開發一個工具可以根據需要動態添加日誌,最好還能按照業務ID進行過濾。
系統間的異常模擬可以使用的工具很多,可是系統內的異常模擬怎麼辦,加開關或是用AOP在開發系統中實現,好想開發一個更優雅的異常模擬工具,既能模擬系統間的異常,又能模擬系統內的異常。
好想獲取行調用鏈路數據,可以用它識別場景、覆蓋率統計等等,覆蓋率統計工具不能原生支持,統計鏈路數據不準確。想自己開發一個工具獲取行鏈路數據。
我想開發錄製回放、故障模擬、動態日誌、行鏈路獲取等等工具,就算我開發完成了,這些工具底層實現原理相同,同時使用,要怎麼消除這些工具之間的影響,怎麼保證這些工具動態加載,怎麼保證動態加載/卸載之後不會影響其他工具,怎麼保證在工具有問題的時候,快速消除影響,代碼還原
如果你有以上研發訴求,那麼你就是JVM-SANDBOX(以下簡稱沙箱容器)的潛在客戶。沙箱容器提供
動態增強類你所指定的類,獲取你想要的參數和行信息甚至改變方法執行
動態可插拔容器框架
項目簡介
JVM-SANDBOX(沙箱)實現了一種在不重啓、不侵入目標JVM應用的AOP解決方案。
沙箱的特性
無侵入:目標應用無需重啓也無需感知沙箱的存在
類隔離:沙箱以及沙箱的模塊不會和目標應用的類相互干擾
可插拔:沙箱以及沙箱的模塊可以隨時加載和卸載,不會在目標應用留下痕跡
多租戶:目標應用可以同時掛載不同租戶下的沙箱並獨立控制
高兼容:支持JDK[6,11]
沙箱常見應用場景
線上故障定位
線上系統流控
線上故障模擬
方法請求錄製和結果回放
動態日誌打印
安全信息監測和脫敏
JVM-SANDBOX還能幫助你做很多很多,取決於你的腦洞有多大了。
實時無侵入AOP框架
在常見的AOP框架實現方案中,有靜態編織和動態編織兩種。
靜態編織:靜態編織發生在字節碼生成時根據一定框架的規則提前將AOP字節碼插入到目標類和方法中,實現AOP;
動態編織:動態編織則允許在JVM運行過程中完成指定方法的AOP字節碼增強.常見的動態編織方案大多采用重命名原有方法,再新建一個同簽名的方法來做代理的工作模式來完成AOP的功能(常見的實現方案如CgLib),但這種方式存在一些應用邊界:
侵入性:對被代理的目標類需要進行侵入式改造。比如:在Spring中必須是託管於Spring容器中的Bean
固化性:目標代理方法在啓動之後即固化,無法重新對一個已有方法進行AOP增強
要解決無侵入的特性需要AOP框架具備 在運行時完成目標方法的增強和替換。在JDK的規範中運行期重定義一個類必須準循以下原則
不允許新增、修改和刪除成員變量
不允許新增和刪除方法
不允許修改方法簽名
JVM-SANDBOX屬於基於Instrumentation的動態編織類的AOP框架,通過精心構造了字節碼增強邏輯,使得沙箱的模塊能在不違反JDK約束情況下實現對目標應用方法的無侵入運行時AOP攔截。
核心原理
事件驅動
在沙箱的世界觀中,任何一個Java方法的調用都可以分解爲BEFORE、RETURN和THROWS三個環節,由此在三個環節上引申出對應環節的事件探測和流程控制機制。
// BEFORE try { /* * do something... */ // RETURN return; } catch (Throwable cause) { // THROWS }
基於BEFORE、RETURN和THROWS三個環節事件分離,沙箱的模塊可以完成很多類AOP的操作。
可以感知和改變方法調用的入參
可以感知和改變方法調用返回值和拋出的異常
可以改變方法執行的流程
在方法體執行之前直接返回自定義結果對象,原有方法代碼將不會被執行
在方法體返回之前重新構造新的結果對象,甚至可以改變爲拋出異常
在方法體拋出異常之後重新拋出新的異常,甚至可以改變爲正常返回
類隔離策略
沙箱通過自定義的SandboxClassLoader破壞了雙親委派的約定,實現了和目標應用的類隔離。所以不用擔心加載沙箱會引起應用的類污染、衝突。各模塊之間類通過ModuleJarClassLoader實現了各自的獨立,達到模塊之間、模塊和沙箱之間、模塊和應用之間互不干擾。
類增強策略
沙箱通過在BootstrapClassLoader中埋藏的Spy類完成目標類和沙箱內核的通訊
整體架構
快速安裝
下載並安裝
# 下載最新版本的JVM-SANDBOX wget http://ompc.oss-cn-hangzhou.aliyuncs.com/jvm-sandbox/release/sandbox-stable-bin.zip # 解壓 unzip sandbox-stable-bin.zip
掛載目標應用
# 進入沙箱執行腳本 cd sandbox/bin # 目標JVM進程33342 ./sandbox.sh -p 33342
掛載成功後會提示
./sandbox.sh -p 33342 NAMESPACE : default VERSION : 1.2.0 MODE : ATTACH SERVER_ADDR : 0.0.0.0 SERVER_PORT : 55756 UNSAFE_SUPPORT : ENABLE SANDBOX_HOME : /Users/vlinux/opt/sandbox SYSTEM_MODULE_LIB : /Users/vlinux/opt/sandbox/module USER_MODULE_LIB : ~/.sandbox-module; SYSTEM_PROVIDER_LIB : /Users/vlinux/opt/sandbox/provider EVENT_POOL_SUPPORT : DISABLE
卸載沙箱
./sandbox.sh -p 33342 -S jvm-sandbox[default] shutdown finished.