美文网首页
OpenTracing 语义说明

OpenTracing 语义说明

作者: zhexuany | 来源:发表于2018-03-02 01:42 被阅读0次

    最近在为 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`。

    相关文章

      网友评论

          本文标题:OpenTracing 语义说明

          本文链接:https://www.haomeiwen.com/subject/mgfpxftx.html