OpenTracing API 自動埋點調研

一 基本術語

Trace : 表示系統中一次數據或者執行路徑的軌跡,可以簡單認爲是多個Span有向無環圖。

Span:Span代表系統中一次邏輯操作運行單元。Span之間會簡歷嵌套或者順序排列建立邏輯因果關係

二 組件架構

 

無緩存隊列的架構

 

 

有緩存隊列架構

三 服務追蹤

服務追蹤過程

四 應用埋點

1 手動埋點工具Client

針對非java應用,目前只能通過手動埋點的方式上報服務追蹤信息,對應的client列表如下 :

Language

GitHub Repo

Go

jaegertracing/jaeger-client-go

Java

jaegertracing/jaeger-client-java

Node.js

jaegertracing/jaeger-client-node

Python

jaegertracing/jaeger-client-python

C++

jaegertracing/jaeger-client-cpp

C#

jaegertracing/jaeger-client-csharp

 

2 手動埋點過程

1. 添加依賴 主要添加opentracing 和 jaeger相關依賴

2. 初始化Tracer對象,並註冊到GlobalTracer

 

io.jaegertracing.Configuration config = new io.jaegertracing.Configuration("demo");

io.jaegertracing.Configuration.SenderConfiguration sender = new io.jaegertracing.Configuration.SenderConfiguration();

// endpoint jaeger collector url :14268/api/traces

sender.withEndpoint("http://collertor-host:14268/api/traces ");

config.withSampler(new io.jaegertracing.Configuration.SamplerConfiguration().withType("const").withParam(1));

config.withReporter(new io.jaegertracing.Configuration.ReporterConfiguration().withSender(sender).withMaxQueueSize(10000));

GlobalTracer.register(config.getTracer());

 

3. 具體方法體內部獲取Tracer對象,並記錄請求數據

Tracer tracer = GlobalTracer.get();
// 創建 Span
Span span = tracer.buildSpan("parentSpan").withTag("myTag", "spanFirst").start();
tracer.scopeManager().activate(span,false);
tracer.activeSpan().setTag("methodName", "testTracing");
// 業務邏輯
...
span.finish();

 

4. 多個微服務間通過Context傳遞Trace信息,比如在HTTP請求中使用Extract/Inject 方法在 HTTP Request Headers 上透傳數據

//客戶端Inject
tracer.inject(tracer.activeSpan().context(), Format.Builtin.HTTP_HEADERS, new RequestBuilderCarrier(requestBuilder));

//服務端Extract
parentSpanCtx = tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapExtractAdapter(headers));

 

3 Java應用自動埋點

目前OpenTracing API社區已經實現了支持各種java框架的自動埋點:

  1. Apache HttpClient
  2. Elasticsearch
  3. JDBC
  4. Kafka
  5. Memcached
  6. Mongo
  7. OkHttp
  8. Redis
  9. Spring Boot
  10. Spring Cloud

針對不同的框架,需要開發對應的OpenTracing API 插件用來實現自動埋點。以Spring Cloud框架爲例子,簡單說明下OpenTracing API 埋點實現過程。

4 Spring Cloud 埋點實現

主要實現原理利用Spring AOP切片技術抽象埋點行爲,如代碼所示聲明瞭TraceAsyncAspect 切面類,使用@Around 聲明攔截規則,後面的邏輯與手動埋點類似,創建一個span,將業務邏輯包圍起來即可。

5 半自動埋點

Spring 應用埋點步驟

  1. pom.xml 添加依賴
<dependency>
  <groupId>io.opentracing.contrib</groupId>
  <artifactId>opentracing-spring-cloud-starter</artifactId>
</dependency>
  1. 項目中定義OpenTracing Tracer Client Bean
@Bean
public io.opentracing.Tracer tracer() {
  //return new  tracer instance of your choice (Zipkin, Jaeger, LightStep)
return new Configuration("spring-boot", new Configuration.SamplerConfiguration(ProbabilisticSampler.TYPE, 1),
        new Configuration.ReporterConfiguration())
        .getTracer();
}

在現有項目或者新建項目中完成上述兩步即可完成Spring 應用的自動埋點

其他實現

  1. 添加依賴

 

  1. 配置參數 application.properties

 

