说一说分布式系统的链路追踪(上)

2,824 阅读24分钟

说明:本文翻译自OpenTrace官方文档,并由个人理解后,整理出来的。如有疑惑的地方,可查询官方开发手册,或者留言

官方文档地址

1. 概述

微服务提供了强大的架构,但是在调试和观察复杂网络中的分布式事务方面,因为没有内存中的调用或堆栈跟踪变的比较困难,这就是分布式跟踪出现的原因。 分布式跟踪为描述和分析跨进程事务提供了一种解决方案。 如Google的Dapper论文所述,分布式跟踪的一些使用案例包括异常检测,诊断稳态问题,分布式分析,资源归因和微服务工作负载建模。

分布式跟踪: 大多数用于跟踪的思维模型都来自Google的Dapper论文。OpenTracing使用类似的名词和动词。

  • 1.Trace:事务在分布式系统中移动时的描述。

  • 2.Span:命名的定时操作,代表工作流的一部分。 Spans接受key:value标记以及附加到特定span实例的细粒度、带有时间戳的结构化日志。

  • 3.SpanContext:伴随分布式事务的Trace信息, 包括什么时候通过网络或者消息总线从一个服务到另一个服务。span context山下文包含trace标识符,span标识符,以及跟踪系统需要传播到下游服务的其他数据。

四大块:从应用程序层的角度来看分布式跟踪系统,如下图所示: 现代软件系统中的组件可以分为三类:

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

这三个组件具有不同的要求,并驱动着分布式跟踪系统的设计。最终的设计有四个重要方面:

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

OpenTracing如何适应这一需求?

OpenTracing API提供了标准的,与供应商无关的工具框架。这意味着,如果开发人员想要尝试使用其他分布式跟踪系统,那么开发人员可以简单地更改Tracer的配置,而不必为新的分布式跟踪系统重复整个检测过程。

1.什么是分布式链路追踪

分布式追踪,也被称为分布式请求追踪,是一种用于分析和监视应用程序的方法,特别是那些使用微服务架构构建的。分布式跟踪有助于查明发生故障的位置以及导致性能下降的原因。

2.谁应该使用分布式跟踪

IT和DevOps团队可以使用分布式跟踪来监视应用程序。分布式跟踪特别适合于调试和监视现代分布式软件体系结构,比如微服务。 开发人员可以使用分布式跟踪来帮助调试和优化他们的代码。

3.什么是OpenTracing

OpenTracing不是什么开始可能更容易。

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

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

4.概念和术语

所有特定语言的OpenTracing API都共享一些核心概念和术语。这些概念对于项目非常重要,非常重要,因此拥有自己的存储库specification

  • 1.OpenTracing语义规范是当前泛语言OpenTracing标准的版本说明
  • 2.语义约定规范描述了常见语义场景的常规Span标签和日志键

根据版本控制策略描述的规则,对两个文件进行版本控制,并对GitHub存储库进行标记。

5.Span

span是分布式跟踪主要的构建块,代表分布式系统中一个独立的工作单元。 分布式系统中每个组件都有一个span. span可以(通常也是这样的)包含对其他span的引用,允许将多个span组合成一个完整的跟踪链路--可视化一个请求在整个分布式系统中的生命周期。

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

  • 操作名称
  • 开始时间戳和结束时间戳
  • 一组键值对 span标签
  • 一组键值对 span日志
  • SpanContext

span 标签 标签是key:value对,可使用 用户定义的span注释,以查询,过滤和理解跟踪数据。

span标签应应用于整个span. semantic_conventions.md上有一个列表,列出了常见场景的常规span标签。示例中常见的标签比如 db.instance指明数据库的主机, http.status_code 标识http返回状态码, 或error,如果由跨度表示的操作失败,则可以将其设置为true

span 日志

日志是关键:值对 对于捕获特定于span的日志消息和应用程序本身的其他调试或信息输出非常有用。 日志对于记录span内的特定时刻或事件可能很有用 (与span标签应该应用于整个span相反).

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

  • 一种与实现相关的状态,用于引用trace中不同的span,例如,spanID和traceID
  • 任何Baggage项目,这个项目都是键值对,跨边界传输,在附带可以跨越整个trace中使用的数据时会非常有用。

