[译] OpenTracing语义规范

OpenTracing语义规范(中文版)

版本 1.0html

原文

The OpenTracing Semantic Specificationgit

概述

这是一份”正式”的OpenTracing语义规范文档。因为OpenTracing是跨语言的,本文档会尽可能避免提到特定语言相关的概念。也就是说,咱们认为全部语言都具备相似”接口”这样的概念,并提供相关的功能。github

版本控制策略

OpenTracing采用了 主版本号.次版本号 形式的版本号,可是没有 .修订号 。当对规范进行向后不兼容的更改时,主版本增长。次版本的增长则用于用于不间断更改,如引入新的标准标记,日志字段或SpanContext引用类型。(你能够在这个Issue specification#2 中读到更多有关此版本控制方案的信息)编程

OpenTracing数据模型

OpenTracing中的Traces由其Span隐式定义。Trace可被认为是由一组Span定义的有向无环图(DAG),在Span之间的被称为References网络

如下是一个由8个Span构成的Trace的例子:并发

一个Trace中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 `FollowsFrom` Span F)

有时用时间轴来显示Traces更容易,以下图所示:编程语言

一个Trace中Span间的时间关系


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

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

每一个Span封装了以下状态:分布式

  • 操做名称函数

  • 开始时间戳工具

  • 结束时间戳

  • 一组零或多个键:值结构的Span标签(Tags)。键必须是字符串。值能够是字符串,布尔或数值类型.

  • 一组零或多个Span日志(Logs),其中每一个都是一个键:值映射并与一个时间戳配对。键必须是字符串,值能够是任何类型。 并不是全部的OpenTracing实现都必须支持每种值类型。

  • 一个SpanContext(见下文)

  • 零或多个因果相关的Span间的References (经过那些相关的SpanSpanContext)

每一个SpanContext封装了以下状态:

  • 任何须要跟跨进程Span关联的,依赖于OpenTracing实现的状态(例如Trace和Span的id)

  • 键:值结构的跨进程的Baggage Items

Span间的Reference

一个Span可引用零或多个因果相关的SpanContext。OpenTracing目前定义了两种类型的Reference: ChildOfFollowsFrom这两种Reference类型都对父子Span间的因果关系进行了建模。将来,OpenTracing可能会为不具因果关系的Span提供不一样类型的Reference (例如批量的Span,卡在队列中的Span等)。

ChildOf reference: 一个Span能够是另外一个Span的子Span。在 ChildOf 引用中,父Span在某种程度上取决于子Span。下列状况会构成 ChildOf 关系:

  • 在一个RPC中,表明服务端的Span可做为 ChildOf 表明客户端的Span

  • 在一个持久化进程中,表明SQL插入的Span可做为 ChildOf 表明ORM save方法的Span

  • 多个并发(多是分布式)执行任务的Span可能分别各自为 Childof 一个合并了多个子Span结果的父Span

下列这些都是有效的具备 ChildOf 关系的时序图

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

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

FollowsFrom reference: 有些父Span不依赖于任何子Span的结果。这种状况下,咱们仅认为子Span在因果上 FollowsFrom 父Span。有许多不一样的 FollowsFrom 引用子类别,在OpenTracing的将来版本中,它们可能会被更正式地区分。

下列这些都是有效的具备 FollowsFrom 关系的时序图

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


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


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

OpenTracing接口定义

OpenTracing规范中有三种相互关联的关键类型 TracerSpan ,and SpanContext。接下来,咱们来看一下各类类型的行为; 简单来讲,每种行为分别在编程语言中对应为一个”方法”,尽管实际上多是一组重载方法。

当咱们讨论“可选”参数时,应当清楚,不一样的语言有不一样的方式来解释这个概念。好比说,在Go语言中咱们会使用”functional Options”这个术语,而在Java中咱们会使用builder模式。

Tracer

Tracer 接口创造 Span 而且可以跨进程地 Inject (序列化)和 Extract (反序列化)。严格来讲,它应具备如下能力:

启动一个新的 Span

必须参数

  • 操做名称,一我的工可读的字符串,它简洁地表示由Span完成的工做 (例如,RPC方法名称、函数名称或一个较大的计算任务中的阶段的名称)。操做名称应该用泛化的字符串形式标识出一个Span实例. 也就是说,get_userget_user/314159 好。

好比说这里有几个操做名称,用于获得一个虚构的帐户信息:

操做名称 建议
get 太宽泛
get_account/792 太具体
get_account 刚恰好,account_id=792 可做为一个合适的 Span 标签