spring.application.name=theservicenname
opentracing.jaeger.udp-sender.host=localhost
opentracing.jaeger.udp-sender.port=6831
  1. 上述兩步即可完成服務追蹤埋點,如果想實現手動埋點,可以通過@Autowired 註解 在對應的類上定義Trace變量即可,這樣可以在具體的類方法上手動埋點。
@Autowired
Tracer tracer;

6 全自動埋點

利用javaAgent機制和字節碼技術實現對代碼無侵入的收集埋點信息,上傳到分佈式追蹤系統Jaeger、skywalking、等。即通過java代理攔截器實現埋點。使用方法很簡單僅需要在java 啓動命令前 添加 javaagent 參數命令即可。

java -javaagent:{agentpath} -jar MyApp.jar

Java-specialagent

java-specialagent 是基於bytebuddy字節碼框架開發的自動埋點Agent

目前最新穩定版 1.7.0

簡介

Java-SpecialAgent 能夠動態或者靜態的綁定java應用,實現自動埋點。通過整合不同的java框架(spring,es,kafka)埋點規則和不同的Tracer Exporter(jaeger、LightStep、wavefront)來實現自動埋點

整合方式

  1. 與Java-SpecialAgent代碼實現沒有耦合性,SpecialAgent需要實現集成規則來與社區 opentracing-contrib 上已經實現好的java框架埋點工具集成來實現自動埋點,這種方式也是該項目推薦的方式。
  2. 與Java-SpecialAgent代碼實現完全耦合性,在SpecialAgent內部實現某種java框架的埋點規則,用戶想使用的話,必須只能通過Java-SpecialAgent 代碼啓動應用進行埋點。

Trace Exporters

SpecialAgent 通過 java的SPI機制來創建不同的分佈式追蹤系統的client,以jaeger爲例說明。

<isolatedDependencies>
...
  <dependency>
    <groupId>io.opentracing.contrib</groupId>
    <artifactId>jaeger-client-bundle</artifactId>
  </dependency>
...
</isolatedDependencies>

 

使用方式

  1. 靜態綁定
java -javaagent:opentracing-specialagent-1.7.0.jar -jar MyApp.jar
  1. 動態綁定
// jdk 1.8
java -Xbootclasspath/a:$JAVA_HOME/lib/tools.jar -jar opentracing-specialagent-1.7.0.jar ${PID}
// jdk 1.9
java -jar opentracing-specialagent-1.7.0.jar ${PID}
  1. 靜態延遲綁定,應用優先啓動,然後在綁定SpecialAgent
// 目前僅支持 SpringBoot Spring WebMVC 
java -javaagent:opentracing-specialagent-1.7.0.jar -Dsa.init.defer=true -jar MySpringBootApp.jar

 

全自動埋點實現原理

ByteBuddy 是 Java 運行時字節碼生成庫,本質上是AOP編程實現。

舉例說明

  1. 定義 Log 註解

 

  1. 定義 字節碼類LoggerAdvisor

  1. 定義測試類

  1. 執行結果

Java-specialagent具體實現

埋點集成

通過bytebuddy字節碼API集成社區已經實現好的java框架自動埋點。

  1. 加載啓動配置  AssembleUtil.loadProperties()
  2. 設置Agent Instrumentation 有加載到JVM的類所有操作權限 BootLoaderAgent.premain(inst)
  3. 加載第三方埋點實現  AgentRule.$Access.load()

load(instrumenter.manager, ruleFiles, isoClassLoader)

埋點規則舉例

設置規則

攔截器實現

埋點上報

通過java SPI機制完成追蹤信息上報的分佈式追蹤系統。目前支持的分佈式追蹤系統包括:

Trace Exporter

Jaeger Trace Exporter

LightStep Trace Exporter

Wavefront Trace Exporter

OpenTelemetry Bridge Trace Exporter

MockTracer

 

 

 

 

 

 

 

Java-specialagent 集成 java-tracerresolver 項目實現不同 Trace

Exporter 加載, 在 java-tracerresolver 內工具類 TracerResolver 中包含靜態方法 resolveTracer(),通過該方法查找實現 TracerFactory 接口方法的 Trace Exporters。

不同類別的Trace Exporters 都需要統一實現 TracerFactory 方法,以Jaeger 爲例,代碼實現如下:

Java-specialagent 在根POM 中的 <isolatedDependencies> 配置指定的依賴項,實現Trace Exporters 與 Java-specialagent 的集成。

 

