新手问题 OpenTracing APIs

cdh0805010118 · 2018年06月30日 · 373 次阅读

OpenTracing 的多语言支持

目前官方 OpenTracing API 支持的平台有:GoPythonJSObjective-CJavaC++。PHP 和 Ruby 正在开发中。

Data Conventions 数据约定

OpenTracing APIs 的设计和规范,对追踪软件开发和探针软件开发都有通用指导意义;追踪系统的开发者不必严格遵守指南,但是强烈推荐大家这么做。

Spans

  1. Span 命名 在上一章 OpenTracing interface 中提到的 Span interface 包含 operation name、tags、logs 和 baggage。这些可以代表 span 中进行的工作类型,例如:RPC 或者 HTTP 调用端点、执行 SQL 语句,一个进程、类库或者模块名称。使得这个 span 所附带的信息是很有价值的。
  2. Span 结构 Span 结构也是非常重要的,主要表示 Span 本身所带重要信息,以及 Spans 之间的关联关系。后文具体介绍

Span Tag 用例

Span Tag 所携带的信息,特定存在的常量 Key,有 Errors、HTTP、Sample 等等。不同的底层会对这些信息做一些其他处理。例如:获取、删除或者清空 Span Tag 下的所有信息,这个使用时可能是用得到的,但是需要注意的是,这些额外的操作可能会对业务系统本身造成不良影响,所以请仔细斟酌这些额外的实现。

Errors

表示一个 span 实例的错误状态,通过一个 tag 来标注。如果设置了一个 span tag 特定常量 errors 的值为 true,这我们可以通过 dashboard ui 的 tag 查询功能,查询所有 trace error 列表,并通过 tag 的 log 日志,查看具体的 web request 错误信息,快速定位。并可以对一段时间的所有 traces error 列表统计,并报表输出。这个是非常重要的

Component Identification 组件定义

我们十分推荐库或者模块为监控程序提供组件的定义,最终用户可能会用拥有一个由框架和第三方混合提供的监控。例如:

  1. span tag 的 key:component,value:需要被监控的类库、模块或者包的基本名称;例如:httplibJDBCmongoose等;
  2. span tag 的 key:span.kind。value:client | server。指定这个 span 代表一个客户端或者服务端。

如果引入的 package 都自带分布式跟踪系统监控标签,则监控粒度就可以很容易的植入进来。

HTTP Server Tags

因为是 http 请求服务入口,所以这些都是在框架层做的事情。例如:

  1. span tag 的 key:http.url;value:url 地址;如:http://www.google.com.hk
  2. span tag 的 key: http.method; value: get|post|head
  3. span tag 的 key:http.status_code; value: 200; 404; 503

Peer Tags

这个用于 rpc 服务使用,描述远程请求过程中,请求调用的方向。(客户端记录下行访问,服务端记录上行访问)。

  1. peer.hostname目标主机名,类型:string
  2. peer.ipv4目标 IPv4 地址,类型:string
  3. peer.ipv6目标 IPv6 地址,类型:string
  4. peer.port目标端口,类型:int
  5. peer.service目标服务名称,string

peer 翻译:对等,比如:client 设置 tag 的 peer{hostname, ipv4, service , port ...},表示 server 的具体信息;server 设置 tag 的 peer{hostname...}, 表示 client 的具体信息。

Sampling 采样

OpenTracing API 不强调采样的概念。有些情况下,当业务量非常大时,如果业务使用了分布式追踪系统功能,则可能会对业务系统的性能造成很大影响。如果追踪系统产品本身实现了采样的特性,可以支持多规则采样,

  1. 流量规则;
  2. web request 数量;
  3. 预期的指定 trace(特定的订单 ID、支付 ID、用户 ID,预先植入,追踪特定请求 trace);

对于以上三种都是非常有价值的采样规则;span tag 中有个采样 key:sampling.priority, value 值为整数类型;

  1. value>0;追踪系统尽可能保留这条 trace;
  2. value=0;追踪系统不保存这条调用链;

如果此 tag 没有提供,追踪系统使用自己的默认采样规则;

Logs

Logs 日志是轻量级 trace 日志,与分布式日志系统无关;它是记录 span 事件日志,例如:当 span 执行单元发生错误时,错误日志存储在 span logs 中 event:error, message: 具体的错误信息;

Inject 和 Extract

《OpenTracing——相关概念术语》一文中提到,spans 之间的 trace 信息携带,如果是是跨进程,需要把数据通过BaggageSpanContext 携带,主要用于:

  1. rpc 服务;
  2. 发布-订阅机制;
  3. 通用消息队列;
  4. HTTP 请求调用;
  5. UDP 传输和其他传输方式;

把携带信息通过 OpenTracing APIs 中的 Inject 和 Extract 方法,在跨进程追踪时进行写入和读取。

InjectExtract方式实现的设计,必须遵循以下要求:

  1. 必须不需要使用 OpenTracing 使用中的特定代码;
  2. 必须不需要针对每一种已知的跨进程通讯机制都处理;
  3. 这套传播机制是最利于扩展的;

基本方法:Inject、Extract 和 Carriers

追踪过程中的 SpanContext 可以被 Inject 方法注入到 Carriers 中,这个 Carriers 可以是一个接口或者一个数据载体。 并在跨进程间传输,OpenTracing 标准包含两种必须的 Carriers 格式,自定义的 Carriers 也是可以的。同时在这个 Span 的 ChildOf 中通过 Extract 方法抽取 Carriers 信息,得到一个 SpanContext。这个 SpanContext 表示被 Inject 到 Carriers 中的信息。

Inject 伪代码:

span_context = ...

carrier = {} // 初始化数据载体
// 把span_context存放到HTTP_HEADERS格式的数据载体中
tracer.inject(span_context, opentracing.Format.HTTP_HEADERS, carrier)

// 并把carrier载体数据写入到跨进程调用client端的网络传输中。
for key, value in carrier:
    outbount_request.header[key] = value

Extrace 伪代码:

inbound_request = ...


// 把跨进程服务端接收到的传输数据,按照指定的格式和字段,抽取到span_context中
carrrier = inbound_request.headers
span_context = tracer.extract(opentracing.Format.HTTP_HEADERS, carrier)

// 并把tracer串联起来,创建一个新的span
span = tracer.start_span("...", child_of=span_context)

Carrier 格式:

所有的 Carriers 都有自己的格式。一般格式都以常量表达,例如:Binary, TextMap, HTTPHeaders 常量或者字符串指定;另一些,则通过 Carriers 的静态类型指定。

自定义的 Carriers 格式:

分布式跟踪系统底层的实现可以采用自定义的 Carriers 格式,进行 Inject 和 Extract 操作。例如: ArrrPC private RPC SubSystem,我们希望增加 OpenTracing 的数据在 RPC 请求过程中传输。伪代码:

span_context = ...
outbound_request = ...

try:
    // 尝试使用自定义的carrier格式,把span_context写入到数据载体中
    // 如果失败,直接使用标准的HTTP_HEADERS格式封装
    tracer.inject(span_context, arrrpc.ARRRPC_OT_CARRIER, carrier)

except opentracing.UnsupportedFormatException:

    carrier = {}
    tracer.inject(span_context, opentracing.Format.HTTP_HEADERS, carrier)

for key, value in carrier:
    outbound_request.header[key] = escape(value)

参考资料

opentracing 文档中文版 ( 翻译 ) 吴晟

更多原创文章干货分享,请关注公众号
  • 加微信实战群请加微信(注明:实战群):gocnio
暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册