jaeger 复习笔记

920 阅读11分钟

平时工作里基本都是直接一把嗦来没有怎么细看过,记录 一下,比较有价值的还是参考文档

OpenTracing语义标准 (译文)

综述

这是正式的OpenTracing语义标准。OpenTracing是一个跨编程语言的标准,此文档会避免具有语言特性的概念。比如,我们在文档中使用"interface",因为所有的语言都包含"interface"这种概念。

版本命名策略

OpenTracing标准使用Major.Minor版本命名策略(即:大版本.小版本),但不包含.Patch版本(即:补丁版本)。如果标准做出不向前兼容的改变,则使用“主版本”号提升。如果是向前兼容的改进,则进行小版本号提升,例如加入新的标准tag, log和SpanContext引用类型。(如果你想知道更多关于制定此版本政策的原因,可参考specification#2) 

OpenTracing数据模型

OpenTracing中的Trace(调用链)通过归属于此调用链的Span来隐性的定义。 特别说明,一条Trace(调用链)可以被认为是一个由多个Span组成的有向无环图(DAG图), Span与Span的关系被命名为References。

Span

表示分布式调用链条中的一个调用单元,其边界包含一个请求进到服务内部再由某种途径(例如:http)从当前服务出去。

一个 Span 一般会记录这个调用单元内部的一些信息,例如每个 Span 包含的操作名称、开始和结束时间、附加额外信息的 Span Tag、可用于记录 Span 内特殊事件 Span Log 、用于传递 Span 上下文的 SpanContext 和定义 Span 之间关系的 References 。

Span 状态

  • 操作名称 (An operation name)
  • 开始时间 (A start timestamp)
  • 结束时间 (A finish timestamp)
  • 标签信息 (Span Tag):零个或多个键值对(keys:values)组成的 Span Tags。键必须是 string 类型,值可以是字符串,布尔,或者数字类型。
  • 日志信息 (Span Log):零个或多个 Span Logs。每次 log 操作包含一个键值对和一个时间戳。 键值对中,键必须为 string 类型,值可以是任意类型。 但并不是所有的支持 OpenTracing 的 Tracer 都需要支持所有的值类型。
  • Span 上下文对象 (SpanContext)
  • Span 间关系 (References):通过 SpanContext 可以指向零个或者多个因果相关的 Span 。

SpanContext 状态

  • 任何一个 OpenTracing 实现都需要将当前调用链的状态(例如:Trace 和 Span 的 id)跨进程边界传输,依赖于一个独特的 Span
  • Baggage Items,Trace 的随行数据,是一个键值对集合,存在于 Trace 中,也需要跨进程边界传输

Span间关系

一个Span可以与一个或者多个SpanContexts存在因果关系。OpenTracing目前定义了两种关系:ChildOf(父子) 和 FollowsFrom(跟随)。这两种关系明确的给出了两个父子关系的Span的因果模型。 将来,OpenTracing可能提供非因果关系的span间关系。(例如:span被批量处理,span被阻塞在同一个队列中,等等)。ChildOf 引用: 一个span可能是一个父级span的孩子,即"ChildOf"关系。在"ChildOf"引用关系下,父级span某种程度上取决于子span。下面这些情况会构成"ChildOf"关系:

  • 一个RPC调用的服务端的span,和RPC服务客户端的span构成ChildOf关系
  • 一个sql insert操作的span,和ORM的save方法的span构成ChildOf关系
  • 很多span可以并行工作(或者分布式工作)都可能是一个父级的span的子项,他会合并所有子span的执行结果,并在指定期限内返回

下面都是合理的表述一个"ChildOf"关系的父子节点关系的时序图。

1.     [-Parent Span---------]
2.          [-Child Span----]
3. 
4.     [-Parent Span--------------]
5.          [-Child Span A----]
6.           [-Child Span B----]
7.         [-Child Span C----]
8.          [-Child Span D---------------]
9.          [-Child Span E----]

FollowsFrom引用: 一些父级节点不以任何方式依赖他们子节点的执行结果,这种情况下,我们说这些子span和父span之间是"FollowsFrom"的因果关系。"FollowsFrom"关系可以被分为很多不同的子类型,未来版本的OpenTracing中将正式的区分这些类型

下面都是合理的表述一个"FollowFrom"关系的父子节点关系的时序图。

1.     [-Parent Span-]  [-Child Span-]
2. 
3. 
4.     [-Parent Span--]
5.      [-Child Span-]
6. 
7. 
8.     [-Parent Span-]
9.                 [-Child Span-]

OpenTracing API

OpenTracing标准中有三个重要的相互关联的类型,分别是TracerSpan and SpanContext。下面,我们分别描述每种类型的行为,一般来说,每个行为都会在各语言实现层面上,会演变成一个方法,而实际上由于方法重载,很可能演变成一系列相似的方法。

当我们讨论“可选”参数时,需要强调的是,不同的语言针对可选参数有不同理解,概念和实现方式 。例如,在Go中,我们习惯使用"functional Options",而在Java中,我们可能使用builder模式。

Tracer

Tracer接口用来创建Span,以及处理如何处理Inject (serialize) 和 Extract (deserialize),用于跨进程边界传递。它具有如下官方能力:

Start a new Span

创建一个新Span

必填参数

  • operation name, 操作名, 一个具有可读性的字符串,代表这个span所做的工作(例如:RPC方法名,方法名,或者一个大型计算中的某个阶段或子任务)。操作名应该是一个抽象、通用,明确、具有统计意义的名称。因此,"get_user" 作为操作名,比 "get_user/314159"更好。

例如,假设一个获取账户信息的span会有如下可能的名称:

必填参数

  • operation name, 操作名, 一个具有可读性的字符串,代表这个span所做的工作(例如:RPC方法名,方法名,或者一个大型计算中的某个阶段或子任务)。操作名应该是一个抽象、通用,明确、具有统计意义的名称。因此,"get_user" 作为操作名,比 "get_user/314159"更好。

例如,假设一个获取账户信息的span会有如下可能的名称:

可选参数

  • 零个或者多个关联(references)的SpanContext,如果可能,同时快速指定关系类型,ChildOf 还是 FollowsFrom
  • 一个可选的显性传递的开始时间;如果忽略,当前时间被用作开始时间。
  • 零个或者多个tag。

返回值,返回一个已经启动Span实例

SpanContext上下文Inject(注入)到carrier

必填参数

  • *SpanContext*实例
  • format(格式化)描述,一般会是一个字符串常量,但不做强制要求。通过此描述,通知Tracer实现,如何对SpanContext进行编码放入到carrier中。
  • carrier,根据format确定。Tracer实现根据format声明的格式,将SpanContext序列化到carrier对象中。

SpanContext上下文从carrier中Extract(提取)

必填参数

  • format(格式化)描述,一般会是一个字符串常量,但不做强制要求。通过此描述,通知Tracer实现,如何从carrier中解码SpanContext
  • carrier,根据format确定。Tracer实现根据format声明的格式,从carrier中解码SpanContext

返回值,返回一个SpanContext实例,可以使用这个SpanContext实例,通过Tracer创建新的Span

注意,对于Inject(注入)和Extract(提取),format是必须的。

Inject(注入)和Extract(提取)依赖于可扩展的format参数。format参数规定了另一个参数"carrier"的类型,同时约束了"carrier"中SpanContext是如何编码的。所有的Tracer实现,都必须支持下面的format。

  • Text Map: 基于字符串:字符串的map,对于key和value不约束字符集。
  • HTTP Headers: 适合作为HTTP头信息的,基于字符串:字符串的map。(RFC 7230.在工程实践中,如何处理HTTP头具有多样性,强烈建议tracer的使用者谨慎使用HTTP头的键值空间和转义符)
  • Binary: 一个简单的二进制大对象,记录SpanContext的信息。

Span

Span结束后(span.finish()),除了通过Span获取SpanContext外,下列其他所有方法都不允许被调用。

除了通过Span获取SpanContext

不需要任何参数。返回值,Span构建时传入的SpanContext。这个返回值在Span结束后(span.finish()),依然可以使用。

复写操作名(operation name)

必填参数

  • 新的操作名operation name,覆盖构建Span时,传入的操作名。

结束Span

可选参数

  • 一个明确的完成时间;如果省略此参数,使用当前时间作为完成时间。

Span设置tag

必填参数

  • tag key,必须是string类型
  • tag value,类型为字符串,布尔或者数字

注意,OpenTracing标准包含**“standard tags,标准Tag”**,此文档中定义了Tag的标准含义。

Log结构化数据

必填参数

  • 一个或者多个键值对,其中键必须是字符串类型,值可以是任意类型。某些OpenTracing实现,可能支持更多的log值类型。

可选参数

  • 一个明确的时间戳。如果指定时间戳,那么它必须在span的开始和结束时间之内。

注意,OpenTracing标准包含**“standard log keys,标准log的键”**,此文档中定义了这些键的标准含义。

设置一个baggage(随行数据)元素

Baggage元素是一个键值对集合,将这些值设置给给定的SpanSpanSpanContext,以及所有和此Span有直接或者间接关系的本地Span。 也就是说,baggage元素随trace一起保持在带内传递。(译者注:带内传递,在这里指,随应用程序调用过程一起传递)Baggage元素为OpenTracing的实现全栈集成,提供了强大的功能 (例如:任意的应用程序数据,可以在移动端创建它,显然的,它会一直传递了系统最底层的存储系统。由于它如此强大的功能,他也会产生巨大的开销,请小心使用此特性。再次强调,请谨慎使用此特性。每一个键值都会被拷贝到每一个本地和_远程_的下级相关的span中,因此,总体上,他会有明显的网络和CPU开销。必填参数

  • baggage key, 字符串类型
  • baggage value, 字符串类型

获取一个baggage元素

必填参数

  • baggage key, 字符串类型

返回值,相应的baggage value,或者可以标识元素值不存在的返回值(译者注:如Null)。

SpanContext

相对于OpenTracing中其他的功能,SpanContext更多的是一个“概念”。也就是说,OpenTracing实现中,需要重点考虑,并提供一套自己的API。 OpenTracing的使用者仅仅需要,在创建span、向传输协议Inject(注入)和从传输协议中Extract(提取)时,使用SpanContextreferences,OpenTracing要求,SpanContext是不可变的,目的是防止由于Span的结束和相互关系,造成的复杂生命周期问题。

遍历所有的baggage元素

遍历模型依赖于语言,实现方式可能不一致。在语义上,要求调用者可以通过给定的SpanContext实例,高效的遍历所有的baggage元素

NoopTracer

所有的OpenTracing API实现,必须提供某种方式的NoopTracer实现。NoopTracer可以被用作控制或者测试时,进行无害的inject注入(等等)。例如,在 OpenTracing-Java实现中,NoopTracer在他自己的模块中。

可选 API 元素

有些语言的OpenTracing实现,为了在串行处理中,传递活跃的SpanSpanContext,提供了一些工具类。例如,opentracing-go中,通过context.Context机制,可以设置和获取活跃的Span

Jaeger组成

Jaeger Client - 为不同语言实现了符合 OpenTracing 标准的 SDK。应用程序通过 API 写入数据,client library 把 trace 信息按照应用程序指定的采样策略传递给 jaeger-agent。
Agent - 它是一个监听在 UDP 端口上接收 span 数据的网络守护进程,它会将数据批量发送给 collector。它被设计成一个基础组件,部署到所有的宿主机上。Agent 将 client library 和 collector 解耦,为 client library 屏蔽了路由和发现 collector 的细节。
Collector - 接收 jaeger-agent 发送来的数据,然后将数据写入后端存储。Collector 被设计成无状态的组件,因此您可以同时运行任意数量的 jaeger-collector。
Data Store - 后端存储被设计成一个可插拔的组件,支持将数据写入 cassandra、elastic search。
Query - 接收查询请求,然后从后端存储系统中检索 trace 并通过 UI 进行展示。Query 是无状态的,您可以启动多个实例,把它们部署在 nginx 这样的负载均衡器后面。

分布式追踪系统发展很快,种类繁多,但核心步骤一般有三个:代码埋点,数据存储、查询展示

快速入门与代码实例

推荐参考3来学习code

参考4视频资料了解组件相关基础概念

TODO

OpenTracing vs OpenCensus

OpenTracing + OpenCensus = OpenTelemetry 三者的区别和联系

参考

1.github.com/opentracing…

2.github.com/yurishkuro/…

3.github.com/yurishkuro/…

4.www.youtube.com/watch?v=aMZ…