- 工作原理
- 源码分析
术语(Terminology)
- Span:基本工作单元,例如,在一个新建的span中发送一个RPC等同于发送一个回应请求给RPC,span通过一个64位ID唯一标识,trace以另一个64位ID表示,span还有其他数据信息,比如摘要、时间戳事件、关键值注释(tags)、span的ID、以及进度ID(通常是IP地址),span在不断的启动和停止,同时记录了时间信息,当你创建了一个span,你必须在未来的某个时刻停止它。
- Trace:一系列spans组成的一个树状结构,例如,如果你正在跑一个分布式大数据工程,你可能需要创建一个trace。
- Annotation:用来及时记录一个事件的存在,一些核心annotations用来定义一个请求的开始和结束
- cs - Client Sent -客户端发起一个请求,这个annotion描述了这个span的开始
- sr - Server Received -服务端获得请求并准备开始处理它,如果将其sr减去cs时间戳便可得到网络延迟
- ss - Server Sent -注解表明请求处理的完成(当请求返回客户端),如果ss减去sr时间戳便可得到服务端需要的处理请求时间
- cr - Client Received -表明span的结束,客户端成功接收到服务端的回复,如果cr减去cs时间戳便可得到客户端从服务端获取回复的所有所需时间
将Span和Trace在一个系统中使用Zipkin注解的过程图形化:
每个颜色的注解表明一个span(总计7个spans,从A到G),如果在注解中有这样的信息:
Trace Id = X
Span Id = D
Client Sent
这就表明当前span将Trace-Id设置为X,将Span-Id设置为D,同时它还表明了ClientSent事件。
spans 的parent/child关系图形化
实现分析
- 服务本身对traceId的处理
Sleuth通过Filter的方式,在filter中对请求头的处理来实现traceId的追踪。
先判断http头中是否存在“X-B3-TraceId”,不存在,则生成新的traceId;存在,则以头X-B3-TraceId的值作为traceId。最后将X-B3-TraceId的值放到MDC中,以便日志输出中带上X-B3-TraceId。这样使得在本服务中,用户请求产生的日志输出都会带有traceId。
- 服务间对traceId的处理
在微服务中,服务A向服务B发起调用请求。那如何将A中的traceId传递给B呢?首先,先要了解服务A是如何调用服务B的。
1、网关接收到进行,进行请求转发
-
网关(gateway)TraceWebFilter
-
网关(zuul)ZuulFilter(TracePostZuulFilter)中将traceId添加到http头X-B3-TraceId中,以便所转发请求对应的服务能从头中获取到traceId。同时还将traceId放到MDC中,以便本应用在输出日志时带traceId。
2、服务内部通过feign注解调用另一个服务
由于feign注解的实现是通过生成Hystrix的代理类来完成请求的处理,而Hystrix在进行请求发送时是通过异步的方式调用ribbon的组件进行负载均衡,然后通过Feign.Client的execute方法来进行请求的发送。故此时需要解决以下两个问题:
(1)如何在异步线程中传递traceId。
Sluth是通过实现HystrixConcurrencyStrategy接口来解决traceId异步传递的问题。Hystrix在实际调用时,会调用HystrixConcurrencyStrategy的wrapCallable方法。因此,通过实现这个接口,在wrapCallable中将traceId存放起来(具体参见SleuthHystrixConcurrencyStrategy)。
(2)Feign如何在服务中传递traceId。
Sluth通过实现Feign.Client,在execute前将traceId存放到X-B3-TraceId头中来实现(具体参见TraceFeignClient)。
日志中字段说明
2019-05-20 13:56:14.921 DEBUG [user-client,fdf23ab0a44d64d9,fdf23ab0a44d64d9,true] 15208 --- [nio-8033-exec-8] o.s.web.servlet.DispatcherServlet : Completed 200 OK 2019-05-20 13:56:14.958 DEBUG [user-client,6b7be2e8ac041461,6b7be2e8ac041461,false] 15208 --- [io-8033-exec-10] o.s.web.servlet.DispatcherServlet : GET "/favicon.ico", parameters={}
注意MDC中的[appname,traceId,spanId,exportable]:
- spanId - the id of a specific operation that took place
- appname - the name of the application that logged the span
- traceId - the id of the latency graph that contains the span
- exportable - whether the log should be exported to Zipkin or not. Whenwould you like the span not to be exportable? In the case in which you want towrap some operation in a Span and have it written to the logs only. 是否应该将日志导出到Zipkin
Sleuth 支持可追踪的组件包含:
详细实现:
常见问题:
- Sleuth在异步线程中丢失traceId TraceableExecutorService 包装 ExecutorService http://www.saily.top/2018/12/29/sleuth-lost-traceId/
参考文档:
https://github.com/apache/incubator-zipkin-b3-propagation#sampling-state-1
https://blog.csdn.net/yaowwwww7071/article/details/85769505
https://blog.csdn.net/xichenguan/article/details/77448288
https://blog.csdn.net/u010257992/article/details/52474639