为什么需要OpenTelemetry

  1. 分布式系统复杂性增加:随着云计算和微服务架构的普及,现代软件系统变得越来越复杂。在这样的系统中,一个请求可能会涉及多个服务和组件,跨越多个服务器和数据中心。因此,跟踪请求在系统中的路径和性能变得至关重要,以便定位和解决潜在的问题。
  2. 缺乏标准化的跟踪和监控解决方案:过去,每个厂商或项目可能会使用自己的监控工具和方法,导致了监控数据的碎片化和不一致性。OpenTelemetry的出现(OpenTracing和OpenCensus合并而来)为开发人员提供了一个统一的标准,使得跨不同系统和语言的监控数据能够更加一致和可比较。
  3. 提高系统的可观察性:可观察性是指对系统内部状态和行为的理解和监控程度。通过使用OpenTelemetry,开发人员可以更好地了解他们的系统在运行时的状态和行为,从而及时发现和解决潜在的问题,提高系统的可靠性和稳定性。

基本概念

可观测性

可观测性使我们能够通过提出关于某个系统的问题从外部了解该系统,而无需了解其内部工作方式,这需要应用程序能够发出跟踪日志指标信号,以便我们能提出相关的问题

日志(logs)

  1. 日志是由服务或其他组件发出的带时间戳的消息
  2. 日志不一定与任何特定的用户请求或事务相关联,区别于跟踪。
  3. 它们几乎存在于软件的各个地方,并且过去被开发人员和操作员广泛依赖,以帮助他们理解系统行为。在 OpenTelemetry 中,任何不属于分布式追踪或度量的数据都被视为日志。例如,事件(Events)是一种特定类型的日志。日志通常包含详细的调试/诊断信息,例如操作的输入、操作的结果以及与该操作有关的任何支持性元数据。
  4. 通常缺乏上下文信息,需要作为span的一部分或与跟踪和跨度相关联时,才更好发挥作用。

跟踪(Distributed Traces)

  1. 也称分布式跟踪,记录了请求(由应用程序或最终用户发起)在多服务架构中传播时所经过的路径,比如微服务和无服务器应用程序。
  2. 提高了我们应用程序或系统的健康状况的可见性,可以在分布式系统中确定性能问题的原因,或者调试在本地难以重现的行为
  3. 跟踪通过 分解请求在分布式系统中的传递过程 来便于调试和理解分布式系统
  4. 一个跟踪由一个或多个跨度组成。第一个跨度表示根跨度,每个根跨度表示从开始到结束的请求,更低层级的跨度提供了有关请求期间发生的更详细的上下文(或组成请求的步骤)的信息。

跨度(spans)

跨度跟踪请求所进行的具体操作,描绘了该操作执行期间发生了什么事情。包含名称、与时间相关的数据、结构化日志消息和其他元数据(即属性),以提供有关所跟踪操作的信息。如:

  1. 上下文(Context):span 的上下文包括了唯一标识该 span 的 ID,以及与其他 span 之间建立关联所需的信息,比如父 span 的 ID、当前跟踪(trace)的 ID 等。
  2. 属性(Attributes):属性是键值对,用于描述 span 的特征和元数据信息。例如,可以记录 span 的名称、开始时间、持续时间、所属服务的名称、请求的 URL 等。属性通常用于标识和分类 span,以及提供有关 span 执行上下文的其他信息。
  3. 事件(Events):事件是与 span 相关的时间戳和描述性消息的组合。它们用于记录 span 执行期间发生的重要事件,比如函数调用、数据库查询、网络请求等。通过记录事件,可以了解 span 的执行流程,以及在执行过程中发生的具体操作。
  4. 链接(Links):链接用于建立 span 之间的关系,通常用于描述跨越服务边界的操作。一个 span 可能会链接到其他 span,以表示它们之间的逻辑关联。例如,如果一个 span 包含了对外部服务的调用,可能会在该 span 中添加链接指向被调用服务的 span,以建立两者之间的关系。
  5. 状态(Status):状态用于表示 span 的执行结果。例如,一个 span 可能被标记为成功、失败或者取消。状态信息可以帮助了解 span 的执行情况,以及可能存在的问题或异常。
  6. 上下文传递(Context Propagation):上下文传递是指在分布式系统中跨越服务边界传递 span 上下文的过程。这包括了在网络请求中传递 span ID 和跨度 ID,以便在服务之间建立关联,并跟踪整个请求的执行流程。
  7. 种类(Span Kind):可取值Client, Server, Internal, Producer, 或 Consumer,为跟踪后端提供了一个关于应该如何组装跟踪的提示。

