目录

  1. 概述
  2. 分布式追踪模型
  3. 四个方面
  4. 分布式追踪
    1. 使用者
    2. OpenTracing
  5. Span
    1. 介绍
    2. Tags
    3. Logs
    4. SpanContext
    5. 例子
  6. Scopes and Threading
    1. 介绍
    2. 访问当前Active Span
    3. 在线程之间移动Span
  7. Tracers
    1. 介绍
    2. Tracer Interface
    3. Setting up a Tracer
    4. Starting a new Trace
    5. Accessing the Active Span
    6. Propagating a Trace with Inject/Extract
    7. Tracing Systems

概述

微服务提供了强大的架构,但并非没有挑战,尤其是在调试和观察复杂网络中的分布式事务方面–仅仅是因为没有内存中的调用或堆栈追踪可以这样做。

这就是为什么会出现分布式追踪。分布式追踪为描述和分析跨进程事务提供了一种解决方案。分布式追踪的一些使用案例包括异常检测,诊断状态问题,分布式分析,资源归因和微服务工作负载建模。

分布式追踪模型



1. Trace(追踪):事务在分布式系统中移动时的描述。 2. Span(跨度):一种命名的定时操作,代表一部分工作流程。Span接受key:value标记以及附加到特定Span实例的细粒度,带时间戳的结构化日志。 3. Span context(跨度上下文):追踪伴随分布式事务的信息,包括它何时通过网络或通过消息总线将服务传递给服务。范围上下文包含追踪标识符,范围标识符以及追踪系统需要传播到下游服务的任何其他数据。

四个方面

从应用程序层分布式追踪系统的角度来看,现代软件系统如下图所示:

现代软件系统中的组件可以分为三类:

  • 应用程序和业务逻辑:您的代码。
  • 广泛共享的库:其他人的代码。
  • 广泛共享的服务:其他人的基础架构。

这三个组件具有不同的要求,并驱动着负责监视应用程序的分布式追踪系统的设计。最终的设计产生四个重要方面:

  • 追踪工具API:装饰应用程序代码的内容。
  • 有线协议:在RPC请求中与应用程序数据一起发送的内容。
  • 数据协议:异步(带外)发送到您的分析系统的内容。
  • 分析系统:用于处理追踪数据的数据库和交互式UI。

分布式追踪

分布式追踪(也称为分布式请求追踪)是一种用于对应用程序进行概要分析和监视的方法,尤其是使用微服务架构构建的应用程序。分布式追踪有助于查明哪里发生故障以及什么原因导致性能下降。

使用者

IT和DevOps团队可以使用分布式追踪来监视应用程序。分布式追踪特别适合调试和监视现代分布式软件体系结构,例如微服务。

开发人员可以使用分布式追踪来帮助调试和优化他们的代码。

OpenTracing

  • OpenTracing不是程序。分布式追踪要求软件开发人员将规范添加到应用程序的代码或应用程序中使用的框架。
  • OpenTracing不是标准。Cloud Native Computing Foundation(CNCF)不是官方标准机构。OpenTracing API项目正在努力为分布式追踪创建更多标准化的API和工具。

OpenTracing由API规范,已实现该规范的框架和库以及该项目的文档组成。OpenTracing允许开发人员使用不会将其锁定到任何一种特定产品或供应商的API来向其应用程序代码中添加工具。

Span

介绍

Span是分布式追踪的主要构建块,代表分布式系统中完成的单个工作单元。

分布式系统的每个组件都有一个Span–代表工作流一部分命名的定时操作。

Span可以包含对其他Span的引用,从而可以将多个Span组合成一个完整的追踪-可视化请求在分布式系统中移动时的生命周期。

每个Span根据OpenTracing规范封装以下状态:

  • 操作名称
  • 开始时间戳和结束时间戳
  • 一组key:value Span标签
  • 一组key:value Span日志
  • SpanContex

Tags

Tags(标签)是key:value键值对,可启用用户定义的Span注释,以查询、过滤和理解追踪数据。Span Tags应该应用于整个跨度。在semantic_conventions.md上有一个列表,列出了常见场景的Span Tags。

Tags包括,例如db.instance来标识数据库主机;http.status_code代表HTTP响应代码;error,如果Span表示的操作失败,则可以将其设置为True。

Logs

Logs(日志)是key:value键值对,可用于捕获特定的Span的日志消息以及来自应用程序本身的其他调试或信息输出。Logs记录跨度内的特定时刻或事件(与应该应用于整个Span的Tags相反)。

SpanContext

SpanContext跨进程边界承载数据。具体来说,它具有两个主要组成部分:

  • 依赖于实现的状态来引用追踪中的不同范围,即实现Tracer对spanID和traceID的定义。
  • 一些Baggage Items
    • 这些是跨流程边界的key:value键值对。
    • 使某些数据可用于整个追踪访问。

例子

t=0            operation name: db_query               t=x

 +-----------------------------------------------------+
 | · · · · · · · · · ·    Span     · · · · · · · · · · |
 +-----------------------------------------------------+

