一 基本术语
Trace : 表示系统中一次数据或者执行路径的轨迹,可以简单认为是多个Span有向无环图。
Span:Span代表系统中一次逻辑操作运行单元。Span之间会建立嵌套或者顺序排列建立逻辑因果关系。
二 Jaeger组件架构
无缓存队列的架构
有缓存队列架构
三 服务追踪
服务追踪过程
四 应用埋点
1 手动埋点工具Client
针对非java应用,目前只能通过手动埋点的方式上报服务追踪信息,对应的client列表如下 :
Language | GitHub Repo |
Go | |
Java | |
Node.js | |
Python | |
C++ | |
C# |
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框架的自动埋点:
针对不同的框架,需要开发对应的OpenTracing API 插件用来实现自动埋点。以Spring Cloud框架为例子,简单说明下OpenTracing API 埋点实现过程。
4 Spring Cloud 埋点实现
主要实现原理利用Spring AOP切片技术抽象埋点行为,如代码所示声明了TraceAsyncAspect 切面类,使用@Around 声明拦截规则,后面的逻辑与手动埋点类似,创建一个span,将业务逻辑包围起来即可。
5 半自动埋点
Spring 应用埋点步骤
- pom.xml 添加依赖
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-cloud-starter</artifactId>
</dependency>
- 项目中定义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 应用的自动埋点
其他实现
- 添加依赖
- 配置参数 application.properties
spring.application.name=theservicenname
opentracing.jaeger.udp-sender.host=localhost
opentracing.jaeger.udp-sender.port=6831
- 上述两步即可完成服务追踪埋点,如果想实现手动埋点,可以通过@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)来实现自动埋点
整合方式
- 与Java-SpecialAgent代码实现没有耦合性,SpecialAgent需要实现集成规则来与社区 opentracing-contrib 上已经实现好的java框架埋点工具集成来实现自动埋点,这种方式也是该项目推荐的方式。
- 与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>
使用方式
- 静态绑定
java -javaagent:opentracing-specialagent-1.7.0.jar -jar MyApp.jar
- 动态绑定
// 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}
- 静态延迟绑定,应用优先启动,然后在绑定SpecialAgent
// 目前仅支持 SpringBoot Spring WebMVC
java -javaagent:opentracing-specialagent-1.7.0.jar -Dsa.init.defer=true -jar MySpringBootApp.jar
全自动埋点实现原理
ByteBuddy 是 Java 运行时字节码生成库,本质上是AOP编程实现。
举例说明
- 定义 Log 注解
- 定义 字节码类LoggerAdvisor
- 定义测试类
- 执行结果
Java-specialagent具体实现
埋点集成
通过bytebuddy字节码API集成社区已经实现好的java框架自动埋点。
- 加载启动配置 AssembleUtil.loadProperties()
- 设置Agent Instrumentation 有加载到JVM的类所有操作权限 BootLoaderAgent.premain(inst)
- 加载第三方埋点实现 AgentRule.$Access.load()
load(instrumenter.manager, ruleFiles, isoClassLoader)
埋点规则举例
设置规则
拦截器实现
埋点上报
通过java SPI机制完成追踪信息上报的分布式追踪系统。目前支持的分布式追踪系统包括:
Trace Exporter |
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 技术架构
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 插件为例子,如下是相关类图 :
埋点插件扩展
|
定义拦截点
实现一个增强类
|
总结
对比
对比项 | java-specialagent | skywalking |
支持多语言 | 是 | 是 |
支持扩展框架 | 是 | 是 |
支持java应用自动埋点 | 是 | 是 |
支持OpenTracing | 是 | 是 |
GitHub Start | 108 | 13k |
告警支持 | 否 | 是 |
JVM监控 | 否 | 是 |
用户数 | 少 | 多 |
插件数 | 45+ | 60+ |
是否国内人员开发 | 否 | 是 |
结论
Java-specialagent和skywalking 都是通过javaAgent机制和字节码增强机制来实现java应用的无侵入埋点。但是,从用户使用情况和社区支持情况来看skywalking 要优于java-specialagent,skywalking在文档和插件扩展开发方面也要优于java-specialagent。
参考
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