OpenTracing 语义说明

最近在为 TiDB 加一个 tracing 的工具。 虽然 TiDB 已经开始使用 OpenTracing 工具了,但是还远远不够。没有做到全链路追踪,没法知道某个具体的 query 在那些节点慢。 在研究过程中,需要熟练掌握 OpenTracing 的概念,也就是这篇 semantic specification。 在这篇文章里规定了 不同语言间 OpenTracing 需要实现的函数,类型。

因为 OpenTracing 是跨语言的,按照标准实现的时候,需要尽可能的根据通用的语言概念,而不能局限于某一个具体的语言特性。这也解释了这篇文档的必要性。

The OpenTracing 数据模型

首先需要阐明的是 Span 和 trace 的概念。 用图论的观点来看的话,traces 可以被认为是 spans 的 DAG。也就是说,对个 spans 形成的 DAG 是一个 Traces。

举例来说,下图是一个由八个 Spans 形成的一个 Trace。

单个 Trace 中 Span 之间的因果关系


        [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 中 Spans 之间的时间关系

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

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

每个 Span 包含一些状态:

  • Operation 的 名字(An operation name)
  • 开始 ts (A start timestamp)
  • 结束 ts (A finish timestamp)
  • 0个或多个以 keys:values 为形式组成的 Span Tags。 key 必须是 string, values 则可以是 strings, bool,numeric types
  • 0个或多个 Span logs
  • 一个 SpanContext
  • 通过 SpanContext 可以指向 0个 或者多个 因果相关的 Span

每个 SpanContext 包含以下状态:

  • 任何 OpenTraceing 实现相关的状态(比如 trace 和 span id)都需要被一个跨进程的 Span 所联系。
  • ​Baggage Items: 跨进程的 key value 对。

References between Spans

一个 Span 可能, 因因果相关,指向0个或者多个其他的 SpanContexts。 目前来说, OpenTracing 仅仅定义了两种关系: ChildOfFollowsForm。如同字面上可以猜测到的, ChildOf 将成为当前 Span 的 child 而 FollowsFrom则会成为 parent。 这两种关系为 child spanparent span 建立了直接因果关系。

ChildOf 引用: 某个 Span 可以是 ChildOfparent Span。在一个 ChildOf 的引用中, parent Span, 在某种程度上取决于child Span。 下面列举能形成 ChildOf 关系的条件:

  • server 端的 RPC 的 Span 可能是 ChildOf client 端 RPC。
  • SQL insert 的 Span 可能是 ChildOf 一个 ORM save 方法的 Span
  • 许多做并发处理工作的 Span 可能都独立的是 ChildOf 一个单独的 合并这些在截止时间返回工作结果的 parent Span。
  [-Parent Span---------]
         [-Child Span----]

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

FollowsFrom 引用: 一些 parent Spans 并不依赖 child Span 的结果。如果是这种情况, 那么我们基于因果关系上说Child Span FollowsFrom parent Span。这里,有很多唯一的 FollowsFrom 引用的子类别。这些会在以后被更加正式的定义。

这些是有效的,基于时间顺序的 FollowFrom 引用:

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


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


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

OpenTracing API

在 OpenTracing 有着三个关键的并且相互关联的类型: Tracer, Span, SpanContext。下面,我们来介绍下每种类型的基本行为。 简单地说,每种行为都会在具体的语言中变为一个“方法”,though it may actually be a set of related sibling methods due to type overloading and so on.

在不同语言中,对于 “Optional” 参数的理解是不一样的。 举例来说, Go 里 我们会使用 “functional Options”,但是 Java 里可能会使用 builder 模式。

Tracer

Tracer interface 创造 Spans 并且理解 如何 Inject (serialize) and Extract (deserialize) them across process boundaries. Formally, it has the following capabilities:

Start a new Span

要求的参数

  • 一个 大家都能够理解的 字符串operation name, 并且精确代表了被 Span 做完的工作。 (例如, 一个 RPC 方法名, 一个函数名, 或者 超大计算任务中某个子任务的名字). The operation name 应该 可以辨认一个 Span 实例的最为一般的 string. 这是说, "get_user" 是比 "get_user/314159" 更好的.

举例来说,假设我们需要获得账户(account)信息, 下面是一些对于一个 Span 可能的 operation names:

Operation Name 指导
get 过于一般
get_account/792 过于具体
get_account 赞, 并且 account_id=792 会是一个很好的 Span tag

可选择的参数:

  • 零个或者多个 references 到相关的SpanContexts, 如果可能的话,包括一个对于 ChildOfFollowsFrom reference types 简略
  • 一个可选的,显性的 start timestamp; 如果被忽略,那么当前 walltime 会被默认使用
  • 零个或者多个 tags

返回 一个 已经开始的 Span 实例 (但是尚未结束)

Inject a SpanContext into a carrier

要求参数

  • 一个 SpanContext 实例
  • 一个能告诉 Tracer 如何将 SpanContext 编码的 格式 描述 (特别的,对于 string 来说,这个不是必须的)
  • 一个被 format 所指定的 carrier。某个Tracer实现根据这个 formatSpanContext编码进入这个 carrier 对象
Extract a SpanContext from a carrier

要求参数

  • 一个 format 描述 (一般但不必要是一个 string 常数)。 目的在于告诉某个 Tracer 实现 如何将SpanContext carrier 中解码。
  • 一个 carrier。它的类型是由format 支配的。某个 Tracer 实现会依据这个 formatSpanContext 从这个 carrier 对象解码。

**返回一个 SpanContext 实例。 当我们想要通过 Tracer 开始一个新的 Span, 这个实例是可以被用来当做一个。

Note: required formats for injection and extraction

injection 和 extraction 都依赖于一个可扩展的 **format 参数。 这个参数规定了关联 “carrier” 的类型,同时也描述了一个 SpanContext 是如何被编码进入这个 carrier 的。 所有下面的 formats 都必须被所有的 Tracer 实现支持:

  • Text Map: 一个任意 string-to-string 的 map。 Keys 和 values 都是不受任何限制的字符 。
  • HTTP Headers: 一个 string-to-string 的 map。Keys 和 values 需要适配 HTTP headers (a la RFC 7230. 实践上来说,因为 HTTP headers 存在被野蛮使用的现象,这里强烈推荐 Tracer 实现限定 HTTP headers 密钥空间(Key Space) 的使用并且保守的将相应的值转义。
  • Binary: 一个 (单独) 任意的 表示 一个 SpanContext binary blob。

Span

除去 将 Span's SpanContext 取回的函数,下面任何一个函数都被不会在 Span 结束后被调用。

Retrieve the Spans SpanContext

没有任何参数。

返回 特定 SpanContext,对于给定的 Span. 返回值可能在 Span结束后仍被使用。

Overwrite the operation name

要求参数。

  • 新的 operation name。它将取代在这 Span 开始时传入的 operation name
Finish the Span

可选参数

  • Spanfinish timestamp;如果没设定,那么当前的 walltime 就会被使用。

除去 将 Span's SpanContext 取回的函数,下面任何一个函数都被不会在 Span 结束后被调用。

Set a Span tag

要求参数

  • the tag key, 必须是 string
  • The tag value, 只能是 string, boolean, numeric type 中任意一个。

Note that the OpenTracing project documents certain "standard tags" that have prescribed semantic meanings.

Log structured data

要求参数

  • 一个或者多个 key:value 对。 这些 keys 必须是 string; values 可以有任意类型 一些 OpenTracing 实现可能会处理更多的 log values。

可选参数

  • 一个显性的 timestamp. 如何设定,这个值一定是在本地开始时间和 span 结束时间之间。

Note that the OpenTracing project documents certain "standard log keys" which have prescribed semantic meanings.

Set a baggage item

Baggage items 是 key:value 的 string 对。key:value 对适用于给定的 Span, 它的 SpanContext, 以及有着直接或者间接 引用关系(reference) 的所有的 Spans。也就是说,baggage items 在随着 trace 一起在频内传播(propagate in-band along with trace itself)。

对于一个 full-stack OpenTracing 集成来说,Baggage items 可实现强大的功能(例如,来自移动应用程序的任意应用程序数据可以透明地、深度地进入存储系统中)中,并带来有一些巨大的成本:请小心驾驶。

谨慎小心地使用此功能。每个键和值都被复制到相关Span的每个本地和远程子元素中,并且这会增加很多网络和CPU开销。

要求参数

  • baggage key, 类型为 string
  • baggage value, 类型为 string
Get a baggage item

要求参数

  • The baggage key, 类型为 string

Returns the corresponding baggage value, xor some indication that such a value was missing.

SpanContext

SpanContext更像是一个“概念”,而不是通用 OpenTracing 层的有用功能。也就是说,这对于 OpenTracing 实现非常重要,并且确实呈现了一个自己的瘦API。大多数 OpenTracing 用户只能在启动新的 Spans 时通过引用*与 SpanContext 进行交互。或者在某些传输协议中注入/提取跟踪。

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

Iterate through all baggage items

这取决于语言以不同的方式进行建模,但在语义上,调用者应该能够在给定'SpanContext`实例的情况下一次遍历所有的 baggage items。

NoopTracer

所有实现 OpenTracing 语言 API 还必须提供某种 “NoopTracer” 实现,可用于标记控制 OpenTracing 或为测试注入无害的东西(等等)。在某些情况下(例如Java),“NoopTracer” 可能在它自己的打包 artifact 中

Optional API Elements

某些语言还提供实用程序来在单个进程中传入一个活动的“ Span” 和/或 “SpanContext”。例如,opentracing-go提供基于 Go 的 'context.Context机制 的 helpers 来设置和获取 中的活动Span`。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,590评论 18 139
  • 注:本文转自好友吴晟的两篇译文 ,译文原文如下:https://github.com/opentracing-co...
    小程故事多阅读 12,927评论 4 18
  • The Inner Game of Tennis W Timothy Gallwey Jonathan Cape ...
    网事_79a3阅读 11,680评论 2 19
  • 昨夜魔鬼来到我身旁 沉睡的我醒来 递给魔鬼一支烟 点燃,烟的红光在漆黑里很美 魔鬼说他只是路过 我问魔鬼你要去哪里...
    傲娇的小猫阅读 185评论 0 0
  • 最近这天气,确实有点热,看了一下天气预报,马上要降温了,今天周二,依旧是按部就班的工作着,我公司前台的工作量...
    惜婉词阅读 257评论 0 1