OpenTelemetry客户端设计规范
本文档定义了 OpenTelemetry 客户端设计的通用规范。目的是所有支持的语言的客户端保持统一,更容易使用,并且能允许保留对特定语言的特性支持的弹性。
OpenTelemetry 客户端的目标是让所有的功能都一个开箱即用,并且在创新型的功能和实验性功能上保持的扩展性。
请先阅读 overview 以了解 OpenTelemetry 架构的基本原理。
本文档不描述 OpenTelemetry 客户端 API 的功能和细节。此部分可以参阅 API specifications 。
OpenTelemetry 客户端作者请注意: OpenTelemetry 的规范、 API 和 SDK 的实现指引还在修订中。如果您发现了信息缺失、冲突、样式不一致或者其他缺陷,请在本仓库创建 issue 或者在 Gitter 上留言,以便文档的作者跟进问题。作为设计规范的实现者,通常您会对如何提升文档质量有更深入的理解,因此规范 SIG 和技术委员会成员会高度重视您的每一条意见和反馈。
要求
- OpenTelemetry API 必须是清晰明确的并且和实现解耦。这样最终用户可以仅仅理解 API 而不需要关系实现。(第2和第3点解释了原因)。
- 第三方库和框架的仅仅需要集成和依赖 OpenTelemetry 客户端 API。第三方库和框架的作者通常不关心(也无法知晓)OpenTelemetry 的最终使用场景和规范。
- 通常由最终的软件开发者来决定如何配置 OpenTelemetry SDK 和使用哪些插件。允许他们接入的程序或者库时可以选择不开启任何 OpenTelemetry 的功能。其最终目的是为了让使用者在即便不想使用 OpenTelemetry 的时候也能直接使用其内部集成了 OpenTelemetry 的第三方库和框架(所以,这就不需要框架开发者分开提供集成和未集成 OpenTelemetry 的版本)。
- SDK 必须把与协议无关的公共逻辑(比如:批处理、按进程信息打标签)和与协议相关的遥测 Exporter 隔离开。遥测 Exporter 必须仅包含最小功能块,以便厂商可以更容易地增加私有协议的支持。
SDK 实现应该包含以下的 Exporter:
- OTLP.
- Jaeger.
- Zipkin.
- Prometheus.
- 标准输出 (或日志) 以用于调试和测试,也可以用于集成日志代理工具。
内存 (Mock) Exporter ,可以用于在本地内存中收集和检查遥测数据。(比如用于单元测试)。
注: 上面有一些 Exporter 包含多种协议 (比如 gRPC , Thrift , 等等)。具体 Exporter 需要实现哪些协议还处于待定状态。
其他厂商定制化的 Exporter (实现了厂商私有协议) 不被包含在 OpenTelemetry 客户端列表中,其文档位于其他位置 (未来会确定保存和维护厂商定制化 Exporter 位置)。
OpenTelemetry 客户端通用设计模型
以下是 OpenTelemetry 客户端的通用设计模型 (调用关系):
Expected Usage
OpenTelemetry 客户端有4种 包 组成: API 包, SDK 包, 语义转换包, 以及插件包。 API 和 SDK 被拆分成了多个包, 每个包都基于单个类型 (比如: 一个用于 api-trace, 一个用于 api-metric, 一个用于 sdk-trace, 一个用于 sdk-metric) ,并且把 API 包和 the SDK 分开实现。
集成 OpenTelemetry 的库、框架、和应用仅需要依赖 API 包。第三方库的开发者通过调用API来产生遥测数据。
如果应用使用的第三方库集成了 OpenTelemetry API,它也能控制是否安装 SDK 来生成遥测数据。如果 SDK 为安转,API 调用应该不做任何事情且保持最小化开销。
为了保证在应用开启遥测时必须依赖 OpenTelemetry SDK 。应用必须配置 Exporter 和其他的插件以确保遥测模块可以生成正确的数据并且传递给其选择的分析工具。如果开启和配置插件的细节由语言规范约束。
API 和最小实现
API 包是自依赖的。即如果最终用户或者第三方库依赖依赖 API包,它可以在不加载SDK实现的情况下编译通过且正常运行,即便这种情况实际上不会生成和传递遥测数据。
自依赖的通过以下方式实现。
API 依赖包含API的最小实现。如果没有其他的实现被显式包含进应用,那么就不会手机任何数据。以下是刚才提及的组件的关系:
有一个非常重要的点是,这个API的最小实现返回的数据应该是有效的,并且不需要调用者做额外的检查(比如: createSpan()
方法不会失败并且总是返回一个有效的非空 Span
对象)。调用者不需要知道也无需单向这个最小实现的实现细节。这样能在集成过程中最小化实验代码和错误处理。
还有一个要点是最小化实现要尽可能减少开销。这样集成了 OpenTelemetry 的第三方库和框架在提供给用户时,即便用户不想开启 OpenTelemetry 功能,其开销也可以忽略不计。
SDK 实现
SDK 实现是一个独立(可选)的依赖项。当它被接入后,他将会替代掉同样的最小实现的 API 包(具体的替代机制因语言而异)。
SDK 实现是生成用于导出的遥测数据的 API 调用的核心功能。以下是当 SDK 功能开启后, OpenTelemetry 组件的结构:
SDK 定义了导出接口。协议专用的 Exporter 负责吧遥测数据发送到实现了改接口的后端。
如果需要的话,SDK 也可以包含一些辅助的 Exporter 用于组装一些附加的功能。
库的设计者需要基于 这个通用规范 定义语言专用的 Exporter
接口。
协议 Exporter
我们期望遥测服务后端的供应商来实现 导出接口。接收到的数据可以通过 Export()
函数来通过供应商专有的方式序列化并发送到后端。
我们鼓励供应商保持 Exporter 的协议规范尽可能简单,并且实现适当的扩展功能,比如排队机制和使用 SDK 提供的工具来做失败重试。
最合理的情况是让应用程序的最终用户可以在排队、重试、标签、批处理等功能中做出选择。比如,如果一个应用的遥测数据必须被发送到不保证可用性的远程的后端。用户可以选择使用一个本地持久化队列和一个可以在失败后重新发送数据的 Exporter
。或者另一种方案是应用可以把数据发送到一个本地的代理服务,这样最终用户就可以使用一个更简单的不包含重试和排队的导出配置。
SDK 应当被拆分成多个不同的库,除此以外,库的名字应当按相关技术的命名规范,把术语 “OpenTelemetry” 和 “Exporter” 包含在前缀中。
比如:
- Python 和 Java: opentelemetry-exporter-jaeger
- Javascript: @opentelemetry/exporter-jeager
资源检测
我们鼓励云服务提供商提供包来从环境中检测资源信息。这些包必须在 SDK 外实现。更多细节参见 资源 SDK
替代实现
最终用户的应用程序可能会想要依赖替代实现。
SDK 提供了一定的弹性和扩展功能并且被很多的实现使用了。在开发一个新的替代实现前,请再检视一下 OpenTelemetry 提供的扩展点。
一个替代实现的例子是自动化测试。可以使用一个 Mock 的实现加到自动化测试中去。比如,在内存里保存所有的遥测数据并提供来复杂这些保存的数据的能力。这样可以让测试用例来检查遥测数据是否正确。我们鼓励 OpenTelemetry 客户端的作者来提供类似这样的 Mock 实现。
注意: 需要 Mock 功能也可以通过使用 SDK 中的 Mock Exporter
而不需要换掉整个 SDK。
Mock 方案的选择取决于在测试目标和测试期间希望拦截哪些遥测数据。
版本标签
API 和 SDK 包必须采用语义化版本控制规范。API 包的版本号和 SDK 包的版本号是解耦的,所以可以不同(并且他们都可以和他们实现的规范的版本号不同)。API 和 SDK 包必须各自都有自己的版本标签。
解耦版本号管理可以让 OpenTelemetry 客户端的作者创建独立的 API 和 SDK 包,且不需要与规范的版本号相协调和匹配。
因为 API 和 SDK 包的版本号并不耦合,所以每个 API 和 SDK 发布包必须显式声明他们实现的规范版本。并且如果特定版本的 SDK 包仅兼容某个特定版本的 API 包,这些兼容性信息也必须由 OpenTelemetry 客户端的作者公布出来。OpenTelemetry 客户端的作者必须把这些兼容性信息公布在发行说明里。比如,SDK 包的发行说明里可以说“SDK 0.3.4 匹配 API 0.1.0,实现了 OpenTelemetry 规范 0.1.0”。
_TODO: 使用 OpenTelemetry 的第三方库的作者如何指引最终用户找到正确的 SDK 包?
性能和阻塞
API 实现中对性能的预估、实现策略和对低负载的时的行为描述见 性能和阻塞 的规格说明。
并发和线程安全
关于API 实现对并发安全的包保证,请参考各个组件特定的 API 规范指引和相关章节: