基于zipkin和brave完成对dubbo的链路追踪
玩过springcloud的同学肯定知道zipkin这个链路追踪工具。他使用类似于下图的图表显示调用链每个节点所花费的时间,从而方便快捷的查找链路瓶颈。本文中的brave是zipkin的一个组件,用来给zipkin服务端提供数据。
此项目的github代码地址
此项目为brave添加了dubbo的监控能力,支持brave最新版,与instrumentation可以完美集成。
brave的github代码地址
一些基本概念
一个完整的链路包含以下四部分:
- Client Send(cs)
客户端发起请求 - Server Receive(sr)
服务端收到请求 - Server Send(ss)
服务端返回请求 - Client Receive(cr)
客户端收到请求结果
链路追踪工具通过在调用链中增加特定的标记来记录这四种状态从而计算出服务端和客户端所花费的时间。
标记包含以下三个概念
- traceId
一次请求全局只有一个traceId。用来在海量的请求中找到同一链路的几次请求。比如servlet服务器接收到用户请求,调用dubbo服务,然后将结果返回给用户,整条链路只有一个traceId。开始于用户请求,结束于用户收到结果。 - spanId
一个链路中每次请求都会有一个spanId。例如一次rpc,一次sql都会有一个单独的spanId从属于traceId。 -
parentId
上一次请求的spanId。用于将一条链路的多次请求串联起来。监控原理
brave主要是利用拦截器在请求前和请求后分别埋点。例如spingmvc监控使用Interceptors,mysql监控使用statementInterceptors。同理dubbo的监控是利用com.alibaba.dubbo.rpc.Filter来过滤生产者和消费者的请求。所以在项目中有一个com.alibaba.dubbo.rpc.Filter的文件,里面包含了
braveProviderFilter=brave.dubbo.DubboProviderFilter
braveConsumerFilter=brave.dubbo.DubboConsumerFilter
这样在两个过滤器中加入埋点就可以完成监控了。
如何使用
这里使用springboot来简化配置。
首先建立Properties用来接收参数。
@ConfigurationProperties(prefix = "trace.brave")
public class TraceProperties {
@Value("${spring.application.name}")
private String serviceName;
private String zipkin;
private float rate;
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getZipkin() {
return zipkin;
}
public void setZipkin(String zipkin) {
this.zipkin = zipkin;
}
public float getRate() {
return rate;
}
public void setRate(float rate) {
this.rate = rate;
}
}
serviceName使用项目名称。zipkin是zipkin服务端的url地址,rate是取样率,指的是多次请求中有百分之多少传到zipkin。例如1.0是全部取样,0.5是50%取样。
application.yml配置如下:
trace:
brave:
zipkin: http://127.0.0.1:9411/api/v2/spans
rate: 1.0
编写自动配置类
@Configuration
@EnableConfigurationProperties({TraceProperties.class})
@Import({TracingHandlerInterceptor.class})
public class TraceAutoConfiguration extends WebMvcConfigurerAdapter {
@Autowired
private TraceProperties traceProperties;
@Autowired
private TracingHandlerInterceptor tracingHandlerInterceptor;
@Bean
public Sender sender() {
return OkHttpSender.create(traceProperties.getZipkin());
}
@Bean
HttpTracing httpTracing(Tracing tracing) {
HttpTracing httpTracing=HttpTracing.create(tracing);
return httpTracing.toBuilder()
.serverParser(new HttpServerParser() {
@Override
public <Req> String spanName(HttpAdapter<Req, ?> adapter, Req req) {
return adapter.path(req);
}
}).clientParser(new HttpClientParser() {
@Override
public <Req> String spanName(HttpAdapter<Req, ?> adapter, Req req) {
return adapter.path(req);
}
}).build();
}
@Bean
public AsyncReporter<Span> spanReporter() {
return AsyncReporter.create(sender());
}
@Bean
public Tracing tracing(){
return Tracing.newBuilder()
.localServiceName(traceProperties.getServiceName())
.spanReporter(spanReporter())
.sampler(Sampler.create(traceProperties.getRate())).build();
}
@Bean
DubboTracing dubboTracing(Tracing tracing) {
return DubboTracing.create(tracing);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tracingHandlerInterceptor);
}
}
其中tracingHandlerInterceptor拦截器用来对springmvc请求埋点。httpTracing和dubboTracing分别是springmvc和dubbo埋点的配置。
pom加入以下三个包
发送zipkin的包
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-sender-okhttp3</artifactId>
<version>${zipkin-reporter.version}</version>
</dependency>
springmvc拦截
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-instrumentation-spring-webmvc</artifactId>
<version>${brave.version}</version>
</dependency>
dubbo拦截
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-instrumentation-dubbo</artifactId>
<version>${brave.version}</version>
</dependency>
分别使用最新版本就好。这里使用的是:
<brave.version>4.9.1</brave.version>
<zipkin-reporter.version>2.1.3</zipkin-reporter.version>
这里需要注意的是4.9.1的brave需要使用2.0以上的zipkin服务端
例如
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
<version>2.2.1</version>
</dependency>