上下文传播(Context Propagation)

上下文传播是实现分布式追踪的核心概念。有了上下文传播,可以将 spans 相互关联并组装成一个追踪,而不管 spans 是在哪里生成的。我们通过两个子概念来定义上下文传播:Context 和 Propagation。

  1. Context(上下文) 是一个对象,它包含了发送和接收服务之间关联一个 span 所需的信息,并将其与整个追踪关联起来。例如,如果服务 A 调用服务 B,A创建的span中包含Trace ID和span ID,则B创建下一个span时,沿用该Trace ID,并且将自己的parent ID复制为A的span ID,表示当前创建的span的父级是A创建的span
  2. Propagation(传播) 是在服务和进程之间传递上下文的机制。它将上下文对象序列化或反序列化,并提供相关的追踪信息,以将其从一个服务传播到另一个服务中。

指标(metrics)

  1. 指标是在运行时捕获的服务的度量,即可以用于观测应用程序运行状态的数据集。捕获度量的时刻被称为指标事件,它不仅包括度量本身,还包括捕获时的时间和关联的元数据。
  2. 应用程序和请求指标是可用性和性能的重要指标。自定义指标可以提供洞察力,了解可用性指标如何影响用户体验或业务。收集的数据可用于发出故障警报或在需求高峰时自动触发调度决策,以扩展部署规模。
  3. 组件:
        - Metric Provider:是Meter的工厂。在大多数应用程序中,Meter Provider只会初始化一次,其生命周期与应用程序的生命周期相匹配。
        - Meter创建指标工具Metric Instruments
        - Metric Instrument用于捕获度量Metric,有多种类别,例如计数器,仪表盘,直方图等
        - Metric Exporter将度量数据发送给消费者。这个消费者可以是用于调试和开发时的标准输出,也可以是OpenTelemetry收集器或您选择的任何开源或供应商后端
        - 获取metric并发送给消费者的链路可描述如下:Metric Provider--->Meter--->Metric Instruments--->Metric--->Metric Exporter--->Consumer

行李(baggage)

  1. Baggage 是 Span 之间传递的上下文信息。它是一个键值存储,与 Trace 中的 Span Context 一起驻留,使值可用于在该 Trace 中创建的任何 Span 。
  2. Baggage区别于SpanContext:
        - Baggage允许将键值对数据(例如用户ID、会话ID等)附加到跨越多个服务的请求中,并在请求链中传递,通常用于传递与请求相关的元数据。相当于为其他信号(signals)提供了一个存储额外信息的容器。
        - Span Context是跨度(Span)之间传播的元数据的容器,用于将跨度连接起来形成请求链。由跨度创建和管理,一旦创建了 Span,它们就是不可变的。
  3. Baggage存储在与当前上下文一起的 HTTP 标头中,会有被篡改或者泄露的风险,应该被用于可以公开的数据。

组件(Components)

规范(Specification)

  1. API: 为生成和关联跟踪、度量和日志数据定义了数据类型和操作。
  2. SDK: 为 API 的特定语言实现定义了要求。此处还定义了配置、数据处理和导出的概念。
  3. 数据: 定义了 OpenTelemetry 协议(OTLP)和供应商无关的语义约定, OpenTelemetry并不提供可视化和存储服务,规范数据格式约定可以满足数据在各后端存储供应商之间高效低成本的迁移等操作。

收集器(Collectors)

  1. 用于接收和处理来自应用程序的跟踪、度量和日志数据。
  2. 可以用于预处理、聚合、过滤和路由数据,然后将其导出到配置的一个或多个后端系统。

K8s 运算符

OpenTelemetry 运算符是 Kubernetes 运算符的一种实现。该运算符管理 OpenTelemetry 收集器,并使用 OpenTelemetry 对工作负载进行自动仪表化。

函数即服务资产

OpenTelemetry 支持不同云供应商提供的监控函数即服务的各种方法。OpenTelemetry 社区目前提供了预构建的 Lambda layer,能够自动仪表化您的应用程序,还提供了用于手动或自动仪表化应用程序时可以使用的独立 Collector Lambda layer。

