Zipkin-1.19.0学习系列14: Brave-OkHttp机制分析

上一节,我们讲解了,brave-web-filter的运行原理,其实别的都不用看,直接拿到最后一张图就可以构造自己的brave-web-filter了。你懂的。

---这一节,我们需要完成一个任务,就是如果在tomcat里,发出了一个新的HTTP请求到后端,如何记住这个操作的信息,耗时等,并上报到zipkin server呢?

参考 :http://www.cnblogs.com/java-zhao/p/5838819.html

 

接下来就来解决这个问题。

---首先是技术选型,这里有很多client,我选择了Brave-OkHttp.

下载版本    3.16.0的brave_okhttp

http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.zipkin.brave%22%20AND%20a%3A%22brave-okhttp%22
然后测试代码如下:

@SuppressWarnings("deprecation")
	private void test() {
		// 构造spanCollector
		SpanCollector spanCollector = new LoggingSpanCollector();
		// HttpSpanCollector.Config spanConfig =
		// HttpSpanCollector.Config.builder().compressionEnabled(false)//
		// 默认false,span在transport之前是否会被gzipped。
		// .connectTimeout(5000)// 5s,默认10s
		// .flushInterval(1)// 1s
		// .readTimeout(6000)// 5s,默认60s
		// .build();
		// spanCollector= HttpSpanCollector.create("http://1.2.3.4:9411",
		// spanConfig, new EmptySpanCollectorMetricsHandler());
		// 构造Brave
		Brave.Builder builder = new Brave.Builder("service1");// 指定serviceName
		builder.spanCollector(spanCollector);
		builder.traceSampler(Sampler.create(1));// 采集率
		Brave brave = builder.build();
		// 假设这里有Http交互
		OkHttpClient client = new OkHttpClient.Builder()
				.addInterceptor(new BraveOkHttpRequestResponseInterceptor(brave.clientRequestInterceptor(),
						brave.clientResponseInterceptor(), new DefaultSpanNameProvider()))
				.build();
		Request request = new Request.Builder().url("http://www.163.com").build();
		Response response;
		try {
			response = client.newCall(request).execute();
			response.body().string();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

---接下来就开始debug了。

Step completed: "thread=http-nio-8080-exec-1", okhttp3.internal.http.RealInterceptorChain.proceed(), line=91 bci=183
91        Interceptor interceptor = interceptors.get(index);

http-nio-8080-exec-1[1] next
> 
Step completed: "thread=http-nio-8080-exec-1", okhttp3.internal.http.RealInterceptorChain.proceed(), line=92 bci=201
92        Response response = interceptor.intercept(next);

http-nio-8080-exec-1[1] print interceptor
 interceptor = "com.github.kristofa.brave.okhttp.BraveOkHttpRequestResponseInterceptor@f9725d"
http-nio-8080-exec-1[1] step
> 
Step completed: "thread=http-nio-8080-exec-1", com.github.kristofa.brave.okhttp.BraveOkHttpRequestResponseInterceptor.intercept(), line=69 bci=0
69        Request request = chain.request();

http-nio-8080-exec-1[1] 

所以,你只要在下面的断点处开始跟踪就好了

stop in com.github.kristofa.brave.okhttp.BraveOkHttpRequestResponseInterceptor.intercept

接下来会执行

requestInterceptor.handle(new HttpClientRequestAdapter(okHttpRequest, spanNameProvider));

表示开始记录执行之前的信息点了,看看做了哪些事情。

Step completed: "thread=http-nio-8080-exec-1", com.github.kristofa.brave.ClientTracer.getNewSpanId(), line=149 bci=0
149            Span parentSpan = spanAndEndpoint().state().getCurrentLocalSpan();

http-nio-8080-exec-1[1] next
> 
Step completed: "thread=http-nio-8080-exec-1", com.github.kristofa.brave.ClientTracer.getNewSpanId(), line=150 bci=13
150            if (parentSpan == null) {

http-nio-8080-exec-1[1] print parentSpan
 parentSpan = null
http-nio-8080-exec-1[1] next
> 
Step completed: "thread=http-nio-8080-exec-1", com.github.kristofa.brave.ClientTracer.getNewSpanId(), line=151 bci=17
151                ServerSpan serverSpan = spanAndEndpoint().state().getCurrentServerSpan();

http-nio-8080-exec-1[1] next
> 
Step completed: "thread=http-nio-8080-exec-1", com.github.kristofa.brave.ClientTracer.getNewSpanId(), line=152 bci=30
152                if (serverSpan != null) {

http-nio-8080-exec-1[1] print serverSpan
 serverSpan = "ServerSpan{span={"traceId":"88a037934ebddc71","id":"88a037934ebddc71","name":"get","timestamp":1484231320269000,"annotations":[{"timestamp":1484231320269000,"value":"sr","endpoint":{"serviceName":"myservicename","ipv4":"192.168.56.102"}}],"binaryAnnotations":[{"key":"http.url","value":"/myeyeweb/","endpoint":{"serviceName":"myservicename","ipv4":"192.168.56.102"}}]}, sample=true}"

首先取出parentSpan,如果不存在localSpan,就从serverSpan里取,这样才可以复用全局traceId.

PS:

一定要时刻记住这里有3个ThreadLocal变量

    private final static ThreadLocal<ServerSpan> currentServerSpan = new ThreadLocal<ServerSpan>() {

        @Override
        protected ServerSpan initialValue() {
            return ServerSpan.EMPTY;
        }
    };
    private final static ThreadLocal<Span> currentClientSpan = new ThreadLocal<Span>();

    private final static ThreadLocal<Span> currentLocalSpan = new ThreadLocal<Span>();

接着上面来说,取出parentSpan后,构造好本次的client span,然后放到client ThreadLocal里去,然后就开始需要把相关的参数反映到requet里进行传递

 @Override
    public void addSpanIdToRequest(@Nullable SpanId spanId) {
        if (spanId == null) {
            request.addHeader(BraveHttpHeaders.Sampled.getName(), "0");
        } else {
            request.addHeader(BraveHttpHeaders.Sampled.getName(), "1");
            request.addHeader(BraveHttpHeaders.TraceId.getName(), spanId.traceIdString());
            request.addHeader(BraveHttpHeaders.SpanId.getName(), IdConversion.convertToString(spanId.spanId));
            if (spanId.nullableParentId() != null) {
                request.addHeader(BraveHttpHeaders.ParentSpanId.getName(), IdConversion.convertToString(spanId.parentId));
            }
        }
    }

这样,下一个接收处理的才可以拿到全局的一些信息。

处理完request后,需要执行

 responseInterceptor.handle(new HttpClientResponseAdapter(new OkHttpResponse(response)));

最后,把当前 span 转化成字符串


  /** Changes this to a zipkin-native span object. */
  public zipkin.Span toZipkin() {
    zipkin.Span.Builder result = zipkin.Span.builder();
    result.traceId(getTrace_id());
    result.traceIdHigh(getTrace_id_high());
    result.id(getId());
    result.parentId(getParent_id());
    result.name(getName());
    result.timestamp(getTimestamp());
    result.duration(getDuration());
    result.debug(isDebug());
    for (Annotation a : getAnnotations()) {
      result.addAnnotation(zipkin.Annotation.create(a.timestamp, a.value, from(a.host)));
    }
    for (BinaryAnnotation a : getBinary_annotations()) {
      result.addBinaryAnnotation(zipkin.BinaryAnnotation.builder()
          .key(a.key)
          .value(a.value)
          .type(zipkin.BinaryAnnotation.Type.fromValue(a.type.getValue()))
          .endpoint(from(a.host))
          .build());
    }
    return result.build();
  }

下面结合一个场景,讲述完整的信息

浏览器--->Tomcat Server (内部触发http请求到163主页),记录下完整的信息如下:

INFO: 
{
"traceId":"46b7687dbc61fb03",
"id":"8f2cdd70e5ecd299",
"name":"get",
"parentId":"46b7687dbc61fb03",
"timestamp":1484238440149000,
"duration":199688,
"annotations":
[
{"timestamp":1484238440149000,"value":"cs","endpoint":{"serviceName":"service1","ipv4":"192.168.56.102"}},
{"timestamp":1484238440348688,"value":"cr","endpoint":{"serviceName":"service1","ipv4":"192.168.56.102"}}],
"binaryAnnotations":
[
{"key":"http.url","value":"http://www.163.com/","endpoint":{"serviceName":"service1","ipv4":"192.168.56.102"}}
]
}
Jan 13, 2017 12:27:21 AM com.github.kristofa.brave.LoggingReporter report


INFO: 
{
"traceId":"46b7687dbc61fb03",
"id":"46b7687dbc61fb03",
"name":"get",
"timestamp":1484238440117000,
"duration":948634,
"annotations":
[
{
timestamp":1484238440117000,
"value":"sr",
"endpoint":{"serviceName":"myservicename","ipv4":"192.168.56.102"}
},
{
"timestamp":1484238441065634,
"value":"ss",
"endpoint":{"serviceName":"myservicename","ipv4":"192.168.56.102"}
}
],
"binaryAnnotations":
[
{"key":"http.status_code","value":"200","endpoint":{"serviceName":"myservicename","ipv4":"192.168.56.102"}},
{"key":"http.url","value":"/myeyeweb/","endpoint":{"serviceName":"myservicename","ipv4":"192.168.56.102"}}
]
}
Jan 13, 2017 12:27:21 AM com.github.kristofa.brave.LoggingReporter report

可以看到,这2个有一个全局统一的global ID.

转载于:https://my.oschina.net/qiangzigege/blog/823352

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值