一 基本术语

Trace : 表示系统中一次数据或者执行路径的轨迹,可以简单认为是多个Span有向无环图。

Span:Span代表系统中一次逻辑操作运行单元。Span之间会建立嵌套或者顺序排列建立逻辑因果关系。

ASM自动埋点 android api埋点_运维

二 Jaeger组件架构

ASM自动埋点 android api埋点_运维_02

 

无缓存队列的架构

 

 

ASM自动埋点 android api埋点_ci_03

有缓存队列架构

三 服务追踪

ASM自动埋点 android api埋点_运维_04

服务追踪过程

四 应用埋点

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,将业务逻辑包围起来即可。

ASM自动埋点 android api埋点_ci_05

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. 添加依赖

ASM自动埋点 android api埋点_运维_06

 

  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 注解

ASM自动埋点 android api埋点_ASM自动埋点 android_07

 

  1. 定义 字节码类LoggerAdvisor

ASM自动埋点 android api埋点_分布式_08

  1. 定义测试类

ASM自动埋点 android api埋点_ASM自动埋点 android_09

  1. 执行结果

ASM自动埋点 android api埋点_ci_10

Java-specialagent具体实现

埋点集成

通过bytebuddy字节码API集成社区已经实现好的java框架自动埋点。

  1. 加载启动配置  AssembleUtil.loadProperties()
  2. 设置Agent Instrumentation 有加载到JVM的类所有操作权限 BootLoaderAgent.premain(inst)
  3. 加载第三方埋点实现  AgentRule.$Access.load()

load(instrumenter.manager, ruleFiles, isoClassLoader)

ASM自动埋点 android api埋点_分布式_11

埋点规则举例

设置规则

ASM自动埋点 android api埋点_ci_12

拦截器实现

ASM自动埋点 android api埋点_运维_13

ASM自动埋点 android api埋点_ci_14

埋点上报

通过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。

ASM自动埋点 android api埋点_运维_15

不同类别的Trace Exporters 都需要统一实现 TracerFactory 方法,以Jaeger 为例,代码实现如下:

ASM自动埋点 android api埋点_ASM自动埋点 android_16

Java-specialagent 在根POM 中的 <isolatedDependencies> 配置指定的依赖项,实现Trace Exporters 与 Java-specialagent 的集成。

 

ASM自动埋点 android api埋点_ASM自动埋点 android_17

java-specialagent 在应用启动之前会预加载Trace Exporters, Trace Exporters 根据配置区分。

加载过程

ASM自动埋点 android api埋点_ci_18

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 技术架构

ASM自动埋点 android api埋点_运维_19

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 提供了多种插件,实现不同框架的埋点。

ASM自动埋点 android api埋点_kubernetes_20

插件的加载

通过AgentClassLoader 继承 java.lang.ClassLoader 实现Agent 类加载器。应用透明接入 SkyWalking ,不会显示导入 SkyWalking 的插件依赖。通过实现自定义的 ClassLoader ,从插件 Jar 中查找相关类。例如说,从 apm-dubbo-plugin.jar 查找 org.skywalking.apm.plugin.dubbo.DubboInstrumentation

插件的匹配

插件资源解析器 PluginResourcesResolver 读取所有插件的定义文件。插件定义文件必须以 skywalking-plugin.def 命名,例如 :

ASM自动埋点 android api埋点_ASM自动埋点 android_21

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

插件的拦截

AbstractClassEnhancePluginDefine ,类增强插件定义抽象基类。不同插件通过实现 AbstractClassEnhancePluginDefine 抽象类,定义不同框架的切面,记录调用链路。以 Spring 插件为例子,如下是相关类图 :

 

ASM自动埋点 android api埋点_ASM自动埋点 android_22

点插件扩展

 


public interface InstanceMethodsInterceptPoint {
    //定义切向方法的适配器,符合适配器的class将被增强
    ElementMatcher<MethodDescription> getMethodsMatcher();
    //增强的具体实现类,classReference
    String getMethodsInterceptor();
    //是否重写参数
    boolean isOverrideArgs();
}


义拦截点

ASM自动埋点 android api埋点_ci_23

 

 

实现一个增强类

 


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);
}


 

ASM自动埋点 android api埋点_运维_24

总结

对比

对比项

java-specialagent

skywalking

支持多语言

支持扩展框架

支持java应用自动埋点

支持OpenTracing

GitHub Start

108

 13k

告警支持

JVM监控

用户数

插件数

45+

60+

是否国内人员开发

结论

Java-specialagent和skywalking 都是通过javaAgent机制和字节码增强机制来实现java应用的无侵入埋点。但是,从用户使用情况和社区支持情况来看skywalking 要优于java-specialagent,skywalking在文档和插件扩展开发方面也要优于java-specialagent。

ASM自动埋点 android api埋点_ci_25

参考

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

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