概述

微服务提供了一个强大的架构,但也有其自身的挑战,特别是在调试和观察跨复杂网络的分布式事务方面——这只是因为没有内存调用或堆栈跟踪来实现这一点。
这就是分布式跟踪出现的地方。分布式跟踪提供了描述和分析跨进程事务的解决方案。在谷歌的Dapper文章中描述的分布式跟踪的一些用例包括异常检测、诊断稳定状态问题、分布式分析、资源属性和微服务的工作负载建模。

分布式跟踪

image.png

  1. 跟踪:事务在分布式系统中移动时的描述。
  2. Span:一个命名的定时操作,表示工作流的一部分。跨度接受key:value标签以及附加到特定跨度实例的细粒度、时间戳和结构化日志。
  3. 跨上下文:伴随分布式事务的跟踪信息,包括通过网络或消息总线将服务传递到服务的时间。跨度上下文包含跟踪标识符、跨度标识符和跟踪系统需要传播到下游服务的任何其他数据。

四大板块
从应用层分布式跟踪系统的角度来看,现代软件系统看起来像下面的图表:
image.png

现代软件系统中的组件可以分为三类:

  • 应用程序和业务逻辑:您的代码。
  • 广泛共享的库:其他人的代码。
  • 广泛共享服务:其他人的基础设施。
    这三个组件有不同的需求,并驱动分布式跟踪系统的设计,后者的任务是监视应用程序。最终的设计产生了四个重要部分:
  • 跟踪插装API:装饰应用程序代码的内容。
  • 有线协议:在RPC请求中与应用程序数据一起发送的内容。
  • 数据协议:异步(带外)发送到分析系统的内容。
  • 分析系统:用于处理跟踪数据的数据库和交互式UI。

OpenTracing是如何适应的呢?

OpenTracing API为检测提供了一个标准的、与供应商无关的框架。这意味着,如果开发人员想要尝试不同的分布式跟踪系统,那么与其为新的分布式跟踪系统重复整个检测过程,开发人员可以简单地更改跟踪器的配置。

什么是分布式跟踪?

分布式跟踪,也称为分布式请求跟踪,是一种用于分析和监视应用程序的方法,特别是那些使用微服务体系结构构建的应用程序。分布式跟踪有助于查明故障发生的位置以及导致性能低下的原因。

谁使用分布式跟踪?

  • IT和DevOps团队可以使用分布式跟踪来监控应用程序。分布式跟踪特别适合于调试和监视现代分布式软件体系结构,比如微服务。
  • 开发人员可以使用分布式跟踪来帮助调试和优化他们的代码。

OpenTracing是什么?

从OpenTracing不是什么开始可能会更容易理解一些。

  • OpenTracing不是下载或程序。分布式跟踪要求软件开发人员向应用程序的代码或应用程序中使用的框架中添加检测工具。
  • OpenTracing不是一个标准。Cloud Native Computing Foundation(CNCF)不是一个官方的标准机构。OpenTracing API项目致力于为分布式跟踪创建更多标准化的API和工具。

OpenTracing由API规范、实现了规范的框架和库以及项目文档组成。OpenTracing允许开发人员使用api向他们的应用程序代码中添加检测,而不会将他们锁定在任何特定的产品或供应商中。有关OpenTracing已经在何处实现的更多信息,请参阅支持OpenTracing规范的语言列表和跟踪程序列表。

概念和术语

所有特定于语言的OpenTracing api共享一些核心概念和术语。这些概念对于项目来说是如此的中心和重要,以至于它们有自己的存储库(github.com/opentracing/specification)和semver方案。

  1. OpenTracing语义规范是对当前泛语言OpenTracing标准的版本描述
  2. 语义约定规范描述了通用语义场景的传统跨标记和日志键
    两个文件都进行了版本控制,GitHub存储库根据版本控制策略描述的规则进行了标记。

Spans

“span”是分布式跟踪的主要构建块,表示在分布式系统中完成的单个工作单元。
分布式系统的每个组件都贡献一个span——一个命名的、计时的操作,表示工作流的一部分。
跨可以(通常也确实)包含对其他跨的“引用”,这允许将多个跨组装成一个完整的跟踪——请求在分布式系统中移动时的生命周期的可视化。
每个span根据OpenTracing规范封装了以下状态:

  • 一个操作名称
  • 开始时间戳和结束时间戳
  • 一组键:值范围标记
  • 一组键:值跨度日志
  • 一个SpanContext

Tags

Tags是键值对,它支持对跨域进行用户定义的注释,以便查询、筛选和理解跟踪数据。
Span tags应该应用于整个Span,在semantic_conventions.md中有一个列表,列出了用于常见场景的常规span tags。例如db这样的标签键db.instance来识别数据库主机,http.status_code表示HTTP响应代码,或者error,如果Span表示的操作失败,可以将其设置为True。

Logs

logs是键值对,对于捕获特定范围的日志消息和应用程序本身的其他调试或信息输出非常有用。日志对于记录跨度内的特定时刻或事件可能很有用(与应该应用于整个跨度的标记相反)。

SpanContext

SpanContext跨流程边界携带数据。具体来说,它有两个主要组成部分:

  • 依赖于实现的状态,用于引用跟踪中不同的跨度,即实现跟踪程序的spanID和traceID定义
  • 任何Baggage Items

    • 跨流程边界的键值对。
    • 对于在整个跟踪过程中有一些可用的数据。

一个span的列子:

    t=0            operation name: db_query               t=x

     +-----------------------------------------------------+
     | · · · · · · · · · ·    Span     · · · · · · · · · · |
     +-----------------------------------------------------+

