brave是zipkin官方提供的java版本zipkin-client實現java
<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>
提供httpCollector收集器mysql
基於http請求提供過濾器git
基於apache-http-client發起氣球提供攔截器github
@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; } }
post or get url : http://localhost/service1web
相關代碼請查看 zipkin簡單介紹及環境搭建(一)spring
流程圖 pointsql
針對請求,若是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
直接注入Brave便可 ps(不建議這樣作,代碼侵入。 zipkin不建議添加大量數據)springboot
@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); /* * 一、執行execute()的先後,會執行相應的攔截器(cs,cr) * 二、請求在被調用方執行的先後,也會執行相應的攔截器(sr,ss) */ return EntityUtils.toString(execute.getEntity(), "utf-8"); } }
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(); } }