企业主流全链路监控系统 - OpenTelemetry(一)

在这里插入图片描述

1. Observability-可观测性

在正式介绍OpenTelemetry之前,我们还需要了解什么是可观测性

管理学大师彼得德鲁克有一句话:“如果你无法衡量它,你就无法管理它”。在企业中,无论是管理人,还是管理事,抑或是管理系统,首先都需要衡量。衡量的过程其实是搜集信息的过程,有了足够的信息才能做出正确的判断,有了正确的判断才能做出有效的管理和行动方案。
在这里插入图片描述

图释:通过观测看到表象,通过判断定位问题,通过优化解决问题。

可观测性描述的就是“观测-判断-优化-再观测”这个闭环的连续性、高效性。如果只有观测而无法基于观测做出判断,则不能称其具备可观测性。如果只有经验判断而没有数据支撑,也不能称其具备可观测性,这样会导致组织高度依赖个人能力会带来管理风险。如果优化之后无法反馈到观测上,或者因优化引入新的技术而导致无法观测,则其可观测性不可持续。如果在观测、判断、优化的闭环中需要付出很高的成本和承担很大风险,则其可观测性的价值为负。

所以,当我们在谈可观测性的时候,其实更多考虑的是观测者、管理者的感受,也就是说在我们遇到问题的时候,能否轻而易举地在观测平台找到答案,没有阻力也没有困惑,这就是可观测性。随着企业的发展,组织架构(角色、观测者)和管理对象(系统、被观测者)都会随之发展变化,当使用了一堆传统的观测工具,却仍然无法满足观测者、管理者新的需求的时候,我们不禁要问:“可观测性何在?”。

“可观测”不等于“可观测性”
下面,我们来看一下我们习以为常的观测方式
在这里插入图片描述

图释:传统的观测工具是垂直的,观测者需要从多个工具中进行问题判断。

通常我们会基于自己想要的数据去搭建观测工具,比如:

  • 当我们想了解掌握基础设施的健康状况的时候,我们会很自然的想到搭建一个仪表盘,实时监测各项指标。
  • 当我们想了解业务是如何出问题的,我们会很自然的想到搭建一个日志平台,随时过滤排查业务日志。
  • 当我们想了解事务为什么高延迟,我们会很自然的想到搭建一个链路监测平台,查询拓扑依赖和各节点的响应时间。

这种模式很好,帮助我们解决了很多问题,以至于我们从不怀疑可观测性,我们信心满满。偶尔遇到大难题,把我们的仪表盘、日志平台、链路平台打开,所有的数据都在这里,我们坚信一定能到找问题的根因。即使花费了很长时间,我们也只是告诉自己要多学习,多了解掌握自己负责的系统,下一次我一定能更快找到根因。是的,当我们想要的数据都摆在面前的时候,我们还有什么理由怪罪观测工具。

在这里插入图片描述

图释:当发现指标有毛刺的时候,往往需要在大脑中构建复杂的日志查询条件,费时不说还容易出错。

我们会不辞劳苦地在各种指标数据中寻找可能的关联性,得到关键线索后,我们会在大脑中构造出一堆复杂的日志查询条件来验证自己的猜想。就这样比对、猜想、验证,同时还要在各种工具中切换,不可否认很充实。
在这里插入图片描述

图释:系统规模庞大的时候,人已经无法去定位问题了。

传统的系统相对简单,上述方式行之有效。现代IT系统的关键词是分布式、池化、大数据、零信任、弹性、容错、云原生等,越来越庞大,越来越精细,越来越动态,同时也越来越复杂。通过人去寻找各种信息的关联性,再根据经验判断和优化,显然是不可行的,耗时耗力还无法找到问题根因。

这里边最关键的其实是解决数据关联的问题,把之前需要人去比对、过滤的事交给程序去处理,程序最擅长此类事同时也最可靠,人的时间更多的用在判断和决策上。这在复杂系统中,节省的时间会被放大很多倍,就这点小事就是可观测性看得见的未来
在这里插入图片描述

图释:未来观测工具需要通过时间和上下文来关联数据

要实现可观测,需要多种数据支撑,其中最为重要的三种如下

  • 日志:记录特定时间发生的各种离散事件的信息。
  • 指标:描述软件系统或组件随时间变化的度量数据,如微服务的 CPU 利用率等。
  • 追踪:描述分布式系统各部分之间的依赖关系。
    在这里插入图片描述