下面是一个Span示例

    t=0            operation name: db_query               t=x

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

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

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"

6.作用域和线程

在任何给定线程中,都有一个“活跃的”span,主要负责由周围的应用程序代码完成的工作,称为ActiveSpan。OpenTracing API仅允许线程中的一个span在任何时间点处于活动状态。这是使用Scope进行管理的,该Scope将Span的激活和停用形式化。

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

  • 启动
  • 没有结束
  • 不活跃

例如,在同一个线程中可以有很多个span,如果span是一下几种

  • 等待I/O
  • 在子Span中阻塞
  • Off关键路径

因为手动将活跃span从一个函数传递到另一个函数很不方便,所以OpenTracing需要每个Tracer包含一个ScopeManager.ScopeManager API授权访问活跃的Span通过一个Scope.这意味着开发者可以访问任何 活跃的span.

使用ScopeManager API,开发者可以在不同的线程中传输span.一个span的生命周期可以开始于一个线程而结束语另一个线程。ScopeManager API允许一个Span被传输到其他线程或者回调。但是将scope传入到其他的线程和回调是不被允许的。获取更多详细信息,查询特定语言的文档。

7.Tracers

OpenTracing提供了一个开放的、独立于供应商的标准API来描述分布式事务,特别是因果关系,语义和时间。它提供了一个通用的分布式上下文传播框架,该框架包含用于

  • 在过程中传递元数据上下文
  • 对元数据上下文进行编码和解码,以便通过网络进行进程间通信
  • 因果关系跟踪: parent-child, forks, joins

OpenTracing消除了众多跟踪器实现之间的差异。这意味着无论开发人员使用哪种跟踪器。为了使用OpenTracing规范对应用程序进行检测,必须部署兼容的OpenTracing跟踪器。系统,工具都将保持不变。为了使用OpenTracing规范对应用程序进行检测,必须部署兼容的OpenTracing跟踪器。所有受支持的跟踪器的列表在此处提供提供的OpenTracing规范支持的tracer

Tracer 接口

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

  • 开启一个新的Span
  • 注入一个SpanContext到一个carrier载体
  • 从一个carrier载体中提取SpanContext

这些将在下面更详细地讨论。

设置追踪器

Tracer 是实际的实现,它将记录Span并将其发布到某个地方。应用程序如何处理实际的Tracer取决于开发人员:要么在整个应用程序中直接使用它,要么将它存储在GlobalTracer中,以便在插装框架中更容易使用。

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

  • 此应用程序的tracer的组件名称。
  • tracing 端点
  • tracing 凭证
  • 抽样策略。

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

为了不强迫用户随身携带Tracer,io.opentracing.util工件包括一个实现io.opentracing.Tracer接口的助手GlobalTracer类,顾名思义,该接口充当全局实例。 可以在任何地方使用。 它通过将所有操作转发到另一个基础的Tracer进行工作,该操作将在将来的某个时间注册。默认情况下,基础Tracer是no-nop实现。

开启一个新的Trace

每当创建新Span而不引用父Span时,就会开始新的Trace。创建新的Span时,您需要指定一个“操作名称”,这是一个自由格式的字符串,可用于帮助您确定此Span所涉及的代码。 我们新Tracer中的下一个Span可能是子Span,可以看作是在主Span内执行的子例程的表示。这个子Span因此与父Span是ChildOf关系。 另外一个关系是FollowsFrom,该关系用于新Span和父Span没有依赖关系的使用使用。比如在异步进程中。

访问活跃的span

Tracer可以用于访问ActiveSpan,在一些语言中,ActiveSpan可通过ScopeManager来访问

使用注入和提取来传播一个trace

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

Tracing 系统

下面的表格,列出了现有已知支持OpenTracing的跟踪器:

