一、链路追踪
微服务架构是将单个应用程序被划分成各种小而连接的服务,每一个服务完成一个单一的业务功能,相互之间保持独立和解耦,每个服务都可以独立演进。相对于传统的单体服务,微服务具有隔离性、技术异构性、可扩展性以及简化部署等优点。
同样的,微服务架构在带来诸多益处的同时,也为系统增加了不少复杂性。它作为一种分布式服务,通常部署于由不同的数据中心、不同的服务器组成的集群上。而且,同一个微服务系统可能是由不同的团队、不同的语言开发而成。通常一个应用由多个微服务组成,微服务之间的数据交互需要通过远过程调用的方式完成,所以在一个由众多微服务构成的系统中,请求需要在各服务之间流转,调用链路错综复杂,一旦出现问题,是很难进行问题定位和追查异常的。
链路追踪系统就是为解决上述问题而产生的,它用来追踪每一个请求的完整调用链路,记录从请求开始到请求结束期间调用的任务名称、耗时、标签数据以及日志信息,并通过可视化的界面进行分析和展示,来帮助技术人员准确地定位异常服务、发现性能瓶颈、梳理调用链路以及预估系统容量。
链路追踪系统的理论模型几乎都借鉴了 Google 的一篇论文”Dapper, a Large-Scale Distributed Systems Tracing Infrastructure”,典型产品有Uber jaeger、Twitter zipkin、淘宝鹰眼等。这些产品的实现方式虽然不尽相同,但核心步骤一般都有三个:数据采集、数据存储和查询展示。
链路追踪系统第一步,也是最基本的工作就是数据采集。在这个过程中,链路追踪系统需要侵入用户代码进行埋点,用于收集追踪数据。但是由于不同的链路追踪系统的API互不兼容,所以埋点代码写法各异,导致用户在切换不同链路追踪产品时需要做很大的改动。为了解决这类问题,于是诞生了OpenTracing规范,旨在统一链路追踪系统的API。
二、OpenTracing规范
OpenTracing 是一套分布式追踪协议,与平台和语言无关,具有统一的接口规范,方便接入不同的分布式追踪系统。
OpenTracing语义规范详见:https://github.com/opentracing/specification/blob/master/specification.md
2.1 数据模型(Data Model)
OpenTracing语义规范中定义的数据模型有 Trace、Sapn以及Reference。
2.1.1 Trace
Trace表示一条完整的追踪链路,例如:一个事务或者一个流程的执行过程。一个 Trace 是由一个或者多个 Span 组成的有向无环图(DAG)。
下图表示一个由8个Span组成的Trace:
[Span A] ←←←(the root span)
|
+------+------+
| |
[Span B] [Span C] ←←←(Span C is a `ChildOf` Span A)
| |
[Span D] +---+-------+
| |
[Span E] [Span F] >>> [Span G] >>> [Span H]
↑
↑
↑
(Span G `FollowsFrom` Span F)
按照时间轴方式更为直观地展现该Trace:
––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–> time
[Span A···················································]
[Span B··············································]
[Span D··········································]
[Span C········································]
[Span E·······] [Span F··] [Span G··] [Span H··]
2.1.2 Span
Span表示一个独立的工作单元,它是一条追踪链路的基本组成要素。例如:一次RPC调用、一次函数调用或者一次Http请求。
每个Span封装了如下状态:
-
操作名称
用于表示该Span的任务名称。 例如:一个 RPC方法名, 一个函数名,或者大型任务中的子任务名称。
-
开始时间戳
任务开始时间。
-
结束时间戳。
任务结束时间。通过Span的结束时间戳和开始时间戳,就能够计算出该Span的整体耗时。
-
一组Span标签
每一个Span标签是一个键值对。键必须是字符串,值可以是字符串、布尔或数值类型。常见标签键可参考:https://github.com/opentracing/specification/blob/master/semantic_conventions.md
-
一组Span日志
每一条Span日志由一个键值对和一个相应的时间戳组成。键必须是字符串,值可以是任何类型。常见日志键参考:https://github.com/opentracing/specification/blob/master/se