zipkin-java-brave源码分析(三)

什么是brave

brave是zipkin官方提供的java版本zipkin-client实现

brave提供的功能

基于brave3.9.0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<modules>
<module>brave-core</module>
<module>brave-benchmarks</module>
<module>brave-http</module>
<module>brave-core-spring</module>
<module>brave-resteasy-spring</module>
<module>brave-resteasy3-spring</module>
<module>brave-spancollector-http</module>
<module>brave-spancollector-scribe</module>
<module>brave-spancollector-kafka</module>
<module>brave-spancollector-local</module>
<module>brave-sampler-zookeeper</module>
<module>brave-jersey</module>
<module>brave-jersey2</module>
<module>brave-jaxrs2</module>
<module>brave-grpc</module>
<module>brave-apache-http-interceptors</module>
<module>brave-spring-web-servlet-interceptor</module>
<module>brave-spring-resttemplate-interceptors</module>
<module>brave-mysql</module>
<module>brave-web-servlet-filter</module>
<module>brave-okhttp</module>
</modules>

基于http提供brave源码分析

brave-spancollector-http

image
提供httpCollector收集器

brave-web-servlet-filter

image
基于http请求提供过滤器

brave-apache-http-interceptors

image
基于apache-http-client发起气球提供拦截器

基于springboot启动

step1配置

  • 针对collector的SpanCollector
  • 针对http请求的filter BraveServletFilter
  • 针对数据发送的Brave
  • 针对http-client请求的拦截器BraveHttpRequestInterceptor,BraveHttpResponseInterceptor
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    @Configuration
    public class ZipkinConfig {
    //span(一次请求信息或者一次链路调用)信息收集器
    @Bean
    public SpanCollector spanCollector() {
    Config config = HttpSpanCollector.Config.builder()
    .compressionEnabled(false)// 默认false,span在transport之前是否会被gzipped
    .connectTimeout(5000)
    .flushInterval(1)
    .readTimeout(6000)
    .build();
    return HttpSpanCollector.create("http://localhost:9411", config, new EmptySpanCollectorMetricsHandler());
    }
    //作为各调用链路,只需要负责将指定格式的数据发送给zipkin
    @Bean
    public Brave brave(SpanCollector spanCollector){
    Builder builder = new Builder("service1");//指定serviceName
    builder.spanCollector(spanCollector);
    builder.traceSampler(Sampler.create(1));//采集率
    return builder.build();
    }
    //设置server的(服务端收到请求和服务端完成处理,并将结果发送给客户端)过滤器
    @Bean
    public BraveServletFilter braveServletFilter(Brave brave) {
    BraveServletFilter filter = new BraveServletFilter(brave.serverRequestInterceptor(),
    brave.serverResponseInterceptor(), new DefaultSpanNameProvider());
    return filter;
    }
    //设置client的(发起请求和获取到服务端返回信息)拦截器
    @Bean
    public CloseableHttpClient okHttpClient(Brave brave){
    CloseableHttpClient httpclient = HttpClients.custom()
    .addInterceptorFirst(new BraveHttpRequestInterceptor(brave.clientRequestInterceptor(), new DefaultSpanNameProvider()))
    .addInterceptorFirst(new BraveHttpResponseInterceptor(brave.clientResponseInterceptor()))
    .build();
    return httpclient;
    }
    }

基于http发起请求服务端处理

post or get url : http://localhost/service1

相关代码请查看 zipkin简单介绍及环境搭建(一)

流程图
brave-http-collector-receive
point

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
针对请求,如果Sampledheader包含(X-B3-Sampled)会获取header中的ParentSpanId,TraceId,SpanId直接返回,否者会认为这是一个新的请求会构建Span
HttpServerRequestAdapter.getTraceData()
public TraceData getTraceData() {
final String sampled = serverRequest.getHttpHeaderValue(BraveHttpHeaders.Sampled.getName());
if (sampled != null) {
if (sampled.equals("0") || sampled.toLowerCase().equals("false")) {
return TraceData.builder().sample(false).build();
} else {
final String parentSpanId = serverRequest.getHttpHeaderValue(BraveHttpHeaders.ParentSpanId.getName());
final String traceId = serverRequest.getHttpHeaderValue(BraveHttpHeaders.TraceId.getName());
final String spanId = serverRequest.getHttpHeaderValue(BraveHttpHeaders.SpanId.getName());
if (traceId != null && spanId != null) {
SpanId span = getSpanId(traceId, spanId, parentSpanId);
return TraceData.builder().sample(true).spanId(span).build();
}
}
}
return TraceData.builder().build();
}
针对请求的采样
traceSampler().isSampled(newTraceId),没有使用zk情况下CountingSampler来决定
public synchronized boolean isSampled(long traceIdIgnored) {
boolean result = sampleDecisions.get(i++);
if (i == 100) i = 0;
return result;
}

基于apache-http发起请求

流程图
brave-http-client-send

如何在代码中添加自己的annotation or binaryAnnotation

直接注入Brave即可 ps(不建议这样做,代码侵入。 zipkin不建议添加大量数据)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@RestController
public class ZipkinBraveController {
@Autowired
private CloseableHttpClient httpClient;
@Autowired
private com.github.kristofa.brave.Brave brave;
@GetMapping("/service1")
public String myboot() throws Exception {
brave.serverTracer().submitBinaryAnnotation("状态", "成功");
Thread.sleep(100);//100ms
HttpGet get = new HttpGet("http://localhost:81/test");
CloseableHttpResponse execute = httpClient.execute(get);
/*
* 1、执行execute()的前后,会执行相应的拦截器(cs,cr)
* 2、请求在被调用方执行的前后,也会执行相应的拦截器(sr,ss)
*/
return EntityUtils.toString(execute.getEntity(), "utf-8");
}
}

ps

  • 如果collector要使用kafka直接切换spanController即可,需要server端进行对应配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    client端
    KafkaSpanCollector.create(KafkaSpanCollector.Config.builder().kafkaProperties(null).build(), new EmptySpanCollectorMetricsHandler());
    server端需要配置kafka配置
    final class KafkaZooKeeperSetCondition extends SpringBootCondition {
    static final String PROPERTY_NAME = "zipkin.collector.kafka.zookeeper";
    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata a) {
    String kafkaZookeeper = context.getEnvironment().getProperty(PROPERTY_NAME);
    return kafkaZookeeper == null || kafkaZookeeper.isEmpty() ?
    ConditionOutcome.noMatch(PROPERTY_NAME + " isn't set") :
    ConditionOutcome.match();
    }
    }

链接