zipkin之brave
brave是同步收集信息,及计算调用时间,但是异步发送日志信息给zipkin;所以很多时候你无法在第一时间获取日志数据可能需要等一会。另外在写一个demo的时候,因为最后睡了1秒,经常会发现丢了一些日志;后来最后sleep(5000)之后,日志都成功获取了。
brave在report发送了一个日志之后其实是放到了一个队列里面了;然后会有消费者线程从队列中取出数据,当数据达到一定程度(或者一段时间之后,这个是根据现象推测的)在批量告知zipkin 服务器。
servlet.isAsync是只有servlet3之后才会支持异步调用;
brave整体分为两部分来理解:
当前节点作为Client端(发送request请求),将会在RestTemplate埋下一个拦截器,这个拦截器将会记录下请求的往来的信息,包括时间间隔;调用完成后将会发送到zipkin服务器;但是想要是拦截器生效前提条件当前应用发送请求使用的是RestTemplate对象。
当前节点作为Server端(接收请求),将会在通过web的Filter(javax.servlet.Filter)来进行埋点;在Filter的doFilter调用中实现对servlet的service()的调用前后拦截处理;
TracingClientHttpRequestInterceptor
明白了client和server端,下面就是两者对应的处理,在RestTemplate埋点的对象是TracingClientHttpRequestInterceptor,这个interceptor核心方法是intercept,Interceptor和Filter处理机制类似,都是在在调用真谛函数(Interceptor的真谛函数就是execution.execute(request, body),执行请求,Filter的真谛函数就是servlet.service())前和后进行拦截处理;
真谛函数之前是调用handler的handler.handleSend,handleSend里面将会把Kind设置为Client,从request中获取span信息(通过span.customizer(),这个函数在handleReceive里面也会用到,主要就是从request以及response中获取信息,然后填充到tags节点中),最后调用span.start,来启动一个span;
真谛函数之后调用的是handler的handleReceive,通过span.customizer()来填充span的信息;最后调用span.finish来向zipkin server提交日志内容。
TracingFilter
是server角色埋的点,默认情况下第一个Filter是DelegatingTracingFilter,这个filter在init的时候就创建了TracingFilter(构造函数里面传的是HttpTracing),然后在doFilter的时候,调用TracingFilter的doFilter来进行拦截;TracingFilter里面也是有着HttpServerHandler,在doFilter里面在真谛函数前后的就是调用HttpServerHandler的handleReceive和handleSend两个函数。
handleReceive函数里面,首先设置Kind类型为Server,然后通过HttpServerParser来从request里面获取数据填充到span中;最后调用一下span.start来标记一个span的开始;
问题:nextSpan是否会把parent的span获取?
handleSend函数中,首先从response中获取相应的信息填充信息,最后调用span.finish向服务器提交一下span内容。
问题:client和server都会想zipkinServer提交log内容吗?
最后还有一个拦截器要交代一下,就是SpanCustomizingAsyncHandlerInterceptor,这个其实是一个server角色拦截器,
问题:这个SpanCustomizingAsyncHandlerInterceptor还需要深入了解一下,尤其里面提到的http.route我记得在别的地方还有用到。
坑
原来CrmTracingHttpClientBuilder是我复制的类,虽然改写了decorateProtocolExec函数里面返回类,但是CrmTracingHttpClientBuilder创建的create函数里面返回的builder还是TracingHttpClientBuilder,所以根本就没有走CrmTracingHttpClientBuilder里面的decorateProtocolExec。
这个问题和brave无关,是自己大脑短路。
servlet2.0怎么办?
我靠,发现maven版本里面打的servletapi是3.0,但是tomcat5确实低版本的servlet(2.4);导致某些方法无法使用!关键是maven里面竟然没有2.4,因为太古老了。是的maven里面没有该jar包。没办法只好从tomcat5中拷贝出来一款
开始是使用:强转方式,但是后来发现到了servlet3之后,这种强转是报错的;
int statusCode = ((brave.servlet.ServletRuntime.Servlet25ServerResponseAdapter)httpResponse).httpStatus;
还好后来找到了brave的超级强大的地方,自己判断平台。
int statusCode = brave.servlet.ServletRuntime.get().status(httpResponse);
搞掂了。
参考:
1.这强推墨竹的博客,对于zipkin的brave组价讲解十分透彻。
http://blog.mozhu.org/categories/zipkin/
2.brave的一个demo