Tags:
- db.instance:"customers"
- db.statement:"SELECT * FROM mytable WHERE foo='bar'"
- peer.address:"mysql://127.0.0.1:3306/customers"

Logs:
- message:"Can't connect to mysql server on '127.0.0.1'(10061)"

SpanContext:
- trace_id:"abc123"
- span_id:"xyz789"
- Baggage Items:
  - special_id:"vsid1738"

Scopes and Threading

介绍

在任何给定的线程中,都有一个“活动”的span,主要负责由周围的应用程序代码完成的工作,称为ActiveSpan。OpenTracing API只允许线程中的一个span在任何时间点处于活动状态。这是通过作用域来管理的,作用域正式确定了Span的激活和停用。
其他涉及同一线程的span将满足以下任一条件:

  • Started
  • Not finished
  • Not “active”
    例如,同一线程上可以有多个跨,如果跨是:
  • 等待I / O
  • 子跨度受阻
  • 偏离了关键路径
请注意,如果在开发人员创建一个新的Span时存在一个范围,那么它将充当它的父Span,除非程序员在buildSpan()时调用ignoreActiveSpan()或显式地指定父上下文。

访问当前活动的apan

因为手动地将活动范围从一个函数传递到另一个函数是不方便的,所以OpenTracing要求每个跟踪程序都包含一个ScopeManager。ScopeManager API通过作用域授予对活动范围的访问权。这意味着开发人员可以通过Scope访问任何活动的span。

在线程之间移动span
使用ScopeManager API,开发人员可以在不同的线程之间传输跨。一个Span的生命周期可能从一个线程开始,在另一个线程结束。ScopeManager API允许将Span传输到另一个线程或回调。不支持将作用域传递给另一个线程或回调。有关更多细节,请参考特定于语言的文档。

Tracers

介绍

OpenTracing提供了一个开放的、与供应商无关的标准API来描述分布式事务,特别是因果关系、语义和时间。它提供了一个通用的分布式上下文传播框架,由以下API原语组成:

  • 在进程中传递元数据上下文
  • 对元数据上下文进行编码和解码,以便在网络上传输元数据,以便进行进程间通信
  • 因果关系跟踪:父-子、分叉、连接
    OpenTracing抽象了许多跟踪器实现之间的差异。这意味着,不管开发人员使用哪种示踪系统,检测手段都将保持不变。为了使用OpenTracing规范检测应用程序,必须部署兼容的OpenTracing跟踪程序。所有支持的跟踪器的列表可以在这里找到。

Tracer Interface

跟踪器接口创建spans,并了解如何跨进程边界注入(序列化)和提取(反序列化)元数据。它具有以下功能:

  • 开始一个新的Span
  • 将SpanContext注入载体
  • 从载体中提取SpanContext
    下面将更详细地讨论这些问题。为了实现目的,请查看特定的语言指南。

设置Tracer

跟踪器是将记录跨度并将其发布到某处的实际实现。应用程序如何处理实际的跟踪程序取决于开发人员:或者直接在整个应用程序中使用它,或者将它存储在GlobalTracer中,以便于与仪表化框架一起使用。不同的跟踪器实现在初始化时接收参数的方式和内容各不相同,例如:

  • 应用程序跟踪的组件名。
  • 跟踪端点。
  • 跟踪凭证。
  • 抽样策略。
    一旦获得了跟踪程序实例,就可以使用它手动创建Span,或者将其传递给框架和库的现有检测。为了不强迫用户保留跟踪程序,io.opentrace.util工具包含一个实现了io.opentrace.Tracer接口的GlobalTracer类,顾名顾义,这个类充当可以在任何地方使用的全局实例。它的工作原理是将所有操作转发到另一个底层跟踪程序,该跟踪程序将在将来的某个点注册,默认情况下,底层跟踪程序是一个no-nop实现。

开始新的跟踪

每当创建新的Span而不引用父Span时,就会启动新的跟踪。在创建一个新的Span时,您需要指定一个“操作名称”,这是一个自由格式的字符串,您可以使用它来帮助您识别这个Span所关联的代码。我们的新跟踪的下一个范围可能是子范围,并且可以被看作是在主范围内执行的子例程的表示。因此,子跨度与父跨度之间存在child-of关系。另一种类型的关系如下所示,用于新跨独立于父跨的特殊情况,例如在异步进程中。

访问活动的span

可以使用跟踪程序来启用对ActiveSpan的访问。在某些语言中,activespan也可以通过ScopeManager访问。有关更多实现细节,请参阅特定语言指南。

使用Inject/Extract传播跟踪

为了在分布式系统中跨流程边界进行跟踪,服务需要能够继续由发送每个请求的客户机注入的跟踪。OpenTracing通过提供将span的上下文编码为载体的注入和提取方法来实现这一点。inject方法允许将SpanContext传递给载体。例如,将跟踪信息传递到客户端请求中,以便发送信息的服务器可以继续跟踪。extract方法的作用正好相反。它从载体中提取SpanContext。例如,如果在客户端有一个活动的请求,开发人员必须使用io.opentracing.Tracer.extract方法提取SpanContext。

image.png

实现了opentracing的系统

追踪系统支持的语言
CNCF JaegerJava, Go, Python, Node.js, C++, C#
DatadogGo
inspectITjava
InstanaCrystal, Go, Java, Node.js, Python, Ruby
LightStepGo, Python, JavaScript, Objective-C, Java, PHP, Ruby, C++
stagemonitorjava

杨辉
92 声望18 粉丝

程序猿