Trace : 表示系统中一次数据或者执行路径的轨迹,可以简单认为是多个Span有向无环图。
Span:Span代表系统中一次逻辑操作运行单元。Span之间会建立嵌套或者顺序排列建立逻辑因果关系。
无缓存队列的架构
有缓存队列架构
服务追踪过程
针对非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 |
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));
目前OpenTracing API社区已经实现了支持各种java框架的自动埋点:
针对不同的框架,需要开发对应的OpenTracing API 插件用来实现自动埋点。以Spring Cloud框架为例子,简单说明下OpenTracing API 埋点实现过程。
主要实现原理利用Spring AOP切片技术抽象埋点行为,如代码所示声明了TraceAsyncAspect 切面类,使用@Around 声明拦截规则,后面的逻辑与手动埋点类似,创建一个span,将业务逻辑包围起来即可。
Spring 应用埋点步骤
io.opentracing.contrib
opentracing-spring-cloud-starter
@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 应用的自动埋点
其他实现
spring.application.name=theservicenname
opentracing.jaeger.udp-sender.host=localhost
opentracing.jaeger.udp-sender.port=6831
@Autowired
Tracer tracer;
利用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)来实现自动埋点
整合方式
Trace Exporters
SpecialAgent 通过 java的SPI机制来创建不同的分布式追踪系统的client,以jaeger为例说明。
...
io.opentracing.contrib
jaeger-client-bundle
...
使用方式
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}
// 目前仅支持 SpringBoot Spring WebMVC
java -javaagent:opentracing-specialagent-1.7.0.jar -Dsa.init.defer=true -jar MySpringBootApp.jar
全自动埋点实现原理
ByteBuddy 是 Java 运行时字节码生成库,本质上是AOP编程实现。
举例说明
Java-specialagent具体实现
埋点集成
通过bytebuddy字节码API集成社区已经实现好的java框架自动埋点。
load(instrumenter.manager, ruleFiles, isoClassLoader)
埋点规则举例
设置规则
拦截器实现
埋点上报
通过java SPI机制完成追踪信息上报的分布式追踪系统。目前支持的分布式追踪系统包括:
Trace Exporter |
Jaeger Trace Exporter |
LightStep Trace Exporter |
Wavefront Trace Exporter |
OpenTelemetry Bridge Trace Exporter |
|
Java-specialagent 集成 java-tracerresolver 项目实现不同 Trace
Exporter 加载, 在 java-tracerresolver 内工具类 TracerResolver 中包含静态方法 resolveTracer(),通过该方法查找实现 TracerFactory 接口方法的 Trace Exporters。
不同类别的Trace Exporters 都需要统一实现 TracerFactory 方法,以Jaeger 为例,代码实现如下:
Java-specialagent 在根POM 中的
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
分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器架构而设计,开源Mosn在未来的计划中也要纳入SkyWalking。
SkyWalking 是观察性分析平台和应用性能管理系统。提供分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案.支持Java, .Net Core, PHP, NodeJS, Golang, LUA语言探针支持Envoy + Istio构建的Service Mesh。
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 插件为例子,如下是相关类图 :
埋点插件扩展
public interface InstanceMethodsInterceptPoint { //定义切向方法的适配器,符合适配器的class将被增强 ElementMatcher //增强的具体实现类,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。
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