分布式链路追踪

2020/03/01 APM OpenTracing

分布式链路追踪

随着业务系统的不断发展、微服务架构的演进,从原来的单体应用架构、垂直应用架构、分布式 SOA 架构到现在的微服务架构,系统逐步走向微服务化以适应用户高并发请求等需求。在微服务架构中,一个业务操作往往需要多个服务间协同操作,而在一个复杂的系统中出现问题的时候,需要我们能够快速的分析并定位到问题的原因,这就需要我们对业务进行一次还原,正是分布式链路追踪需要解决的问题。

链路追踪介绍

对于一个大型的几十个,几百个微服务构成的微服务架构系统,通常会遇到下面的一系列问题。

  • 如何串联整个调用链路,快速定位问题?
  • 如何澄清各个微服务之间的依赖关系?
  • 如何进行各个微服务接口的性能分析?
  • 如何追踪各个业务流程的调用处理顺序? 分布式链路追踪就是将一次分布式请求还原成调用链路,将一次分布式请求的调用情况集中展示,比如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等。 分布式链路跟踪主要功能:
  • 故障快速定位 :可以通过调用链结合业务日志快速定位错误信息,包括请求时间、响应的状态、节点名称等信息,用于到达故障定位的能力;
  • 链路性能可视化 :各个阶段链路耗时、服务依赖关系通过可视化界面展现出来;
  • 链路分析 :通过分析链路耗时、服务依赖关系可以得到用户的行为路径,汇总分析应用在很多业务场景。

分布式链路追踪的基本原理

APM背景

APM (Application Performance Management) 即应用性能管理系统,是对企业系统即时监控以实现对应用程序性能管理和故障管理的系统化的解决方案。 应用性能管理,主要指对企业的关键业务应用进行监测、优化,提高企业应用的可靠性和质量,保证用户得到良好的服务,降低IT总拥有成本。 随着微服务、云计算的发展,提升了应用的可用性、扩展性,同时也带来了运维、监控的复杂性,当我们需要从众多服务依赖中,查询出问题根源也越来越难。

系统的监控分为三个维度:

  • Metrics 指标性统计 一个服务的正确率、成功率、流量、TPS、响应时间等。
  • Tracing 分布式追踪 从请求开始到结束,服务节点之间的调用链路。
  • Logging 日志记录 程序在执行的过程中间发生了一些日志,会一帧一帧地跳出来给大家去记录这个东西,这是日志记录。

Dapper 模型

链路追踪系统最早是由Goggle公开发布的一篇论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,这篇论文讲述了 Dapper 链路追踪系统的基本原理和关键技术点,通过一个分布式全局唯一的 id(即traceId),将分布在各个服务节点上的同一次请求串联起来,还原调用关系、追踪系统问题、分析调用数据、统计系统指标。

例如一条完整的链路是:user -> 服务A -> 服务B -> 服务C -> 服务D -> 服务E -> 服务C -> 服务A -> user,服务之间经过的每一条链路构成了一条完整的链路,并且每一条局部的链路都可以用唯一的 trace id标识。

通过唯一的 trace id无法知道先是调用了服务A还是先调用了服务B,因此为了去表达这种父子关系引入了 span 的概念,相同层的 parent id 相同,span id不同,并且 span id 由小到大来表示请求的顺序。除此之外,还可以记录其他的一些信息,比如发起服务的名称、IP、被调用服务的名称、返回结果、网络耗时等。

分布式调用链标准(OpenTracing)

OpenTracing最初是由Ben Sigelman在2016年发布的一篇论文“Distributed Tracing with OpenTracing”。该论文提出了分布式追踪的概念,并阐述了OpenTracing的设计目标、基本原则和实现方式。 论文指出,分布式追踪的核心挑战在于需要在多个服务之间建立上下文,并跨越多个异步和同步调用。OpenTracing通过使用上下文传递和操作ID来解决这个问题,并提供了一种可扩展的方式来生成和收集跟踪数据。

