首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 運行時監控(二):編譯後插裝與性能監控

     編輯:Java 相關知識

前言

源碼級插裝雖有優勢(見第一部分),但面對第三方組件無源碼、生產環境不可修改源碼等場景,需採用編譯後插裝技術。本文介紹三大類無需修改原始源碼的插裝手法:攔截、類包裝、字節碼插裝,均基於第一部分的 ITracer 介面實現性能數據追蹤。

攔截器插裝

核心原理:透過攔截結構轉換特定調用模式,記錄入站/出站時間差計算運行時間,提交 APM。Java EE 容器(Servlet、EJB)與 Spring 等 IoC 框架均內建攔截器鏈支援,優勢在於:無需修改目標類源碼;僅需將攔截器類加入類路徑並修改部署描述符即可注入執行流程。

攔截器性能數據收集基本流程

攔截器核心指標與 ThreadMXBean 進階收集

典型指標:運行時間、每間隔調用/響應/異常計數、並發數。進階可選 ThreadMXBean 指標:線程 CPU 時間(納秒)、阻塞/等待計數與時間(同步等待、JDBC 遠程調用等)。收集需先 startThreadInfoCapture 建立基準,再 endThreadInfoCapture 計算增量,利用堆疊支援嵌套調用。注意:收集成本較高,避免在緊密循環中使用。並發計數器建議存儲於 JVM 受保護位置(如平台 MBean)避免多類加載器導致計數不準。

收集 ThreadMXBean 指標相對成本

EJB 3 攔截器

標準 @AroundInvoke + InvocationContext 實現。部署描述符 ejb-jar.xml 宣告攔截器類與綁定目標 EJB。InvocationContext 提供目標對象、方法名、參數等元數據,支援上下文追蹤:如遠程管理 EJB 依區域路由不同服務器,從參數提取區域碼加入複合命名空間,按區域劃分性能數據。

@AroundInvoke
public Object trace(InvocationContext ctx) throws Exception {
    int concur = concurrency.incrementAndGet();
    tracer.trace(concur, "EJB Interceptors", ctx.getTarget().getClass().getName(), ctx.getMethod().getName(), "Concurrent Invocations");
    tracer.startThreadInfoCapture(CPU + BLOCK + WAIT);
    Object returnValue = ctx.proceed();
    tracer.traceIncident("EJB Interceptors", ..., "Responses");
    concurrency.decrementAndGet();
    tracer.traceIncident(..., "Invocations");
    return returnValue;
}

Servlet Filter 攔截器

doFilter 中記錄請求 URI,filterChain.doFilter 前後包裹 ThreadInfoCapture。web.xml 映射 /* 覆蓋所有請求。指標複合名由過濾器類名與 URI 構建。

EJB 客戶端攔截與上下文傳遞

客戶端與服務端攔截器協作,透過調用負載傳遞時間戳上下文:客戶端請求時間、服務端接收時間、服務端響應時間。計算上行/下行傳輸時間與總耗時,區分網路延遲與服務端處理時間。JBoss AOP Interceptor 實現,ejb3-interceptors-aop.xml 定義切點與攔截器棧(客戶端 stack name、服務端 domain)。客戶端攔截器類須在客戶端類路徑,或啟用遠程類載入。時鐘不同步會導致異常結果。

客戶端與服務端 EJB 攔截器數據流

上下文客戶端攔截器性能指標

Spring AOP 攔截器

Spring MethodInterceptor 實現,透過 ProxyFactoryBean 為目標 Bean(如 EmpDAOImpl)建立代理鏈,注入 SpringTracingInterceptor。支援標準代理與優化代理(proxyTargetClass=true, optimize=true,使用 CGLIB)。測試對比四種場景:無攔截、標準攔截、優化攔截、非 Spring 管理直呼。結果顯示優化攔截器略優於標準,單線程測試差異微小,多線程下差異更明顯。

Spring 與攔截概覽

EmpDAO 類結構

Spring 攔截器測試 APM 指標樹

Spring 攔截器測試結果圖表

類包裝實現 JDBC 插裝

資料庫介面是企業應用性能問題高發區。JDBC 純介面定義、具體實現隱式載入,適合類包裝:定義新 JDBC Driver 包裝真實 Driver,攔截 connect 返回包裝後的 Connection、Statement、ResultSet,收集執行時間、並發、阻塞等指標。WrappingJDBCDriver 識別「轉碼後」URL(如 jdbc:!itracer!wrapped:postgresql://...),內部載入真實驅動、解碼 URL 建立真實連線再包裝。配置檔 wrapped-driver.xml 指定驅動前綴、類名、類路徑、追蹤命名空間正則模式(從 URL 提取資料庫類型與實例名)。

WrappingJDBCDriver 概覽

多線程測試與結果分析

強化測試用例:雙 DataSource(原始/插裝)、Spring 代理監控獲取連線時間、DAO 攔截器監控並發線程數、後台線程輪詢 DataSource 統計、WrappingJDBCCore 基類彙總資料庫級指標。結果明顯:插裝 JDBC 平均耗時顯著高於原始(27ms vs 5ms),插裝 Spring Bean 亦高於無攔截(36ms vs 16ms)。開銷來源:反射調用、較長代碼路徑、大量臨時對象創建。生產環境需深度調優。資料庫級彙總顯示平均阻塞時間為零,但最大值非零,APM 視覺化可同時呈現均值與極值。

插裝 JDBC 指標樹

插裝 JDBC 結果圖表

JDBC 彙總阻塞時間

字節碼插裝 (BCI)

直接修改類字節碼注入監控邏輯,不延長執行路徑、無額外對象開銷,效能優於攔截與包裝。兩大策略:

  • 靜態 BCI:構建時插裝,產出修改後的類檔案部署。使用 JBoss AOP aopc Ant 任務,jboss-aop.xml 定義切點(如 execution(public * $instanceof{DAO}->get(..)))與攔截器。啟動時需 -Djboss.aop.path=... 指定配置。靈活性受限:僅能激活構建時定義的切點。
  • 動態 BCI:啟動時 -javaagent:jboss-aop-jdk50.jar,JVM 載入類前動態重寫字節碼。ClassTransformer 實現 transform 方法修改位元碼。優勢:可插裝任意類(含第三方庫)、運行時熱切換切點與攔截器庫(如同時插裝 Connection.prepareStatement、PreparedStatement.executeQuery 並套用不同攔截器)。

靜態 BCI 指標樹

動態 BCI 指標樹

BCI 對比包裝性能

性能對比顯示 BCI 方法在 PreparedStatement.executeQuery 上開銷顯著低於包裝方式,確立 BCI 為高性能環境首選。

第二部分結語

本文詳述編譯後三大插裝技術:攔截器(EJB/Servlet/Spring/客戶端上下文傳遞)、類包裝(JDBC 驅動包裝)、字節碼插裝(靜態/動態 BCI)。選型視場景而定,但 BCI 已成主流。APM 系統(內建/開源/商用)實現 BCI 為 Java 性能管理基石。第三部分將介紹 JVM 外部資源監控(主機/OS、資料庫、通訊系統)及資料管理、視覺化、報警總結。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved