本文假设你已经阅读过Dapper文章:http://bigbully.github.io/Dapper-translation/,对分布式服务跟踪有了初步了解。另一篇zipkin的介绍文章(基础篇)可以参考:http://www.tangrui.net/implement-distributed-tracking-system-with-zipkin-and-brave/?utm_source=tuicool&utm_medium=referral
本文旨在介绍最新的Brave版本的使用,如何模拟出Dapper的调用链效果。
实现效果
定义有两个模块之间的调用,appserver服务调用datacenter服务。
其中由外部网络调用appserver的group_data接口,然后group_data再分别调用datacenter的get_radio_list、get_user_list、get_program_list三个接口。
代码
现在,为了模拟出这个调用层级,给大家理解brave的使用。给出了模拟的代码例子:
import java.util.ArrayList;import java.util.Collection;import java.util.Random;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;import com.github.kristofa.brave.Brave;import com.github.kristofa.brave.ClientRequestAdapter;import com.github.kristofa.brave.ClientRequestInterceptor;import com.github.kristofa.brave.ClientResponseAdapter;import com.github.kristofa.brave.ClientResponseInterceptor;import com.github.kristofa.brave.EmptySpanCollectorMetricsHandler;import com.github.kristofa.brave.KeyValueAnnotation;import com.github.kristofa.brave.ServerRequestAdapter;import com.github.kristofa.brave.ServerRequestInterceptor;import com.github.kristofa.brave.ServerResponseAdapter;import com.github.kristofa.brave.ServerResponseInterceptor;import com.github.kristofa.brave.SpanId;import com.github.kristofa.brave.TraceData;import com.github.kristofa.brave.http.HttpSpanCollector;import com.twitter.zipkin.gen.Endpoint;public class BraveTest { private static HttpSpanCollector collector = null; private static Brave brave = null; private static Brave brave2 = null; private static void braveInit(){ collector = HttpSpanCollector.create("http://localhost:9411/", new EmptySpanCollectorMetricsHandler()); brave = new Brave.Builder("appserver").spanCollector(collector).build(); brave2 = new Brave.Builder("datacenter").spanCollector(collector).build(); } static class Task { String name; SpanId spanId; public Task(String name, SpanId spanId) { super(); this.name = name; this.spanId = spanId; } } public static void main(String[] args) throws Exception { braveInit(); final BlockingQueuequeue = new ArrayBlockingQueue (10); Thread thread = new Thread(){ public void run() { while (true) { try { Task task = queue.take(); dcHandle(task.name, task.spanId); } catch (Exception e) { e.printStackTrace(); } } } }; thread.start(); { ServerRequestInterceptor serverRequestInterceptor = brave.serverRequestInterceptor(); ServerResponseInterceptor serverResponseInterceptor = brave.serverResponseInterceptor(); ClientRequestInterceptor clientRequestInterceptor = brave.clientRequestInterceptor(); ClientResponseInterceptor clientResponseInterceptor = brave.clientResponseInterceptor(); serverRequestInterceptor.handle(new ServerRequestAdapterImpl("group_data")); ClientRequestAdapterImpl clientRequestAdapterImpl = new ClientRequestAdapterImpl("get_radio_list"); clientRequestInterceptor.handle(clientRequestAdapterImpl); queue.offer(new Task("get_radio_list", clientRequestAdapterImpl.getSpanId())); Thread.sleep(10); clientResponseInterceptor.handle(new ClientResponseAdapterImpl()); clientRequestAdapterImpl = new ClientRequestAdapterImpl("get_user_list"); clientRequestInterceptor.handle(clientRequestAdapterImpl); queue.offer(new Task("get_user_list", clientRequestAdapterImpl.getSpanId())); Thread.sleep(10); clientResponseInterceptor.handle(new ClientResponseAdapterImpl()); clientRequestAdapterImpl = new ClientRequestAdapterImpl("get_program_list"); clientRequestInterceptor.handle(clientRequestAdapterImpl); queue.offer(new Task("get_program_list", clientRequestAdapterImpl.getSpanId())); Thread.sleep(10); clientResponseInterceptor.handle(new ClientResponseAdapterImpl()); serverResponseInterceptor.handle(new ServerResponseAdapterImpl()); } Thread.sleep(3000); } public static void dcHandle(String spanName, SpanId spanId){ ServerRequestInterceptor serverRequestInterceptor = brave2.serverRequestInterceptor(); ServerResponseInterceptor serverResponseInterceptor = brave2.serverResponseInterceptor(); serverRequestInterceptor.handle(new ServerRequestAdapterImpl(spanName, spanId)); serverResponseInterceptor.handle(new ServerResponseAdapterImpl()); } static class ServerRequestAdapterImpl implements ServerRequestAdapter { Random randomGenerator = new Random(); SpanId spanId; String spanName; ServerRequestAdapterImpl(String spanName){ this.spanName = spanName; long startId = randomGenerator.nextLong(); SpanId spanId = SpanId.builder().spanId(startId).traceId(startId).parentId(startId).build(); this.spanId = spanId; } ServerRequestAdapterImpl(String spanName, SpanId spanId){ this.spanName = spanName; this.spanId = spanId; } @Override public TraceData getTraceData() { if (this.spanId != null) { return TraceData.builder().spanId(this.spanId).build(); } long startId = randomGenerator.nextLong(); SpanId spanId = SpanId.builder().spanId(startId).traceId(startId).parentId(startId).build(); return TraceData.builder().spanId(spanId).build(); } @Override public String getSpanName() { return spanName; } @Override public Collection requestAnnotations() { Collection collection = new ArrayList (); KeyValueAnnotation kv = KeyValueAnnotation.create("radioid", "165646485468486364"); collection.add(kv); return collection; } } static class ServerResponseAdapterImpl implements ServerResponseAdapter { @Override public Collection responseAnnotations() { Collection collection = new ArrayList (); KeyValueAnnotation kv = KeyValueAnnotation.create("radioid", "165646485468486364"); collection.add(kv); return collection; } } static class ClientRequestAdapterImpl implements ClientRequestAdapter { String spanName; SpanId spanId; ClientRequestAdapterImpl(String spanName){ this.spanName = spanName; } public SpanId getSpanId() { return spanId; } @Override public String getSpanName() { return this.spanName; } @Override public void addSpanIdToRequest(SpanId spanId) { //记录传输到远程服务 System.out.println(spanId); if (spanId != null) { this.spanId = spanId; System.out.println(String.format("trace_id=%s, parent_id=%s, span_id=%s", spanId.traceId, spanId.parentId, spanId.spanId)); } } @Override public Collection requestAnnotations() { Collection collection = new ArrayList (); KeyValueAnnotation kv = KeyValueAnnotation.create("radioid", "165646485468486364"); collection.add(kv); return collection; } @Override public Endpoint serverAddress() { return null; } } static class ClientResponseAdapterImpl implements ClientResponseAdapter { @Override public Collection responseAnnotations() { Collection collection = new ArrayList (); KeyValueAnnotation kv = KeyValueAnnotation.create("radioname", "火星人1"); collection.add(kv); return collection; } }}
maven的依赖包:
io.zipkin.brave brave-spancollector-http 3.9.0
结果
把下载好的zipkin-server.jar包运行起来:java -jar zipkin-server.jar
然后运行上面测试代码后,用浏览器打开web UI:http://localhost:9411/
点击上面红色方框的记录
可以看到每个请求消耗的时间和调用顺序,点击第一个datacenter的调用记录,显示如下:
上面的弹窗框展示了一个调用从Client Send->Server Receive->Server Send->Client Receive的完整耗时。(Relative Time相对时间)