Tracing systemSupported languages
CNCF JaegerJava, Go, Python, Node.js, C++, C#
DatadogGo
inspectITJava
InstanaCrystal, Go, Java, Node.js, Python, Ruby
LightStepGo, Python, JavaScript, Objective-C, Java, PHP, Ruby, C++
stagemonitorJava

8.Inject and extract

添加跨进程边界跟踪支持的开发人员必须理解opentrace规范的trace.inject(…)和trace.extract(…)功能。

它们在概念上是强大的,允许程序员编写正确的和通用的跨进程传播代码,而不局限于特定的OpenTracing实现;

也就是说,权力越大,混淆的机会就越大。下面的内容简要介绍了Inject和Extract的设计和正确使用,而不考虑特定的opentrace语言或opentrace实现。

显示trace传输的传播概况

关于分布式跟踪,最困难的是分布式部分。任何跟踪系统都需要一种方法来理解许多不同进程中的活动之间的因果关系, 无论它们是通过正式的RPC框架、pub-sub系统、通用消息队列、直接HTTP调用、最佳效果UDP包或其他完全不同的方式连接的。

一些分布式跟踪系统(例如,2003年的Project5,或者2006年的WAP5,或者2014年的Mystery Machine)可以推断跨进程边界的因果关系。当然,在这些基于黑箱推理的方法的明显便利性和收集的痕迹的新鲜度和质量之间存在权衡。 基于对质量的关注,opentrace是一种明确的分布式跟踪工具标准,因此它与2007年的X-Trace、2010年的Dapper等方法或许多开源跟踪系统(如Zipkin或Jaeger等)更加一致。

注入和提取一起支持进程间跟踪传播,而不需要程序员与特定的OpenTracing实现紧密耦合。

OpenTracing传播模式的需求

要使Inject和Extract有用,以下所有条件都必须为真:

  • 根据上面的说明,处理跨进程跟踪传播的opentrace用户肯定不需要编写特定于opentrace实现的代码
  • OpenTracing实现肯定不需要为每个已知的进程间通信机制提供特殊的处理程序:那工作量太大了,而且它甚至没有被定义好
  • 也就是说,传播机制应该是可扩展的,以便进行优化

基本方法:注入、提取和载体

trace中的任何SpanContext都可以注入到OpenTracing所谓的载体(Carriers)中。载体是对进程间通信(IPC)有用的接口或数据结构。 也就是说,载体是将跟踪状态从一个进程传递到另一个进程的东西。OpenTracing规范包含了两种必须的载体形式:文本映射格式和二进制格式,尽管自定义载体格式也是可能的。

类似地,给定一个载体,注入的trace可以被提取,产生一个SpanContext实例,它在语义上与注入到载体中的是相同的一个。

例如注入的示例:

if err := opentracing.GlobalTracer().Inject(
			sp.Context(),
			opentracing.HTTPHeaders,
			opentracing.HTTPHeadersCarrier(r.Header)); err != nil {
			log.Println(err)
		}

提取的示例:

spanCtx, _ := opentracing.GlobalTracer().Extract(
	opentracing.HTTPHeaders, 
	opentracing.HTTPHeadersCarrier(r.Header))

载体格式:

所有的载体都有一个样式,在一些OpenTracing语言中,样式必须显示指定为常量或者字符串,在其他一些语言中,样式是从载体的静态类型信息推断出来的。

需要注入/提取载体格式:

所有平台都要求OpenTracing实现支持两种载体格式:一种为text map样式,一种为binary样式。

  • text map 载体样式是一个平台惯用map从string到string
  • binary 载体样式是一个不透明的字节数组(大概更紧凑,更高效)

OpenTracing实现选择在这些载体中存储什么并不是由OpenTracing规范正式定义的, 但假定它们找到了一种方法来对传播的SpanContext的tracer state以及任何k:v形式的Baggage Items进行编码

跨进程边界的OpenTracing实现的互操作性

不期望不同的OpenTracing实现以兼容的方式注入和提取SpanContexts。 尽管OpenTracing对于跨整个分布式系统的跟踪实现是不可知的,但为了成功地进行进程间切换,传播两边的进程都必须使用相同的跟踪实现。