OpenTracing 是一个中立的分布式追踪的 API 规范,提供了统一接口方便开发者在自己的服务中集成一种或者多种分布式追踪的实现,使得开发人员能够方便的添加或更换追踪系统的实现。OpenTracing 可以解决不同的分布式追踪系统 API 不兼容的问题,各个分布式追踪系统都来实现这套接口。 OpenTracing 的数据模型,主要有以下三个:

  • Trace:可以理解为一个完整请求链路,也可以认为是由多个 span 组成的有向无环图(DAG);
  • Span:span 代表系统中具有开始时间和执行时长的逻辑运行单元,只要是一个完整生命周期的程序访问都可以认为是一个 span,比如一次数据库访问,一次方法的调用,一次 MQ 消息的发送等;每个 span 包含了操作名称、起始时间、结束时间、阶段标签集合(Span Tag)、阶段日志(Span Logs)、阶段上下文(SpanContext)、引用关系(Reference);
  • SpanContext: Trace 的全局上下文信息,span 的状态通过 SpanContext 跨越进程边界进行传递,比如包含 trace id,span id,Baggage Items(一个键值对集合)。

TraceId是这个请求的全局标识。内部的每一次调用就称为一个 Span,每个 Span 都要带上全局的 TraceId,这样才可把全局 TraceId 与每个调用关联起来。这个 TraceId 是通过 SpanContext 传输的,既然要传输,显然都要遵循协议来调用。如果我们把传输协议比作车,把 SpanContext 比作货,把 Span 比作路应该会更好理解一些。

设计方案

OpenTracing的设计方案包括以下几个核心组件:

  • Tracer:跟踪器是OpenTracing的核心组件,用于创建和管理跟踪span。它还提供了一组标准API,用于在应用程序中嵌入跟踪代码。
  • API: API是一组标准化的接口,用于跨语言和跨平台地记录和传递跟踪数据。
  • Span:Span是跟踪中的基本单位,用于描述操作的开始和结束。它可以包含事件、标签和日志,并可以与上下文关联。
  • Context:Context是OpenTracing中用于传递上下文信息的关键组件。它可以包含操作ID、Span和其他跟踪数据,用于跨越不同服务和调用之间的信息传递。Context通常需要与RPC系统和HTTP框架进行集成,以便在不同的服务之间传递跟踪信息。
  • Carrier:Carrier是OpenTracing中用于传递跟踪数据的载体。它可以是HTTP请求头、RPC参数、日志文件等等。通过使用标准化的Carrier格式,不同的跟踪系统可以互相兼容并集成。

在设计OpenTracing时,还考虑了可扩展性和可插拔性。跟踪器和跟踪系统可以根据需要进行定制和更改,而不会影响应用程序中的跟踪代码。

底层原理

在实现OpenTracing时,通常会使用两个核心组件:Tracer和Span。

Tracer

Tracer是OpenTracing中的核心组件之一,它充当了跟踪系统和应用程序之间的桥梁。Tracer主要负责管理和创建Span和Trace。Span是代表代码执行时间和相关上下文信息的对象,而Trace是包含所有Span的集合。Tracer可以通过将跟踪数据发送到跟踪系统进行存储和分析,以便开发人员能够更好地了解应用程序的行为和性能。

在OpenTracing中,Tracer对象是线程安全的,因此可以在多个线程中使用。通常,Tracer应该在应用程序中只有一个实例。创建Tracer实例时,通常需要提供一些配置选项,例如跟踪系统的地址、采样率等。

Span

Span是OpenTracing中的另一个核心组件,它代表了一段代码的执行时间和相关的上下文信息。Span通常被嵌套在Trace中,并且可以包含其他Span。

Span通常由以下几个部分组成:

  • SpanContext:包含Span的元数据,例如Span的唯一标识符、父Span的标识符等。
  • Operation Name:Span的名称,用于描述Span代表的操作。
  • Start Time:Span的开始时间,用于记录Span开始执行的时间。
  • End Time:Span的结束时间,用于记录Span执行结束的时间。
  • Tags:用于添加Span的标签,例如Span的名称、开始时间、结束时间等。
  • Logs:用于向Span中添加日志和事件信息,例如请求开始和结束的时间、传输的数据等。

在OpenTracing中,Span通常由以下几个操作组成:

  • StartSpan:用于开始一个新的Span,并返回一个Span对象。
  • SetTag:用于添加Span的标签。
  • Log:用于向Span中添加日志和事件信息。

使用Tracer和Span可以帮助开发人员更好地了解应用程序的行为和性能。Tracer可以帮助开发人员将应用程序的跟踪数据发送到跟踪系统进行存储和分析,而Span则可以用来描述整个请求的跟踪信息

