耐克公司的WingTips分布式跟踪系统

分布式跟踪是一种通过分布式网络跟踪请求的系统,这样能够在复杂的微服务系统中创建一种透明的调用路径,一条请求可能会经过成百上千个微服务调用环节,如同树形结构一样分散开来,如果没有分布式跟踪,很难确定某个微服务是否是整个路径上的性能瓶颈。

分布式跟踪提供了近乎实时的监控和历史分析,它提供必要工具收集和解释跟踪,能够让你方便看到应用花费的时间。

一个分布式跟踪系统由以下部分组成:
1.每个分布式跟踪包含一个TraceID,代表整个跨多个服务器或微服务的请求,这些TraceID会是唯一64位整数long型。
2.在分布式跟踪系统中每个单元被定义为Span,Span通常分为overall-request-time和downstream-call-time两种,前者是服务器/微服务的整个请求花费时间,后者是下游花费时间,Span由SpanID标识,也是一种64位long型。
3.Span能够有父Span,这样建立跨多个服务器/服务的基于请求行为的树形图,ParentSpanID是Span的SpanID的父节点。
4.所有Span包含有关整个跟踪的TreacID。
5.Span包含SpanName,这是供人工读取的标识,比如GET_/some/endpoint是REST请求的整个Span,或者downstream-POST_https://otherservice.com/other/endpoint是执行另外一个服务的下游调用Span。
6.Span包含计时信息,一个开始时间戳和花费时间值。


Wingtips是一个基于Java 7的分布式跟踪解决方案,有几个模块:
wingtips-core - 提供分布式跟踪功能的核心库
wingtips-servlet-api - 基于Sevlet应用的插件,能够在一个Servlet过滤器中集成分布式跟踪。
wingtips-zipkin - 一个易于集成Zipkin的插件。

下面是每个请求一个线程框架场景下的伪代码演示:


import com.nike.wingtips.Span;
import com.nike.wingtips.Tracer;

// ======As early in the request cycle as possible======
try {
// 检查请求比如请求头部决定父span是否存在
Span parentSpan = extractParentSpanFromRequest(request);

// 开始整个请求span (对于当前线程会成为"current span" ,除非或直至子Span sub-span被创建)
if (parentSpan == null)
Tracer.getInstance().startRequestWithRootSpan(
"newRequestSpanName");
else
Tracer.getInstance().startRequestWithChildSpan(parentSpan,
"newRequestSpanName");

// 推荐在响应头部包含整个请求的跟踪ID
addTraceIdToResponseHeaders(response, Tracer.getInstance().getCurrentSpan());

// 执行正常的请求逻辑
doRequestLogic();
}
finally {
// ======As late in the request/response cycle as possible======
Tracer.getInstance().completeRequestSpan();
// Completes the overall request span and logs it to SLF4J
}

如果基于非堵塞异步的 reactive场景,通过下面几个方法进行跟踪:
Tracer.registerWithThread(Deque)
Tracer.unregisterFromThread()
Tracer.getCurrentSpanStackCopy()

Nike-Inc/wingtips: WingTips is a distributed traci