自定义插入/提取载体格式

任何传播子系统(RPC库,消息队列等)都可以选择引入自己的自定义“注入/提取”载体格式。

通过首选自定义格式,但在需要时返回到所需的OpenTracing格式,它们允许OpenTracing实现优化自定义格式,而不需要OpenTracing实现来支持它们的格式。

载体格式的精确表示可能因平台而异,但在所有情况下,它们都应该从全局名称空间中提取。由于支持新的自定义载体格式,所以不需要更改核心的opentrace平台api

端到端注入和提取传播示例

为了使以上内容更具体,请考虑以下顺序:

  • 客户端进程有一个SpanContext实例,并将通过本地HTTP协议进行RPC。
  • 客户端进程调用Tracer.Inject(...),传入 active SpanContext实例,文本映射的格式标识符,和文本映射载体 作为 参数
  • Inject已在载体中填充文本映射;客户端应用程序编码映射到HTTP协议中(例如,作为头部信息)
  • HTTP请求发生,数据跨越进程边界
  • 现在在服务器进程中,应用程序代码从自己的HTTP协议中解码文本映射,并使用它初始化文本映射载体
  • 服务器进程调用`Trace.extract(…),传入所需的操作名称、文本映射的格式标识符和上面的载体
  • 没有数据损坏或其他错误.服务器现在有一个与客户端同属同样的Trace的SpanContext实例

9.OpenTracing 规范(Version: 1.1)

这是“正式的” OpenTracing语义规范。由于OpenTracing必须跨多种语言工作,因此本文档应避免使用特定于语言的概念。也就是说,所有语言都有一个“接口”的概念,它封装了一组相关的功能。

OpenTracing规范使用Major.Minor版本号,但没有.Patch组件。对规范进行向后不兼容的更改时,主要版本会递增。次要版本会增加不间断的更改,例如引入新的标准标记,日志字段或SpanContext引用类型。

大图:OpenTracing的范围

OpenTracing的核心规范(即本文档)有意不知道特定下游跟踪或监视系统的细节。这是因为OpenTracing的存在是为了描述分布式系统中事务的语义。对这些事务的描述不应受到任何特定后端处理的方式或表示数据方式的影响。例如,详细的OpenTracing工具可用于简单地测量延迟并在时间序列监视系统(例如Prometheus)中应用标签;或者可以将Span的开始+结束时间以及Span日志重定向到一个中央日志服务(例如 Kibana)

因此,OpenTracing规范和数据建模约定的范围比某些跟踪系统更广。如果对于特定的跟踪或监视系统,某些语义行为超出范围,则该系统可以汇总或简单地忽略来自OpenTracing工具的各个数据.

OpenTracing数据模型

OpenTracing中的跟踪是由它们的span隐式定义的。特别地,Trace可以被视为Spans的有向无环图(DAG),span之间的边称为引用。

例如,以下是由8个span组成的示例跟踪:

Causal relationships between Spans in a single 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)

有时,使用时间轴来可视化跟踪更容易,如下图所示:

Temporal relationships between Spans in a single Trace


––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–> time

 [Span A···················································]
   [Span B··············································]
      [Span D··········································]
    [Span C········································]
         [Span E·······]        [Span F··] [Span G··] [Span H··]

每个Span封装以下状态:

  • 操作名称
  • 开始时间
  • 结束时间
  • 一组零个或者多个key:value Span标签。键必须是字符串,值可以是字符串,bool值,或者数字类型。
  • 一组另个或者多个Span日志,每个元素本身又是一个键值对map和一个timestamp。键必须是一个字符串,值可以是任意类型,
  • 一个SpanContext
  • 零个或多个因果相关的Span的引用(通过那些相关Span的SpanContext)

每个SpanContext封装以下状态:

  • 任何依赖于opentrace实现的状态(例如,跟踪和span id)都需要引用跨进程边界的独立span
  • 跨过程边界的Baggage Items仅仅是一个键值对

Span之间的引用

Span可以引用零个或多个因果相关的其他SpanContext。OpenTracing当前定义了两种类型的引用: ChildOfFollowsFrom.这两种引用类型都专门为子Span和父Span之间的直接因果关系建模

将来,OpenTracing可能还会支持具有非因果关系的Span的引用类型(例如,成批排列在一起的Span,卡在同一队列中的Span等等)

ChildOf: 一个Span可以是父SpanChildOf.在ChildOf引用中,父Span某种程度上依赖于子Span。下面所有的构成ChildOf关系:

  • 代表RPC的服务器端的Span可以是代表该RPC客户端的SpanChildOf
  • 表示SQL插入的Span可以是代表ORM保存方法的SpanChildOf
  • 许多同时执行(也许是分布式的)工作的Span可能全部是单个父Span的Child,它合并了在截止期限内返回的所有孩子的结果

对于父元素的子元素,这些都可以是有效的计时图。

    [-Parent Span---------]
         [-Child Span----]

    [-Parent Span--------------]
         [-Child Span A----]
          [-Child Span B----]
        [-Child Span C----]
         [-Child Span D---------------]
         [-Child Span E----]

FollowsFrom:一些父Span完全不依赖于其子Span的结果.在这种情况下,我们说子Span在因果关系上 FollowsFromSpan.有许多不同的FollowsFrom子类别,在将来的OpenTracing版本中,它们可能会更正式地加以区分。

以下都是有效的FollowsFrom

    [-Parent Span-]  [-Child Span-]


    [-Parent Span--]
     [-Child Span-]


    [-Parent Span-]
                [-Child Span-]

OpenTracing API

OpenTracing规范中有三种关键的相互关联的类型: Tracer, Span, 和 SpanContext。下面,我们将介绍每种类型的行为,粗略地说,在典型的编程语言中,每种行为都成为一种“方法”,尽管由于类型重载等原因,它实际上可能是一组相关的同级方法。

当我们讨论“可选”参数时,可以理解,不同的语言有不同的方式来解释这些概念。例如,在Go中,我们可以使用“功能选项”惯用语,而在Java中,我们可以使用构建器模式。

Tracer

Tracer接口创建Span,并了解如何跨过程边界Inject(序列化)和Extract(反序列化)它们。形式上,它具有以下功能:

1.开始一个新的span

  • 操作名称,一个人类可读的字符串,简洁地表示Span完成的工作(例如,RPC方法名称,函数名称或较大计算中的子任务或阶段的名称)。操作名称应该是最通用的字符串,用于标识(统计上)有趣的Span实例类。即get_user要好于get_user/31459

例如:下面是一个潜在的操作名称对于获取假定的账号信息的Span

|--|--|

操作名指导
get太笼统
get_account/444太具体
get_account比较合适,并且account_id=444 可以作为一个Span 标签

可选参数

  • 零个或者多个和相关SpanContext的引用,尽可能包含ChildOf和FollowsFrom参考类型的简写。
  • 可选的显式开始时间戳记;如果省略,则默认使用当前的walltime
  • 零个或多个标签

返回已经启动(但尚未完成)的Span实例

2.将SpanContext注入载体

必要参数

  • 一个SpanContext实例
  • 一个format描述符(通常但不一定是字符串常量)告诉Tracer实现如何在载体参数中编码SpanContext
  • 一个carrier其类型由format决定。Tracer实现将根据format在此载体对象中对SpanContext进行编码。

3.从载体中提取SpanContext

必要参数

  • 一个format描述符(通常但不一定是字符串常量)告诉Tracer实现如何从载体参数中解码SpanContext
  • 一个carrier,其类型由format决定。 Tracer实现将根据format在此载体对象中对SpanContext进行解码。

当通过Tracer启动一个新的Span时返回一个SpanContext实例适用于引用。


注入和提取都依赖于一个可扩展格式参数,该参数规定了相关的“载体”的类型以及在该载体中如何编码SpanContext。所有Tracer实现都必须支持以下所有格式。
- 文本映射:任意字符串到字符串的映射,其中键和值的字符集不受限制
- HTTP标头:具有适用于HTTP标头(例如RFC 7230)的键和值的字符串到字符串的映射。在实践中,由于HTTP头的处理方式存在“多样性”,因此强烈建议Tracer实现使用有限的HTTP头key空间并保守地转义值。
- 二进制:表示SpanContext的(单个)任意二进制Blob

Span

除了检索Span的SpanContext的方法外,Span完成后,以下任何一项将不会再调用。

检索SpanSpanContext, 不应有参数,返回给定SpanSpanContext.返回值在Span结束之后,依然可以使用。

改写操作名称,必须提供的参数:新的操作名称,它取代了Span启动时传递的任何内容

Finish Span,可选参数,Span的一个现实的结束时间戳;如果省略,使用当前的时间,

设置Span标签,必须参数,tag键,必须是字符串,tag值必须是字符串,bool值或者数字类型的一种

记录结构化数据, 必须参数:一个或多个key:value对,其中的键必须是字符串,并且值可以是任何类型。一些OpenTracing实现可能比其他实现处理更多(或更多)某些日志值。 可选参数:明确的时间戳。 如果指定,它必须介于span的本地开始时间和结束时间之间。

顺便说一句:“日志记录”,以及它在OpenTracing中的含义 “日志记录”是我们行业中的重载术语; 可以合理地说,所有跟踪只是一种特别有组织的日志记录形式。OpenTracing的“日志”实际上只是key:value映射,用于描述Span上下文中的特定时刻。

虽然可以将通用过程级日志重定向到OpenTracing,但是这样做需要小心。例如,在跟踪系统中,没有锚定在特定事务或跟踪中的日志记录可能没有意义。就是说,在绝大多数传统日志记录语句已经涉及分布式事务的环境中,将数据记录到OpenTracing中是合理的,而且通常是有益的。

Span日志的粒度旨在比流程级日志记录框架中的典型“info”式日志记录更好。由于跟踪系统通常具有智能的,全有或全无的每次跟踪采样机制,单个跟踪中的详细程度可能高于整个流程所需要的详细程度,尤其是当该过程具有高并发性时。

设置baggage项

baggage项是k:v字符串对,应用于给定Span(它的SpanContext),以及直接或通过传递方式引用本地Span的所有Span。 即,baggage项与trace本身一起传播。

通过全栈OpenTracing集成,行李物品可实现强大的功能(例如,来自移动应用程序的任意应用程序数据可以透明地将其一直存储到存储系统的深处)随之而来的是一些强大的成本:请谨慎使用此功能。

请谨慎使用此功能。每个键和值都将复制到关联的Span的每个本地和远程子级中,这可能会增加大量网络和cpu开销。

必须参数:baggage键,字符串;baggage值,字符串

获取baggage项, 必须参数 baggage键,字符串 返回关联的baggage值或某种迹象表明缺少该值。

SpanContext

SpanContext与通用OpenTracing层的有用功能相比,它更像是一个“概念”。也就是说,这对于OpenTracing实现至关重要,并且确实提供了自己的瘦API。大多数OpenTracing用户在启动新的Span或向某些传输协议注入/从某些传输协议提取跟踪时,仅通过引用与SpanContext进行交互。

在OpenTracing中,我们强制SpanContext实例是不可变的,以避免围绕Span 结束和引用的复杂生命周期问题。

遍历所有baggage项,根据语言的不同,建模方式不同,但从语义上讲,调用方应该能够有效地遍历所有 baggage项在一个SpanContext实例中

NoopTracer

所有OpenTracing语言API也必须提供某种NoopTracer实现,该实现可用于标记控制OpenTracing或注入对测试无害的东西(等等)。在某些情况下(例如Java),NoopTracer可能位于其自己的打包工件中。

可选的API元素

某些语言还提供实用程序,以围绕单个进程传递活动的Span和/或SpanContext。例如,opentracing-go提供了帮助在使用go的context.Context上下文机制来设置和获取活跃的Span