一、文档解读
1、分布式调用链查询和诊断:追踪分布式架构中的所有微服务用户请求,并将它们汇总成分布式调用链。
2、应用性能实时汇总:通过追踪整个应用程序的用户请求,来实时汇总组成应用程序的单个服务和资源。
3、分布式拓扑动态发现:用户的所有分布式微服务应用和相关 PaaS 产品可以通过链路追踪收集到的分布式调用信息。
4、多语言开发程序接入:基于 OpenTracing 标准,全面兼容开源社区,例如 Jaeger 和 Zipkin。
5、丰富的下游对接场景:收集的链路可直接用于日志分析,且可对接到 MaxCompute 等下游分析平台。
特点及作用分析:链路追踪工具是提供给开发者的一个记录应用调用过程和信息的一个工具,其上游支持不同编程语言SDK的接入,能够将开发者需要的分布式调用信息(包括微服务的和中间件产品)对接到下游平台进行分析。这些信息的作用是帮助用户对于应用在调用期间的问题进行收集,帮助开发者快速分析和诊断分布式应用架构下的性能瓶颈,提高微服务时代下的开发诊断效率。
二、产品测试
开通链路追踪后需要注意两个事项,因为链路追踪服务的下游牵涉到LOG SERVICE日志服务,因此需要授权链路追踪读写日志服务,主要通过三个步骤:
1、开通日志服务
2、开通访问控制RAM
3、授权链路追踪读写日志服务
之后会出现各种语言SDK的接入信息,从免费版来看支持JAVA、C++、Python、GO,这里我们以最常见的JAVA语言和Python语言的接入通过代码来分析整个链路追踪的配置,采用的是spring cloud方式来进行埋点:
JAVA语言SDK:
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-cloud-starter</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>io.jaegertracing</groupId>
<artifactId>jaeger-client</artifactId>
<version>0.31.0</version>
</dependency>
代码分析:以上是通过spring cloud方式进行埋点,所以代码分为两部分,引入 Jar 包依赖和添加组件依赖。
@Bean
public io.opentracing.Tracer tracer() {
io.jaegertracing.Configuration config = new io.jaegertracing.Configuration("springFrontend");
io.jaegertracing.Configuration.SenderConfiguration sender = new io.jaegertracing.Configuration.SenderConfiguration();
/**
* 从链路追踪控制台获取网关(Endpoint)、用户名、密码(userkey)
* 第一次运行时,请设置当前用户的网关、用户名、密码(userkey)
*/
sender.withEndpoint("http://tracing-analysis-dc-hz.aliyuncs.com/api/traces");
// 设置用户名
sender.withAuthUsername("abcdefg@123456");
// 设置密码(userkey)
sender.withAuthPassword("abcdefg@123456");
config.withSampler(new io.jaegertracing.Configuration.SamplerConfiguration().withType("const").withParam(1));
config.withReporter(new io.jaegertracing.Configuration.ReporterConfiguration().withSender(sender).withMaxQueueSize(10000));
代码分析:配置用户的网关、用户名和密码,这些信息在控制台里的region信息中可以看到,根据需要对不同的地域的用户名密码在SDK中进行设置。
如果是对于手动埋点的话,则代码为以下结构:
<dependency>
<groupId>io.jaegertracing</groupId>
<artifactId>jaeger-client</artifactId>
<version>0.31.0</version>
</dependency>
代码分析:同spring cloud不同的地方是,只需要添加组件的依赖即Jaeger组建,而没用Jar包,因为埋点的方式在这种情况下是手动的。
io.jaegertracing.Configuration config = new io.jaegertracing.Configuration("manalDemo");
io.jaegertracing.Configuration.SenderConfiguration sender = new io.jaegertracing.Configuration.SenderConfiguration();
/**
* 从链路追踪控制台获取网关(Endpoint)、用户名、密码(userkey)
* 第一次运行时,请设置当前用户的网关、用户名、密码(userkey)
*/
sender.withEndpoint("http://tracing-analysis-dc-hz.aliyuncs.com/api/traces");
// 设置用户名
sender.withAuthUsername("abcdefg@123456");
// 设置密码(userkey)
sender.withAuthPassword("abcdefg@123456");
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());
记录请求数据。
代码分析:同之前的方式一样,配置用户的网关、用户名和密码。
Tracer tracer = GlobalTracer.get();
// 创建 Span
Span span = tracer.buildSpan("parentSpan").withTag("myTag", "spanFrist").start();
tracer.scopeManager().activate(span, false);
tracer.activeSpan().setTag("methodName", "testTracing");
// 业务逻辑
testCall();
span.finish();
代码分析:添加Tracer 对象,创建 Span 对象(记录分布式操作时间)、跨机器透传数据(Extract/Inject 方法),或设置当前 Span(activeSpan)。
Tracer tracer = GlobalTracer.get();
Span parentspan = tracer.activeSpan();
Tracer.SpanBuilder spanBuilder = tracer.buildSpan("childSpan").withTag("myTag", "spanSecond");
if (parentspan !=null) {
spanBuilder.asChildOf(parentspan).start();
}
Span childSpan = spanBuilder.start();
tracer.scopeManager().activate(childSpan, false);
//.业务逻辑
childSpan.finish();
代码分析:用于记录应用的上一步请求操作和下一步请求操作,可以看到,创建了一个child span,当前的span即active span为parent span,如果当前的span不为空即有信息的话,执行spanBuilder函数对于下一步请求操作进行记录。这些记录的信息是可以自定义的,也就是在tracer.buildSpan之后可以根据需要创建标签来进行信息的采集。
Python语言SDK:
pip install jaeger-client
import logging
import time
from jaeger_client import Config
if __name__ == "__main__":
log_level = logging.DEBUG
logging.getLogger('').handlers = []
logging.basicConfig(format='%(asctime)s %(message)s', level=log_level)
config = Config(
config={ # usually read from some yaml config
'sampler': {
'type': 'const',
'param': 1,
},
'logging': True,
},
service_name='your-app-name',
)
# this call also sets opentracing.tracer
tracer = config.initialize_tracer()
with tracer.start_span('TestSpan') as span:
span.log_kv({'event': 'test message', 'life': 42})
with tracer.start_span('ChildSpan', child_of=span) as child_span:
span.log_kv({'event': 'down below'})
time.sleep(2) # yield to IOLoop to flush the spans - https://github.com/jaegertracing/jaeger-client-python/issues/50
tracer.close() # flush any buffered spans
代码分析:同JAVA需要配置Jaeger组建一样,Python需要安装Jaeger组件包,同样通过创建span来对需要采集的信息来设置标签。这里的span是一个没有parent的span,但实际的span设置可以根据需要自由设置(包括记录前后步操作的child span),和JAVA相同的地方是创建tracer的对象并通过在tracer创建span来实现对信息的追踪服务。
三、测试总结:
对于不同语言的链路追踪服务采用的接入方式其实是同一个,就是进行埋点,不管是JAVA还是Python的SDK中都是采用创建tracer对象来实现追踪服务,tracer创建完毕后通过tracer创建span来实现采集的标签,这种标签可以是自定义的,也可以根据需要通过parent span和child span的方式来实现对应用上一步和下一步操作的记录。