ServiceComb + Zipkin : 源码解读
SeviceComb + Zipkin 简介
ServiceComb 是Apache开源的微服务架构,在微服务框架中,服务通过网络进行通信,我们必须处理所有与网络相关的问题,例如延迟,超时和分区。随着部署的服务越来越多,我们需要系统监控微服务网络延迟和请求流。
Zipkin是一种分布式跟踪系统。它有助于收集解决微服务架构中的延迟问题所需的时序数据。它管理这些数据的收集和查找。Zipkin的设计基于Google Dapper论文。参见Zipkin官网1
ServiceComb与Zipkin集成以提供自动跟踪,以便用户可以专注于满足他们的业务需求。
ServiceComb 如何支持zipkin
ServiceComb 提供了处理链机制,通过扩展handler处理链接口,已经实现负载均衡、熔断容错、流量控制等能力。同样,实现调用链追踪能力,也可以通过扩展处理链接口实现调用链追踪处理链。了解ServiceComb处理链参考 https://docs.servicecomb.io/java-chassis/zh_CN/references-handlers/intruduction.html
ServiceComb 扩展handler处理链接口,编写了handler-tracing-zipkin 模块,用于支持追踪基于ServiceComb java chassis 的微服务。Handler-tracing-zipkin 模块在java-chassis/handler处理链下,模块内容如下。那么handler-tracing-zipkin 模块究竟做了什么去支持zipkin调用链追踪?
事实上,zipkin服务端提供了数据收集、存储、API查询检索、Web UI等服务,我们只需要向zipkin服务上传调用链追踪数据,即可在zipkin提供的Web页面查看服务调用链追踪信息。如此一来,我们只需要使用zipkin的brave组件跟踪服务调用链并记录追踪数据,再使用reporter组件上传追踪数据到zipkin服务即可。
按照这个思路,ServiceComb只需要在后台启动zipkin服务,使用上面的Handler-tracing-zipkin模块实现追踪调用链记录数据和上传追踪数据到zipkin服务,即可支持zipkin调用链追踪。
ServiceComb项目如何使用zipkin实施调用链追踪,参考Distributed Tracing with ServiceComb and Zipkin2
ServiceComb 的 handler-tracing-zipkin模块源码解读
上面提到我们只需要追踪调用链、记录数据、上传追踪数据到zipkin服务即可支持zipkin调用链追踪。下面我们从编码角度,去介绍如何具体实现它。
追踪调用链首先需要在程序中初始化配置zipkin追踪组件(zipkin提供了一系列用于调用链柱子的组件),然后适配追踪组件到调用链请求上(zipkin在调用链请求和追踪组件之间提供了一系列适配接口和类)。调用链追踪组件设置完毕,我们只需要定义好一系列追踪方法和调用这些方法即可。上面的过程可以归结为以下4步:
- 初始化配置追踪组件
- 适配分布式调用链
- 追踪分布式调用链,记录并发送追踪数据到zipkin
- 调用上述追踪方法,追踪调用链,并记录日志
按照上面4步,我们实现了handler-tracing-zipkin 模块。但由于消费端和服务端对于调用链请求的适配追踪处理方法不同,handler-tracing-zipkin 模块分别实现了消费端和服务端追踪。下面我们从handler-tracing-zipkin 模块UML类图,去解读模块内类关系结构。
从handler-tracing-zipkin模块UML类图可以看到:
- TracingConfiguration类:初始化配置追踪组件,供调用链追踪使用。
- ConsumerInvocationAdapter 和ProviderInvocationAdapter 调用链适配类:分别继承了zipkin提供的消费端和服务端调用链适配器接口,分别支持消费端和服务端适配调用链。
- ZipkinConsumerDelegate 和 ZipkinProviderDelegate 类:实现了ZipkinTracingDelegate接口,分别依赖ConsumerInvocationAdapter 和ProviderInvocationAdapter 调用链适配类,定义了消费端和服务端调用链追踪方法。
- ZipkinTracingHandler 类:实现了handler处理链接口,调用成员变量ZipkinTracingDelegate 定义的方法,追踪调用链,并记录日志。
- ZipkinConsumerTracingHandler 类 和 ZipkinProviderInvocationAdapter 类继承了ZipkinTracingHandler调用链处理类,为消费端调用链追踪入口和服务端调用链追踪入口,如下,在cse.handler.xml中分别对应handler-id为"tracing-consumer"和"tracing-provider",handler-id为handler处理链名字,帮助应用配置调用链追踪处理链,如何配置可参考(http://servicecomb.apache.org/docs/tracing-with-servicecomb/)2。
<config> <handler id="tracing-consumer" class="org.apache.servicecomb.tracing.zipkin.ZipkinConsumerTracingHandler"/> <handler id="tracing-provider" class="org.apache.servicecomb.tracing.zipkin.ZipkinProviderTracingHandler"/> </config>
下面按照分布式调用链追踪步骤,深入代码解读handler-tracing-zipkin模块内类
-
初始化配置追踪组件:TracingConfiguration 类
class TracingConfiguration { private String apiVersion = CONFIG_TRACING_COLLECTOR_API_V2; //定义sender方法 @Bean Sender sender(DynamicProperties dynamicProperties) { apiVersion = dynamicProperties.getStringProperty(CONFIG_TRACING_COLLECTOR_API_VERSION, CONFIG_TRACING_COLLECTOR_API_V2).toLowerCase(); // use default value if the user set value is invalid if (apiVersion.compareTo(CONFIG_TRACING_COLLECTOR_API_V1) != 0) { apiVersion = CONFIG_TRACING_COLLECTOR_API_V2; } String path = MessageFormat.format(CONFIG_TRACING_COLLECTOR_PATH, apiVersion); return OkHttpSender.create( dynamicProperties.getStringProperty( CONFIG_TRACING_COLLECTOR_ADDRESS, DEFAULT_TRACING_COLLECTOR_ADDRESS) .trim() .replaceAll("/+$", "") .concat(path)); } //初始化reporter组件 @Bean Reporter<Span> zipkinReporter(Sender sender) { if (apiVersion.compareTo(CONFIG_TRACING_COLLECTOR_API_V1) == 0) { return AsyncReporter.builder(sender).build(SpanBytesEncoder.JSON_V1); } return AsyncReporter.builder(sender).build(); } //初始化tracing追踪组件 @Bean Tracing tracing(Reporter<Span> reporter, DynamicProperties dynamicProperties, CurrentTraceContext currentTraceContext) { return Tracing.newBuilder() .localServiceName(dynamicProperties.getStringProperty(CONFIG_QUALIFIED_MICROSERVICE_NAME_KEY, DEFAULT_MICROSERVICE_NAME)) .currentTraceContext(currentTraceContext) // puts trace IDs into logs .