那么,如何做数据关联呢?说起来很容易,那就是做时间+空间的关联。在我们的统一数据平台上,由于数据是来自于各种观测工具的,虽然我们在数据格式上统一成了metric、log、trace,但不同工具的metric、log、trace的元数据截然不同,而如果我们在这个统一数据平台上去梳理和映射这些元数据的话,这将是庞杂、难维护、不可持续的。那该如何做呢?答案就是标准化。只有将标准化、结构化的数据喂给观测平台,观测平台才能从中发现巨大价值。统一数据平台只是在数据格式上进行了标准化,而要想将trace、metric、log关联还必须建立context的标准化,context就是数据的空间信息,再叠加上时间信息的关联就可以发挥真正的观测价值。

所以,它来了,Opentelemetry(以下简称:OTel)就是解决数据标准化问题的一个项目

以上部分内容参考"一文读懂可观测性与Opentelemetry"

2. OpenTelemetry来了

OpenCensus由Google发起,最初是Google内部追踪平台,后开源。
OpenTracing由CNCF托管,具备较为完善的instrumentation库。

这两个项目较为特殊:其一是OpenTracing,他制定了一套无关平台的统一的Trace的标准,后续的很多项目,例如:Jaeger等,都是基于此协议,因此他在当时的Trace标准领域具有不小影响力;其二是OpenCensus,他背靠Google,并且它不仅仅实现了Trace,还包括了Metrics,并且他包含了一系列诸如Agent和Collector的方案,可以说是相当完备。

在当时这两大流派可以说是互相有一大票的追随者,一边是以Google和微软领衔的OpenCensus,一边是众多开源项目和厂商使用的OpenTracing,两者可以说是各有优劣,各领风骚。直到有一天…

在经过了一段时间的发展后,OpenCensus与OpenTracing为了将两者的优点整合,便诞生了赫赫有名的Opentelemetry!
在这里插入图片描述Opentelemetry可以说是含着金汤匙出生:OpenTracing和OpenCensus的支持,刚开始就自带经验丰富的的社区人员,同时背后也有互联网巨头的支持。自Opentelemetry诞生之后,OpenTracing和OpenCensus就不再维护了。

OpenTelemetry 的自身定位很明确:数据采集和标准规范的统一,对于数据如何去使用、存储、展示、告警等,官方并不涉及

OpenTelemetry 要解决的是对可观测性的大一统,它提供了一组 API 和 SDK 来标准化遥测数据的采集和传输,opentelemetry 并不想对所有的组件都进行重写,而是最大程度复用目前业界在各大领域常用工具,通过提供了一个安全,厂商中立的能用协议、组件,这样就可以按照需要形成 pipeline 将数据发往不同的后端。

3. 架构及核心概念

在这里插入图片描述

  • receivers(接收者): 定义从 client 端的数据要以何种数据模型进行接收, 支持很多种数据模型
  • processors: 将 receivers 的数据进行某些处理,比如批量、性能分析等
  • exporters: 将 processors 后的数据导出到特定的后端,比如 metrics 数据存储到 prometheus 中

OTLP协议: otlp 是 opentelemetry 中比较核心的存在,在遥测数据及 Collector 之间制定了包括编码(encoding)、传输(transport)、传递(delivery)等协议。
在这里插入图片描述

  • Specification: 是定义了 API/SDK 及数据模型,所有包含第三方实现的都需要遵循 spec 定义的规范。
  • Semantic Conventions: OpenTelemetry 项目保证所有的 instrumentation(不论任何语言)都包含相同的语义信息
  • Resource: resource 附加于某个 process 产生的所有 trace 的键值对,在初始化阶段指定并传递到 collector 中
  • Baggage: 为添加在 metrics、log、traces 中的注解信息,键值对需要唯一,无法更改
  • Propagators: 传播器,比如在多进程的调用中,开启传播器用于跨服务传播 spanContext。
  • Attributes: 其实就是 tag, 可以给 span 添加 metadata 数据,SetAttributes属性可以多次添加,不存在就添加,存在就覆盖
  • Events: 类似于日志, 比如在 trace 中嵌入请求体跟响应体。
  • Collector: 它负责遥测数据源的接收、处理和导出三部分,提供了与供应商无关的实现。
  • Data sources: OpenTelemetry 提供的数据源, 目前包含:
    • Traces
    • Metrics
    • Logs
    • Baggage

在这里插入图片描述

下面我们来详细说说这些概念:

API