下面的例子是一个Trace,里面有8个Span:

       [Span A]  ←←←(the root span)        
           |
    +------+------+   
    |             |
[Span B]      [Span C] ←←←(Span C 是    Span A 的孩子节点, ChildOf)   
    |            |
[Span D]     +---+-------+
             |           |
          [Span E]    [Span F] >>> [Span G] >>> [Span H]                    
                                        ↑
                                        ↑
                                        ↑
                        (Span G 在 Span F 后被调用, FollowsFrom)

一个Span可以和一个或者多个Span间存在因果关系。Open Tracing定义了两种关系:ChildOf和FollowsFrom。这两种引用类型代表了子节点和父节点间的直接因果关系。未来,OpenTracing将支持非因果关系的span引用关系。(例如:多个span被批量处理,span在同一个队列中,等等)

ChildOf 很好理解,就是父亲 Span 依赖另一个孩子 Span。比如函数调用,被调者是调用者的孩子,比如说 RPC 调用,服务端那边的Span,就是 ChildOf 客户端的。很多并发的调用,然后将结果聚合起来的操作,就构成了 ChildOf 关系。

如果父亲 Span 并不依赖于孩子 Span 的返回结果,这时可以说它他构成 FollowsFrom 关系。

在使用OpenTracing时,开发人员需要在代码中创建Span,并通过Tracer将Span与跟踪操作相关联。下面是一些使用OpenTracing的示例代码:

import opentracing  
# 创建一个新的Tracer对象
tracer = opentracing.Tracer()  
# 开始一个新的Spanwith 
tracer.start_active_span('my_operation') as scope:    span = scope.span    
# 在Span中添加一些标签    
span.set_tag('key', 'value')    
# 记录一些日志    
span.log_kv({'event': 'my_event', 'data': 'my_data'})    
# 执行一些操作    
do_something()    
# 结束Span    
scope.close()  

上面的代码使用Python的OpenTracing库创建了一个新的Tracer对象,并使用start_active_span方法开始一个新的Span。在Span中,开发人员可以添加标签、记录日志、执行操作等。当跟踪操作完成后,Span会被自动关闭并提交给Trace。

Log的概念

每个Span可以进行多次Logs操作,每一个Logs操作,都需要一个带时间戳的时间名称、以及可选的任意大小的存储结果。

Tags的概念

每个Span可以有多个键值对(key:value)形式的Tags,Tags是没有时间戳的,支持简单的对Span进行注解和补充。

目前基于OpenTracing理论的开源项目:

Jaeger

Jaeger是一个开源的分布式追踪系统,它支持OpenTracing规范,并提供了一个用于收集、存储和查询跟踪数据的平台。并支持多种语言和平台。Jaeger可以帮助用户了解服务之间的依赖关系,找到性能瓶颈,进行故障排除等。在Jaeger中,开发人员可以使用OpenTracing API创建Span,并将它们与Jaeger进行交互。

Jaeger的设计与OpenTracing的原则非常一致。Jaeger的架构包括以下组件:

  • Agent:运行在每个主机上的进程,用于接收Span数据并将其发送到Collector。
  • Collector:收集Agent发送的Span数据,并将其存储在数据库中。
  • Query:提供一个Web界面,用于查询和分析存储在数据库中的Span数据。
  • Storage:用于存储Span数据的后端存储,支持Cassandra、Elasticsearch和Memory三种存储方式。

Zipkin

Zipkin是Twitter开源的分布式跟踪系统,它也实现了OpenTracing规范,并支持多种语言和平台。Zipkin可以帮助用户追踪请求的路径,分析服务之间的依赖关系,以及找到性能瓶颈。

SkyWalking

SkyWalking是Apache基金会孵化的分布式APM系统,它也支持OpenTracing规范。SkyWalking可以帮助用户追踪分布式系统中的请求,分析服务之间的依赖关系,以及监控服务的性能指标。

参考资料

  • Dapper,大规模分布式系统的跟踪系统
  • opentracing文档中文版 ( 翻译 ) 吴晟
  • OpenTracing文档
  • OpenTracing语义标准
  • OpenTracing语义惯例
  • OpenTracing语义标准规范及实现

Search

    微信好友

    博士的沙漏

    Table of Contents