概述
本文档提供了 OpenTelemetry 项目的概述,并定义了重要的基础术语。
其他术语定义可在术语表中找到。
OpenTelemetry 客户端架构

在最高架构层面,OpenTelemetry 客户端被组织成信号。每种信号都提供一种专门的可观察性形式。例如,跟踪、指标和 baggage 是三种独立的信号。信号共享一个共同的子系统——上下文传播——但它们之间独立运行。
每种信号都为软件提供了一种描述自身的方式。代码库,例如 Web 框架或数据库客户端,会依赖各种信号来描述自身。OpenTelemetry 仪器代码可以混合到该代码库中的其他代码中。这使得 OpenTelemetry 成为一种横切关注点——一种为了提供价值而被混合到许多其他软件中的软件。横切关注点,就其本质而言,违反了一个核心设计原则——关注点分离。因此,OpenTelemetry 客户端设计需要额外的谨慎和关注,以避免给依赖这些横切 API 的代码库带来问题。
OpenTelemetry 客户端的设计目的是将每种信号中必须作为横切关注点导入的部分与可以独立管理的部分分离开来。OpenTelemetry 客户端还被设计成一个可扩展的框架。为了实现这些目标,每种信号都由四种类型的包组成:API、SDK、语义约定和 Contrib。
API
API 包由用于仪器的横切公共接口组成。OpenTelemetry 客户端中任何被导入到第三方库和应用程序代码的部分都被视为 API 的一部分。
SDK
SDK 是 OpenTelemetry 项目提供的 API 的实现。在应用程序中,SDK 由应用程序所有者安装和管理。请注意,SDK 包含其他公共接口,这些接口不被视为 API 包的一部分,因为它们不是横切关注点。这些公共接口被定义为构造函数和插件接口。应用程序所有者使用 SDK 构造函数;插件作者使用 SDK 插件接口。仪器作者绝对不应该直接引用任何 SDK 包,只能引用 API。
语义约定
语义约定定义了描述应用程序使用的常见概念、协议和操作的键值。
语义约定现在位于其自己的存储库中:https://github.com/open-telemetry/semantic-conventions
收集器和客户端库都应该将语义约定键和枚举值自动生成到常量(或语言习惯用法)中。生成的值不应在稳定包中分发,直到语义约定稳定为止。必须使用YAML文件作为生成的来源。每种语言实现都应该为代码生成器提供特定于语言的支持。
此外,规范要求的属性将在此处列出。
Contrib 包
OpenTelemetry 项目维护了与流行的 OSS 项目的集成,这些项目被认为对于观察现代 Web 服务很重要。例如,API 集成包括 Web 框架、数据库客户端和消息队列的仪器。例如,SDK 集成包括导出遥测数据到流行分析工具和遥测存储系统的插件。
某些插件,例如 OTLP Exporters 和 TraceContext Propagators,是 OpenTelemetry 规范所必需的。这些必需的插件包含在 SDK 中。
可选的、与 SDK 分开的插件和仪器被称为Contrib包。API Contrib指仅依赖于 API 的包;SDK Contrib指还依赖于 SDK 的包。
Contrib 一词特指 OpenTelemetry 项目维护的插件和仪器集合;它不指代托管在其他地方的第三方插件。
版本控制与稳定性
OpenTelemetry 重视稳定性和向后兼容性。请参阅版本控制与稳定性指南了解详情。
跟踪信号
分布式跟踪是一组事件,由单个逻辑操作触发,并在应用程序的各个组件之间进行整合。分布式跟踪包含跨越进程、网络和安全边界的事件。当有人点击按钮启动网站上的某个操作时,可能会启动一个分布式跟踪——在这个例子中,跟踪将代表处理此按钮点击所启动的请求链的下游服务之间的调用。
追踪
OpenTelemetry 中的跟踪由其Span隐式定义。特别是,一个Trace可以看作是Span的有向无环图(DAG),其中Span之间的边由父/子关系定义。
例如,以下是一个由 6 个Span组成的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]
有时,通过时间轴可视化Trace会更容易,如下面的图所示。
Temporal relationships between Spans in a single Trace
––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–> time
[Span A···················································]
[Span B··········································]
[Span D······································]
[Span C····················································]
[Span E·······] [Span F··]
Span
Span 代表事务中的一个操作。每个Span封装以下状态:
- 操作名称
- 开始和结束时间戳
- 属性:键值对列表。
- 零个或多个事件的集合,每个事件本身都是一个元组(时间戳、名称、属性)。名称必须是字符串。
- 父Span标识符。
- 链接到零个或多个因果相关的Span(通过相关Span的SpanContext)。
- 引用 Span 所需的SpanContext信息。见下文。
SpanContext
表示标识Trace中Span的所有信息,并且必须传播到子 Span 和跨进程边界。SpanContext包含跟踪标识符以及从父 Span 传播到子 Span 的选项。
- TraceId是跟踪的标识符。通过生成 16 个随机字节,其在全球范围内具有实际足够高的唯一性。TraceId 用于将特定跟踪的所有 Span 组合在一起,跨越所有进程。
- SpanId是 span 的标识符。通过生成 8 个随机字节,其在全球范围内具有实际足够高的唯一性。当传递给子 Span 时,此标识符成为子Span的父 span ID。
- TraceFlags表示跟踪的选项。它表示为 1 个字节(位图)。
- 采样位 - 用于表示跟踪是否被采样的位(掩码
0x1)。
- 采样位 - 用于表示跟踪是否被采样的位(掩码
- Tracestate以键值对列表的形式承载特定于跟踪系统的上下文。Tracestate允许不同的供应商传播额外信息并与他们的旧 ID 格式互操作。有关更多详细信息,请参阅此处。
Span 之间的链接
一个Span可以链接到零个或多个其他Span(由SpanContext定义),这些Span具有因果关系。Links可以指向单个Trace内的Span,也可以指向不同Trace之间的Span。Links可用于表示批量操作,其中一个Span由多个初始Span触发,每个Span代表正在处理的批量中的单个传入项。
使用Link的另一个例子是声明源跟踪和后续跟踪之间的关系。当Trace进入服务受信任边界,并且服务策略要求生成新跟踪而不是信任传入的跟踪上下文时,可以使用此方法。新链接的跟踪也可能代表由许多快速传入请求之一启动的长期异步数据处理操作。
在使用 scatter/gather(也称为 fork/join)模式时,根操作启动多个下游处理操作,所有这些操作都聚合回一个Span中。最后一个Span链接到它聚合的许多操作。它们都是来自同一跟踪的Span。这类似于Span的 Parent 字段。然而,在这种情况下,建议不要设置Span的父项,因为从语义上讲,父字段表示单个父项场景,并且在许多情况下,父Span完全包含子Span。在 scatter/gather 和批量场景中并非如此。
指标信号
OpenTelemetry 允许记录原始测量值或具有预定义聚合和属性集的指标。
使用 OpenTelemetry API 记录原始测量值赋予最终用户选择给定指标聚合算法的灵活性。此功能在 gRPC 等客户端库中特别有用,它允许记录“server_latency”或“received_bytes”等原始测量值。最终用户然后可以自主决定这些原始测量值的聚合方法,选项范围从简单的平均值到更复杂的直方图计算。
记录原始测量值
使用 OpenTelemetry API 记录原始测量值所涉及的主要组件是Measurement、Instrument和Meter。Meter从MeterProvider获取并用于创建Instrument,而Instrument负责捕获测量值。
+------------------+
| MeterProvider | +-----------------+ +--------------+
| Meter A | Measurements... | | Metrics... | |
| Instrument X +-----------------> In-memory state +-------------> MetricReader |
| Instrument Y | | | | |
| Meter B | +-----------------+ +--------------+
| Instrument Z |
| ... | +-----------------+ +--------------+
| ... | Measurements... | | Metrics... | |
| ... +-----------------> In-memory state +-------------> MetricReader |
| ... | | | | |
| ... | +-----------------+ +--------------+
+------------------+
Instruments
Instrument用于报告Measurement,并通过名称、类型、描述和值单位进行标识。
有几种类型的指标仪器适用于特定用例,例如用于递增值的计数器、用于捕获当前值的仪表以及用于捕获测量值分布的直方图。仪器可以是同步的,意味着它们由应用程序逻辑内联调用;或者异步的,其中用户注册一个回调函数,该函数由 SDK 按需调用。
指标数据模型和 SDK
指标数据模型在此处指定,并基于metrics.proto。此数据模型定义了三种语义:API 使用的事件模型,SDK 和 OTLP 使用的进行中的数据模型,以及表示导出器如何解释进行中的模型的 TimeSeries 模型。
不同的导出器具有不同的功能(例如,支持哪些数据类型)和不同的约束(例如,属性键中允许哪些字符)。指标旨在成为可能内容的超集,而不是普遍支持的最低公分母。所有导出器都通过 OpenTelemetry SDK 中定义的 Metric Producer 接口从 Metrics Data Model 消耗数据。
因此,Metrics 对数据施加了最小的约束(例如,键中允许哪些字符),处理 Metrics 的代码应避免验证和清理 Metrics 数据。相反,将数据传递给后端,依靠后端执行验证,并将后端返回的任何错误传递回来。
有关更多信息,请参阅指标数据模型规范。
Views (视图)
视图是指定如何处理、聚合和导出Instrument数据的配置。它们可以通过MeterProvider进行配置。View允许在默认收集行为之外定制指标数据,从而实现指标的特定聚合、转换和过滤。
日志信号
数据模型
日志数据模型定义了 OpenTelemetry 如何理解日志和事件。
Baggage 信号
除了跟踪传播之外,OpenTelemetry 还提供了一种简单的机制来传播名称/值对,称为Baggage。Baggage旨在通过同一事务中先前的服务提供的属性来索引一个服务中的可观察性事件。这有助于在这些事件之间建立因果关系。
虽然Baggage可用于原型化其他横切关注点,但此机制主要用于向 OpenTelemetry 可观察性系统传达值。
这些值可以从Baggage中获取,并用作指标的附加属性,或者日志和跟踪的附加上下文。一些示例:
- Web 服务可以受益于包含发送请求的服务周围的上下文
- SaaS 提供商可以包含有关负责该请求的 API 用户或令牌的上下文
- 确定特定浏览器版本与图像处理服务中的故障相关联
为了与 OpenTracing 向后兼容,在使用 OpenTracing bridge 时,Baggage 会作为Baggage传播。具有不同标准的新关注点应考虑创建新的横切关注点来覆盖其用例;它们可以受益于 W3C 编码格式,但使用新的 HTTP 标头在分布式跟踪中传递数据。
资源
Resource捕获有关为其记录遥测信息的实体的信息。例如,Kubernetes 容器暴露的指标可以链接到指定集群、命名空间、Pod 和容器名称的资源。
Resource可以捕获整个实体标识层次结构。它可以描述云中的主机和特定容器或正在进程中运行的应用程序。
请注意,一些进程识别信息可以由 OpenTelemetry SDK 自动与遥测关联。
Context Propagation
所有 OpenTelemetry 的横切关注点,例如跟踪和指标,都共享一个底层的Context机制,用于在分布式事务的整个生命周期中存储状态和访问数据。
有关更多信息,请参阅Context。
传播器
OpenTelemetry 使用Propagators来序列化和反序列化横切关注点值,例如Span(通常仅是SpanContext部分)和Baggage。不同的Propagator类型定义了特定传输所施加的限制,并绑定到数据类型。
Propagators API 目前定义了一种Propagator类型:
TextMapPropagator将值注入文本载体或从中提取文本。
Collector
OpenTelemetry 收集器是一组组件,可以从 OpenTelemetry 或其他监控/跟踪库(Jaeger、Prometheus 等)进行仪器的进程中收集跟踪、指标以及最终其他遥测数据(例如日志),进行聚合和智能采样,并将跟踪和指标导出到一个或多个监控/跟踪后端。收集器将允许丰富和转换收集到的遥测数据(例如,添加其他属性或删除个人信息)。
OpenTelemetry 收集器有两种主要操作模式:Agent(作为应用程序本地运行的守护程序)和 Collector(独立的运行服务)。
有关更多信息,请参阅 OpenTelemetry Collector 的长期愿景。
仪器库
该项目的灵感来自于让每个库和应用程序开箱即用地可观察,让它们直接调用 OpenTelemetry API。然而,许多库将不会有这种集成,因此需要一个单独的库来注入这些调用,使用诸如包装接口、订阅库特定的回调或将现有遥测数据转换为 OpenTelemetry 模型等机制。
启用另一个库的 OpenTelemetry 可观察性的库称为仪器库。
仪器库的命名应遵循被仪器库的任何命名约定(例如,Web 框架的“middleware”)。
对于托管在 OpenTelemetry 存储库中的仪器,建议使用“opentelemetry-instrumentation”作为包的前缀,后跟被仪器库本身的名称。例如:
- opentelemetry-instrumentation-flask (Python)
- @opentelemetry/instrumentation-grpc (Javascript)
未由 OpenTelemetry 托管的仪器库应避免与 OpenTelemetry 托管的包发生潜在的命名冲突。例如,它们可以在仪器包名称前加上其公司或项目名称作为前缀
- {company}-opentelemetry-instrumentation-{component} (Python)
- @{company}/opentelemetry-instrumentation-{component} (Javascript)
有关更多信息,请参阅仪器库。