java-specialagent 在應用啓動之前會預加載Trace Exporters, Trace Exporters 根據配置區分。

加載過程

Jaeger舉例

java -javaagent:opentracing-specialagent-1.7.0.jar -Dsa.tracer=jaeger -Dsa.log.level=INFO  -DJAEGER_SERVICE_NAME="test"  -jar springboot-helloworld-1.0-SNAPSHOT.jar

五 SkyWalking實現原理

1 SkyWalking簡介

分佈式系統的應用程序性能監視工具,專爲微服務、雲原生架構和基於容器架構而設計,開源Mosn在未來的計劃中也要納入SkyWalking

SkyWalking 是觀察性分析平臺和應用性能管理系統。提供分佈式追蹤、服務網格遙測分析、度量聚合和可視化一體化解決方案.支持Java, .Net Core, PHP, NodeJS, Golang, LUA語言探針支持Envoy + Istio構建的Service Mesh

2 技術架構

frame.jpeguploading.4e448015.gif正在上傳…重新上傳取消frame.jpeguploading.4e448015.gif正在上傳…重新上傳取消frame.jpeg

3 實現原理

SkyWalking Agent 同樣也是基於 JavaAgent 機制和字節碼增強技術,實現應用自動埋點。

SkyWalking Agent啓動過程

1 初始化Agent配置 SnifferConfigInitializer.initialize(agentArgs)

2 加載Agent插件 new PluginFinder(new PluginBootstrap().loadPlugins())

3 通過ByteBuddy初始化 Agent Instrumentation

4 初始化服務管理 ServiceManager.INSTANCE.boot()

插件化實現透明埋點

SkyWalking Agent 提供了多種插件,實現不同框架的埋點。

插件的加載

通過AgentClassLoader 繼承 java.lang.ClassLoader 實現Agent 類加載器。應用透明接入 SkyWalking ,不會顯示導入 SkyWalking 的插件依賴。通過實現自定義的 ClassLoader ,從插件 Jar 中查找相關類。例如說,從 apm-dubbo-plugin.jar 查找 org.skywalking.apm.plugin.dubbo.DubboInstrumentation

插件的匹配

插件資源解析器 PluginResourcesResolver 讀取所有插件的定義文件。插件定義文件必須以 skywalking-plugin.def 命名,例如 :

再讀取 skywalking-plugin.def 文件,生成插件定義,添加到 pluginClassList

插件的攔截

AbstractClassEnhancePluginDefine ,類增強插件定義抽象基類。不同插件通過實現 AbstractClassEnhancePluginDefine 抽象類,定義不同框架的切面,記錄調用鏈路。以 Spring 插件爲例子,如下是相關類圖 :

 

http://static.iocoder.cn/images/SkyWalking/2020_07_05/06.png

點插件擴展

 

public interface InstanceMethodsInterceptPoint {

    //定義切向方法的適配器,符合適配器的class將被增強

    ElementMatcher<MethodDescription> getMethodsMatcher();

    //增強的具體實現類,classReference

    String getMethodsInterceptor();

    //是否重寫參數

    boolean isOverrideArgs();

}

義攔截點

 

 

實現一個增強類

 

public interface InstanceMethodsAroundInterceptor {

    //方法真正執行前執行

    void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,

        MethodInterceptResult result) throws Throwable;

    //方法真正執行後執行

    Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,

        Object ret) throws Throwable;

    //當異常發生時執行

    void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,

        Class<?>[] argumentsTypes,

        Throwable t);

}

 

總結

對比

對比項

java-specialagent

skywalking

支持多語言

支持擴展框架

支持java應用自動埋點

支持OpenTracing

GitHub Start

108

 13k

告警支持

JVM監控

用戶數

插件數

45+

60+

是否國內人員開發

結論

Java-specialagent和skywalking 都是通過javaAgent機制和字節碼增強機制來實現java應用的無侵入埋點。但是,從用戶使用情況和社區支持情況來看skywalking 要優於java-specialagent,skywalking在文檔和插件擴展開發方面也要優於java-specialagent。

java-specialagent 支持自動埋點列表  https://github.com/opentracing-contrib/java-specialagent#41-integrations

skywalking 支持自動埋點列表 https://github.com/apache/skywalking/blob/v7.0.0/docs/en/setup/service-agent/java-agent/Supported-list.md

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