特定语言的 API & SDK 实现

  1. 仪表库(Instrumentation Libraries)
        - 这些库用于在特定编程语言的应用程序中自动或手动地集成分布式追踪、度量和日志记录功能。它们提供了针对特定语言和框架的 API 和工具,使开发人员能够轻松地将追踪和监视功能集成到他们的应用程序中。
  2. 导出器(Exporters)
        - 针对特定语言的 SDK 实现通常会包括用于将收集的跟踪、度量和日志数据导出到后端存储和分析系统的导出器。这些导出器可以与特定语言的常见后端系统集成,如数据存储、监控系统等。
  3. 自动仪表化(Automatic Instrumentation)
        - 一些特定语言的 SDK 实现可能会提供自动仪表化功能,这使得开发人员可以轻松地自动检测和仪表化应用程序的组件,无需手动添加代码。
  4. 资源探测器(Resource Detectors)
        - 这些组件用于自动发现和识别运行应用程序的环境和基础设施,以帮助收集有关应用程序的上下文信息。它们可以帮助开发人员更好地理解和监视他们的应用程序在不同环境中的运行情况。
  5. 跨服务传播器(Cross-Service Propagators)
        - 特定语言的 SDK 实现可能会包括用于在分布式系统中传播跟踪上下文的传播器,以确保请求链中的所有跨度都与同一跟踪相关联。
  6. 采样器(Samplers)
        - 一些特定语言的 SDK 实现可能会包括采样器,用于控制跟踪数据的收集率,以确保系统在大规模部署时能够有效地处理和存储跟踪数据。

资源

  1. 资源(Resource)是描述应用程序、服务或系统的特性和属性的实体。
  2. 资源提供了有关应用程序运行环境的关键信息,如应用程序的名称、版本、运行环境、部署位置等。
  3. 资源通常是与跟踪、度量和日志记录等监视数据相关联的一部分。

采样

  1. 分布式跟踪很多时候并不需要跟踪所有的请求流程,甚至很大一部分的成功请求对分析系统中潜在的问题并没有什么实际作用,因此并不总是需要大量的数据来获得正确的洞察力,而只需要正确的或者说可能有用的数据样本。
  2. 采样的核心思想是控制发送到可观察性后端的跨度,以降低摄取成本。
  3. 常见的采样方法有首部采样和尾部采样。对于某些系统,尾部采样可能与首部采样一起使用,以保护遥测流程免受过载的影响。

首部采样

  1. 首部采样是一种在请求链的开始阶段进行的采样方法。当请求进入系统时,采样器会决定是否记录该请求的起始跨度。如果采样器决定记录起始跨度,则整个请求链路上的所有跨度都会被记录。如果采样器决定不记录起始跨度,则整个请求链路上的跨度都不会被记录。
  2. 首部采样的优点是简单高效,可以有效地减少跟踪数据的生成量。但是,它可能会导致某些请求的完整跟踪数据丢失,从而降低了跟踪数据的完整性。

尾部采样

  1. 尾部采样是一种在请求链的结束阶段进行的采样方法。当请求完成时,采样器会根据请求的特性和其他因素决定是否记录该请求的终止跨度。如果采样器决定记录终止跨度,则整个请求链路上的所有跨度都会被记录。如果采样器决定不记录终止跨度,则整个请求链路上的跨度都不会被记录。
  2. 尾部采样的优点是可以根据请求的实际情况和性能特征进行决策,从而更好地控制跟踪数据的生成率。但是,由于需要等待请求完成,因此尾部采样可能会导致一些延迟,并且在某些情况下可能无法获得完整的跟踪数据。并且,因为系统的复杂性等原因需要频繁调整采样策略,可能很难实现。

仪表范围

仪表范围在 OpenTelemetry 中的作用是定义了遥测数据的上下文和关联。它是应用代码中的逻辑单元,与发出的遥测数据相关联,也就是定义了数据(信号)的来源等相关信息

  1. 在应用程序代码中,可以选择模块、包或类作为仪表范围
  2. 对于库或框架,可以使用唯一的标识符作为仪表范围,例如库或框架的完全限定名称和版本
  3. 从提供者获取跟踪器(Tracer)、计量器(Meter)或记录器(Logger)实例时,通常会为仪表范围定义一个名称和版本对。创建的每个跨度(span)、指标(metric)或日志记录(log record)都会与提供的仪表范围相关联。
  4. 使用仪表范围,可以将遥测数据进行切片和切割,以便在可观测性后端中更好地理解和分析应用程序的行为和性能。例如,可以查看特定库版本的性能指标,或者将问题定位到应用程序的特定模块。