可选参数

  • 零或多个与 SpanContext 相关的references,尽量包括 ChildOfFollowFrom 引用类型的信息

  • 开始时间戳,若是没有的话,默认使用现实时间(walltime)

  • 零或多个标签

返回值是一个刚刚启动的 Span 实例

注入(Inject) SpanContext到载体中

必须参数

  • SpanContext实例

  • 格式描述符(format descriptor)(一般但不必定是字符串常量),告诉Tracer的实现如何在载体对象中对SpanContext进行编码

  • 载体(carrier),其类型由格式描述符指定。Tracer的实现将根据格式描述对此载体对象中的SpanContext进行编码

从载体中抽取(Extract) SpanContext

必须参数

  • 格式描述符(format descriptor),告诉Tracer的实现如何在载体对象中对SpanContext进行解码

  • 载体,其类型由格式描述符指定。 Tracer的实现将根据格式描述对此载体对象中的SpanContext进行解码

返回值是一个SpanContext实例,适合做为经过Tracer启动Span时的reference

注意: Injection和Extraction所需的格式

Injection和Extraction都依赖于一个可扩展的格式描述符参数,其指定了相关联的”载体”类型以及 SpanContext 是如何被编码的。Tracer实现必须支持下列全部格式。

  • 文本映射(Text Map): 任意的无字符编码限制的string-string型键值结构

  • HTTP Headers: string-string型的键值结构在HTTP headers( RFC 7230 )中也适用。在实操中,因为HTTP header很容易被各类不一样的方式处理, 强烈建议在Tracer的实现中使用有限的键空间和保守的转意值

  • 二进制: 表明了 SpanContext 的任意二进制数据

Span

除了获取 SpanSpanContext 的方法以外,下面任何方法都不能在 Span 完成后被调用。

获取 SpanSpanContext

无需参数。

返回值是 SpanSpanContext 。返回值甚至可能在 Span 结束后被使用。

重写操做名

必须参数

  • 新的操做名,当 Span 启动时取代旧内容

结束 Span

可选参数

  • 显式地添加Span的结束时间戳,若是没有这个参数则会隐式的添加现实时间(walltime)
    除了获取Span的SpanContext的方法以外,任何Span对象的方法都不能在其完成后被调用。

设置 Span 标签

必须参数

  • 标签的键,必须是字符串

  • 标签的值,必须是字符串,布尔值,数值类型其中之一

注意OpenTracing项目文档中已经为一些”标准标签”规定了语义。

记录(Log) 结构化的数据

必须参数

  • 一到多个键值对,键必须是字符串,值能够是任意类型。有些OpenTracing的实现能够处理更多的日志的值。

可选参数

  • 显式时间戳。该参数必须落在当前Span的开始与结束时间戳之间。

注意OpenTracing项目文档中已经为一些“日志的标准键“ 规定了语义。

设置(set) baggage item

Baggage item是对应于某个 Span 及其 SpanContext ,以及全部直接或间接引用自本地(local) SpanSpan 的键值对。也就是说,baggage items是与其trace一块儿传播的。

Baggage item为全栈式的OpenTracing集成提供了强大的功能(好比在移动App上使用时,它能够一路追踪数据直至储存系统的深度),不过使用这些功能时要小心。

每一个键值都会被拷贝到每个本地(local)及远程的子Span,这可能致使巨大的网络和CPU开销。

必须参数

  • baggage键,字符串

  • baggage值,字符串

获取(get) baggage item

必须参数

  • baggage键,字符串

返回值是对应的baggage值,或是一个表示没有baggage值的一个量。

SpanContext

在通常所指的OpenTracing层面上,SpanContext 更像是一个概念而不是一种实用功能。也就是说,这对OpenTracing的实现来讲提供一层薄的接口是相当重要的。当启动一个 Span 或者注入/提取(injecting/extracting) trace时,多数OpenTracing用户仅经过referenceSpanContext 进行交互。

在OpenTracing中,SpanContext 被强制设定为不可变的(immutable),以应对在 Span 结束时和引用(reference)时产生的复杂的生命周期问题。

遍历全部的baggage item

不一样语言对此有不一样的建模方式,不过给出一个 SpanContext 实例,语义上仍是应该能让调用者在短期内遍历baggage items。

NoopTracer

全部语言的OpenTracing API必须提供某种 NoopTracer 实现,可用做标记控制(flag-control)或者进行一些用于测试的无害注入等。某些状况下(好比Java),NoopTracer 可能在它本身的制品包(packaging artifact)中。

可选的API元素

有些语言提供了在单进程中用来传递活动的 SpanSpanContext 的工具。好比,opentracing-go 提供了在Go的 context.Context 机制中,用来set和get活动 Span 的帮助函数(helpers)。