API 是 OpenTelemetry 的一部分,专门用于定义和捕获指标数据。导入第三方库和应用程序代码的 OpenTelemetry 客户端的任何部分都被视为 API 的一部分。

SDK

SDK 是 OpenTelemetry 项目提供的 API 的实现,在应用程序中,SDK 由应用程序所有者安装和管理。请注意,SDK 包括额外的公共接口,这些接口不被视为 API 包的一部分,因为它们不是横切关注点,这些公共接口被定义为构造函数和插件接口:

  • 应用程序所有者使用 SDK 构造函数
  • 插件作者使用 SDK 插件接口
  • 仪器作者不得直接引用任何类型的任何 SDK 包,只能引用 API。

Semantic Conventions(语义约定)

语义约定定义了描述应用程序使用的常见概念、协议和操作的键和值,语义约定现在位于它们自己的存储库中:[https://github.com/open-telemetry/semantic-conventions](https://github.com/open-telemetry/semantic-conventions)
在这里插入图片描述
收集器和客户端库都应该将语义约定键和枚举值自动生成为常量(或语言惯用的等价物),在语义约定稳定之前,不应将生成的值分发到稳定的包中。YAML 文件必须用作生成的真实来源,每种语言实现都应该为代码生成器提供特定于语言的支持。
在这里插入图片描述
此外,规范所需的属性将在此处列出。

Contrib Packages(贡献包)

OpenTelemetry 项目与流行的 OSS 项目保持集成,这些项目已被确定为对观察现代 Web 服务很重要。示例API 集成包括用于 Web 框架、数据库客户端和消息队列的检测;示例 SDK 集成包括用于将遥测导出到流行的分析工具和遥测存储系统的插件。

OpenTelemetry 规范必须要有一些插件,例如 OTLP Exporters 和 TraceContext Propagators,这些必需的插件包含在 SDK 中。

可选且独立于 SDK 的插件和检测包称为 Contrib 包,API Contrib 是指完全依赖于 API 的包; SDK Contrib 是指仅依赖于 SDK 的包。

术语 Contrib 特指由 OpenTelemetry 项目维护的插件和工具的集合;它不涉及在别处托管的第三方插件。

版本控制和稳定性

OpenTelemetry 重视稳定性和向后兼容性。有关详细信息,请参阅版本控制和稳定性指南。

Tracing Signal(跟踪信号)

分布式跟踪是一组事件,由单个逻辑操作触发,跨应用程序的各个组件进行整合,分布式跟踪包含跨进程、网络和安全边界的事件。当有人按下按钮开始网站上的操作时,可能会启动分布式跟踪 - 在此示例中,跟踪将表示下游服务之间进行的调用,这些服务处理由按下此按钮启动的请求链。

Traces

OpenTelemetry 中的跟踪由其跨度隐式定义。特别地,Trace 可以被认为是 Spans 的有向无环图 (DAG),其中 Spans 之间的边被定义为父/子关系。例如,下面是由 6 个 Spans 组成的示例 Trace:

    Causal relationships between Spans in a single Trace
     
            [Span A]  ←←←(the root span)
                |
         +------+------+
         |             |
     [Span B]      [Span C] ←←←(Span C is a `child` of Span A)
         |             |
     [Span D]      +---+-------+
                   |           |
               [Span E]    [Span F]

有时使用时间轴更容易可视化跟踪,如下图所示:

    Temporal relationships between Spans in a single Trace
     
    ––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|> time
     
     [Span A···················································]
       [Span B··········································]
          [Span D······································]
       [Span C····················································]
             [Span E·······]        [Span F··]

Spans

跨度表示事务中的操作。每个 Span 封装了以下状态:

  • 操作名称
  • 开始和结束时间戳
  • 属性:键值对列表
  • 一组零个或多个事件,每个事件本身就是一个元组(时间戳、名称、属性),名称必须是字符串
  • 父母的 Span 标识符
  • 链接到零个或多个因果相关的 Spans(通过那些相关 Span 的 SpanContext)
  • 引用 Span 所需的 SpanContext 信息。见下文。

Span数据结构:

type Span struct {
    
    
    TraceID    int64 // 用于标示一次完整的请求id
    Name       string
    ID         int64 // 当前这次调用span_id
    ParentID   int64 // 上层服务的调用span_id  最上层服务parent_id为null
    Annotation []Annotation // 用于标记的时间戳
    Debug      bool
}

SpanContext

表示在 Trace 中标识 Span 的所有信息,并且必须传播到子 Span 并跨越进程边界,SpanContext 包含跟踪标识符和从父 Span 传播到子 Span 的选项。

  • TraceId 是跟踪的标识符,它由 16 个随机生成的字节组成,具有几乎足够的概率,是全球唯一的,TraceId 用于将特定跟踪的所有跨度分组到所有进程中。
  • SpanId 是跨度的标识符,通过将其制成 8 个随机生成的字节,它具有几乎足够的概率是全局唯一的,当传递给子跨度时,此标识符将成为子跨度的父跨度 ID。
  • TraceFlags 表示跟踪的选项。它表示为 1 个字节(位图)
    • 采样位 - 表示轨迹是否被采样的位(掩码 0x1)
  • Tracestate 在键值对列表中携带跟踪系统特定的上下文,Tracestate 允许不同的供应商传播附加信息并与他们的旧 Id 格式进行互操作,有关详细信息,请参阅此。

Spans之间的链接

一个跨度可以链接到零个或多个因果相关的其他跨度(由 SpanContext 定义),链接可以指向单个 Trace 内或跨不同 Trace 的 Spans,链接可用于表示批处理操作,其中一个 Span 由多个启动 Span 启动,每个 Span 表示批处理中正在处理的单个传入项。

使用链接的另一个示例是声明原始跟踪和后续跟踪之间的关系,当 Trace 进入服务的受信任边界并且服务策略需要生成新的 Trace 而不是信任传入的 Trace 上下文时,可以使用此方法,新链接的 Trace 也可能代表一个长时间运行的异步数据处理操作,它是由许多快速传入请求之一发起的。

当使用分散/聚集(也称为 fork/join)模式时,根操作会启动多个下游处理操作,并将所有这些操作聚合回单个 Span,最后一个 Span 链接到它聚合的许多操作,它们都是来自同一个 Trace 的 Span,类似于 Span 的 Parent 字段。但是,建议不要在这种情况下设置 Span 的 parent,因为从语义上讲,parent 字段表示单个父场景,在许多情况下,父 Span 完全包含子 Span,在分散/聚集和批处理场景中不是这种情况。

Metric Signal

OpenTelemetry 允许使用预定义的聚合和一组属性来记录原始测量或指标,使用 OpenTelemetry API 记录原始测量值允许最终用户决定应将哪种聚合算法应用于该指标以及定义属性(维度),它将在 gRPC 等客户端库中用于记录原始测量值“server_latency”或“received_bytes”。因此,最终用户将决定应从这些原始测量中收集哪种类型的聚合值,它可能是简单的平均或复杂的直方图计算。

使用 OpenTelemetry API 通过预定义聚合记录指标同样重要,它允许收集诸如 cpu 和内存使用率之类的值,或诸如“队列长度”之类的简单指标。

记录原始测量值

用于记录原始测量的主要类是 Measure 和 Measurement,可以使用 OpenTelemetry API 记录测量列表以及附加上下文,因此,用户可以定义聚合这些测量并使用一起传递的上下文来定义结果指标的其他属性。

  • Measure:度量描述了库记录的单个值的类型,它定义了公开度量的库和将这些单独的度量聚合为度量的应用程序之间的契约,度量由名称、描述和值的单位标识。
  • Measurement 描述了要为 Measure 收集的单个值,Measurement是 API 表面中的空接口,该接口在 SDK 中定义。

使用预定义聚合记录指标

所有类型的预聚合指标的基类称为 Metric,它定义基本的指标属性,如名称和属性。从 Metric 继承的类定义了它们的聚合类型以及单个测量或点的结构,API 定义了以下类型的预聚合指标:

  • Counter 用于报告测量的计数器指标,计数器值可以上升或保持不变,但永远不会下降;计数器值不能为负数。有两种类型的计数器度量值 - doublelong
  • Gauge metric 报告数值的瞬时测量,Gauge既可以上升也可以下降。仪表值可以是负数,有两种类型的计数器度量值 - doublelong

API 允许构建所选类型的指标。 SDK定义了查询导出Metric当前值的方式。每种类型的指标都有它的 API 来记录要聚合的值。 API 同时支持 - 设置指标值的推送和拉取模型。

Metrics数据模型和SDK

Metrics 数据模型在此处指定,基于 metrics.proto。该数据模型定义了三种语义:

  • API 使用的事件模型
  • SDK 和 OTLP 使用的飞行中数据模型
  • 表示导出器应如何解释飞行中模型的 TimeSeries 模型。

不同的导出器具有不同的功能(例如支持哪些数据类型)和不同的约束(例如属性键中允许使用哪些字符),指标旨在成为可能的超集,而不是随处支持的最低公分母。所有出口商都通过 OpenTelemetry SDK 中定义的指标生产者接口使用指标数据模型中的数据。

因此,指标对数据施加了最小的限制(例如,键中允许使用哪些字符),处理指标的代码应避免对指标数据进行验证和清理。相反,将数据传递到后端,依靠后端执行验证,并从后端传回任何错误。

有关详细信息,请参阅指标数据模型规范。

Log Signal

  • 数据模型
    日志数据模型定义了 OpenTelemetry 如何理解日志和事件。

Baggage Signal

除了跟踪传播之外,OpenTelemetry 还提供了一种用于传播名称/值对的简单机制,称为 Baggage;Baggage 用于索引一项服务中的可观察性事件,该服务具有同一事务中先前服务提供的属性,这有助于在这些事件之间建立因果关系。

虽然 Baggage 可用于对其他横切关注点进行原型设计,但该机制主要旨在为 OpenTelemetry 可观察性系统传达价值。

这些值可以从 Baggage 中使用,并用作指标的附加属性,或日志和跟踪的附加上下文,一些例子:

  • Web 服务可以受益于包含有关发送请求的服务的上下文
  • SaaS 提供商可以包含有关负责该请求的 API 用户或令牌的上下文
  • 确定特定浏览器版本与图像处理服务中的故障相关联

为了与 OpenTracing 向后兼容,Baggage 在使用 OpenTracing 桥接时作为 Baggage 传播,具有不同标准的新关注点应该考虑创建一个新的横切关注点来涵盖他们的用例,它们可能受益于 W3C 编码格式,但使用新的 HTTP 请求头在整个分布式跟踪中传送数据。

Resources

资源捕获有关为其记录遥测的实体的信息,例如,Kubernetes 容器公开的指标可以链接到指定集群、命名空间、pod 和容器名称的资源。

资源可以捕获实体标识的整个层次结构,它可能描述了云中的主机和特定的容器或进程中运行的应用程序。

请注意,某些进程标识信息可以通过 OpenTelemetry SDK 自动与遥测相关联。

上下文传播

所有 OpenTelemetry 横切关注点(例如跟踪和指标)共享一个底层上下文机制,用于在分布式事务的整个生命周期中存储状态和访问数据,查看上下文。

Propagators

OpenTelemetry 使用 Propagators 序列化和反序列化横切关注值,例如 Spans(通常只有 SpanContext 部分)和 Baggage,不同的传播器类型定义了特定传输施加的限制并绑定到数据类型。Propagators API 目前定义了一种 Propagator 类型:

  • TextMapPropagator 将值作为文本注入载体并从载体中提取值。

Collector(收集器)

OpenTelemetry 收集器是一组组件,可以从 OpenTelemetry 或其他监控/跟踪库(Jaeger、Prometheus 等)检测的进程中收集跟踪、指标和其他遥测数据(例如日志),进行聚合和智能采样,以及将跟踪和指标导出到一个或多个监控/跟踪后端。收集器将允许丰富和转换收集到的遥测数据(例如添加额外的属性或擦除个人信息)。

OpenTelemetry 收集器有两种主要的操作模式:

  • 代理(与应用程序一起在本地运行的守护进程)
  • 收集器(独立运行的服务)

在 OpenTelemetry 服务长期愿景中阅读更多内容。

检测库

该项目的初衷是让每个库和应用程序直接调用 OpenTelemetry API,从而开箱即用。然而,许多库不会有这样的集成,因此需要一个单独的库来注入这样的调用,使用包装接口、订阅特定库的回调或将现有遥测数据转换为 OpenTelemetry 模型等机制。为另一个库启用 OpenTelemetry 可观察性的库称为 Instrumentation 库。

检测库的命名应遵循检测库的任何命名约定(例如,Web 框架的“middleware”)。如果没有确定的名称,建议在包前加上“opentelemetry-instrumentation”,然后是检测库名称本身。例子包括:

    opentelemetry-instrumentation-flask (Python)
    @opentelemetry/instrumentation-grpc (Javascript)

忍着性子读到这里的读者想必已经打算放弃了,先别急,我们开始部署吧

猜你喜欢

转载自blog.csdn.net/u010230019/article/details/132543339
今日推荐