Tags:
- db.instance:"jdbc:mysql://127.0.0.1:3306/customers
- db.statement: "SELECT * FROM mytable WHERE foo='bar';"

Logs:
- message:"Can't connect to mysql server on '127.0.0.1'(10061)"

SpanContext:
- trace_id:"abc123"
- span_id:"xyz789"
- Baggage Items:
- special_id:"vsid1738"

Scopes and Threading

介绍

在任何给定线程中,都有一个“active”范围,主要负责由周围的应用程序代码(称为ActiveSpan)完成的工作。OpenTracing API允许线程中的一个Span在任何时间点都处于活动状态。这是使用Scope管理的,该范围正式确定了Span的启用和停用。

同一线程所涉及的其他Span将满足以下条件之一:

  • Started
  • Not finished
  • Not “active”

同一线程上可以有多个Span,Span需要满足以下条件:

  • Waiting for I/O
  • Blocked on a child Span
  • Off of the critical path

请注意,如果开发人员创建新的Span时存在Scope(作用域),则它将充当其父对象,除非程序员在buildSpan()时调用ignoreActiveSpan()或显式指定父上下文。

访问当前Active Span

由于在功能之间手动传递Active Span不方便,因此OpenTracing要求每个Tracer都包含一个ScopeManager。ScopeManager API通过Scope授予对Active Span的访问。这意味着开发人员可以通过Scope访问任何Active Span。

在线程之间移动Span

使用ScopeManager API,开发人员可以在不同线程之间传输Span。 Span的生命周期可能始于一个线程,而结束于另一个线程。ScopeManager API允许将Span传输到另一个线程或回调。不支持将Scope传递给另一个线程或回调。

Tracers

介绍

OpenTracing提供了一个开放的,与供应商无关的标准API,用于描述分布式事务,尤其是因果关系,语义和时间安排。它提供了一个通用的分布式上下文传播框架,该框架由以下API原语组成:

  • 在过程中传递元数据上下文
  • 编码和解码元数据上下文,以便通过网络传输它以进行进程间通信
  • 因果关系追踪:父子,分叉,联接

OpenTracing消除了众多追踪器实现之间的差异。这意味着无论开发人员使用哪种追踪系统,仪器显示都将保持不变。为了使用OpenTracing规范对应用程序进行检测,必须部署兼容的OpenTracing追踪器。

Tracer Interface

Tracer界面创建Span,并了解如何跨进程边界Inject注入(序列化)和Extract提取(反序列化)其元数据。它具有以下功能:

  • Start a new Span
  • Inject a SpanContext into a carrier
  • Extract a SpanContext from a carrier

Setting up a Tracer

Tracer将记录跨度并将其发布到某个地方。应用程序如何处理实际的Tracer取决于开发人员:直接在整个应用程序中使用它,还是将其存储在GlobalTracer中,以便更轻松地用于已检测框架。

不同的Tracer实现在初始化时接收方式和接收参数的方式有所不同,例如:

  • Component name for this application’s traces.
  • Tracing endpoint.
  • Tracing credentials.
  • Sampling strategy.

获取Tracer实例后,就可以使用它来手动创建Span,或将其传递给框架和库的现有工具。

为了不强迫用户始终围绕Tracer,io.opentracing.util实现包括io.opentracing.Tracer接口的帮助程序GlobalTracer类。顾名思义,GlobalTracer类,它是可以在任何地方使用的全局实例。它通过将所有操作转发到另一个基础的Tracer进行工作,该追踪器将在将来的某个时间进行注册。

默认情况下,基础Tracer是no-nop实现。

Starting a new Trace

每当创建新的Span而不引用父Span时,就会开始新的追踪。创建新的Span时,需要指定一个“操作名称”,它是一种自由格式的字符串,可用于帮助您识别该Span所涉及的代码。我们新追踪中的下一个Span可能是子Span,可以看作是在主Span内执行的子程序的表示。因此,此子Span与父级具有ChildOf关系。另一种关系类型是FollowsFrom,在特殊情况下使用,新的Span独立于父Span,例如在异步过程中。

Accessing the Active Span

追踪器可用于启用对ActiveSpan的访问。还可以通过scopeManager以某些语言访问ActiveSpans。

Propagating a Trace with Inject/Extract

为了跨分布式系统中的进程边界进行追踪,服务需要能够继续由发送每个请求的客户端注入的trace。OpenTracing通过提供注入和提取方法来实现此目标,该方法将Span的上下文编码为载体。Inject方法允许将SpanContext传递给载体。例如,将追踪信息传递到客户的请求中,以便您将其发送到的服务器可以继续追踪。Extract方法完全相反,它从载体中提取SpanContext。例如,如果客户端存在活动请求,则开发人员必须使用io.opentracing.Tracer.extract方法提取SpanContext。

Tracing Systems

下表列出了所有当前已知的OpenTracing追踪器:

Tracing System Supported Languages
CNCF Jaeger Java, Go, Python, Node.js, C++, C#
Datadog Go
inspectIT Java
Instana Crystal, Go, Java, Node.js, Python, Ruby
LightStep Go, Python, JavaScript, Objective-C, Java, PHP, Ruby, C++
stagemonitor Java