65.9K
CodeProject 正在变化。 阅读更多。
Home

OpenTelemetry,缺失的要素

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2022年11月8日

CPOL

9分钟阅读

viewsIcon

10069

OpenTelemetry 如何弥合我们的代码与可观测性后端选项之间的差距

第一部分:现代可观测性问题
第二部分:OpenTelemetry,缺失的要素

引言

第一部分中,我们探讨了现代系统(微服务、可组合架构、事件驱动、共享组件——所有这些都能很好地解决问题的好东西)面临的可观测性挑战。但它们真的很难支持。我们强调了正确数据检测的重要性,并得出结论:有许多优秀的可观测性解决方案,包括开源和商业的。但它们都以自己的方式行事,大大降低了我们灵活适应的能力——让我们的老对手供应商锁定趁虚而入。

在本文中,我们将探讨 OpenTelemetry 如何弥合我们的代码与可观测性后端选项之间的鸿沟,支持**摆脱特定于供应商的工具**来生成和导出遥测数据。

快速回顾

在开始之前,让我们回顾一下第一部分中的术语

**检测**是产生遥测数据的方式。当我们谈论检测时,我们指的是向我们的应用程序添加库和/或代码以收集日志、指标和跟踪等遥测数据。

**遥测数据**是对系统行为或内部工作原理的洞察——系统发出的关于“黑匣子”内部发生情况的数据,通过检测收集。您可能还会听到这些被称为信号。

一种供应商中立的标准

OpenTelemetry(OTel)的核心是一种跨语言的、供应商中立的遥测标准。您只需对代码进行一次检测,然后当您的需求发生变化时,就可以轻松切换到其他可观测性后端。

这也意味着您可以在坚持选择的后端的同时,更改您使用的语言——所有支持的语言都将遵循相同的API规范进行检测。

不仅仅是供应商中立的标准

OTel 还提供了**完整的端到端实现**,用于生成、发出、收集、处理和将遥测数据导出到任何受支持的可观测性后端。对于目前支持的每种语言,都有核心库、自动检测库和导出器。

核心库

**API** 是检测的骨干接口——不会有实际的遥测数据发送到后端。之所以这样做,是因为希望检测其代码的第三方库不应关心消费应用程序如何实现其 OpenTelemetry。

**SDK** 是完整的语言库,提供 API 的实现,因此我们可以手动检测我们的代码。它是我们直接引入应用程序的东西。它不实现导出器,导出器是依赖于 SDK 的独立库。替代的检测在实现 API 的独立库中可用。

通常,我们希望通过 OTel 连接到可观测性后端的任何应用程序,都将通过对检测库和导出器的依赖,间接依赖于这两个组件。

检测库

即插即用,适用于许多常用库和框架,例如 Web 和数据库框架。例如,我们可以自动为 ASP.NET Core 入站 Web 请求和出站 Entity Framework 请求生成遥测数据。只需添加两个包

  • OpenTelemetry.Instrumentation.AspNetCore
  • OpenTelemetry.Contrib.Instrumentation.EntityFrameworkCore

并将它们作为服务添加到代码中

public void ConfigureServices(IServiceCollection services)
{
    services.AddOpenTelemetryTracing((builder) => builder
        .AddAspNetCoreInstrumentation()
        .AddEntityFrameworkCoreInstrumentation()
        // Add your exporter(s) here
    );
}

OTel 项目在其每个语言的主仓库中维护关键 OSS 项目的检测和导出器包,并符合 OTel 规范。对于 .NET,这是 open-telemetry/opentelemetry-dotnet。许多其他包则来自姊妹贡献仓库,对于 .NET,这是 open-telemetry/opentelemetry-dotnet-contrib

导出器

导出器是将检测到的遥测数据发送到后端的库。这可以通过 OpenTelemetry Protocol (OTLP) 本身实现——这也是长期目标*——或者特定于供应商的,例如 Jaegar 或 Azure Monitor,其中导出器库会将内存中的 OpenTelemetry 数据转换为供应商工具使用的格式。这些类型的导出器的可用性使得规划和执行向 OTLP 的过渡变得更加容易。

*供应商正越来越多地提供对原生 OTLP 直接入站的全面支持。请参阅此列表以获取更新。Jaeger 文档现在甚至声明

引用

截至2022年,Jaeger SDK 不再受支持,建议所有用户迁移到 OpenTelemetry。

厂商中立的追踪

在调试分布式系统时,我面临的最大挑战之一是如何获得事务通过所有相关服务的完整端到端旅程的可视性。

第一部分中,我们引入了分布式跟踪作为任何可观测性解决方案的关键部分,以解决这个问题。我们承认有许多开源和商业产品已经通过在事务中的所有操作之间传播跟踪 ID 来将所有内容关联起来。

但通常情况下,我们最终得到的是一幅不完整的图景,业务部门将其视为一种风险,尽管支持工作量增加了。一些常见的原因包括:

  • 混合技术栈上的服务需要不同的解决方案,资源限制阻碍了我们对所有服务进行检测
  • 供应商锁定,我们选择的后端不支持我们某些服务的技术栈
  • 用于检测和发送遥测数据的客户端和代理是内部构建的,资源限制阻碍了我们为所有服务技术栈维护它们。

作为技术栈和后端单一标准,OTel消除了这些挑战。它带来了一套完整的工具,这些工具确实可以简单地即插即用,大大减少了所需的资源,而且由于它是一个开放标准,切换到(或添加)其他后端所需的资源非常少。

OpenTelemetry 如何进行追踪

OTel 使用**span**的概念来表示系统中跟踪中的每个操作。在OTel 规范中定义的其他内容中,每个 span 将包含

  • 当前事务在系统中整个“旅程”的唯一跟踪 ID
  • span 本身的唯一 ID
  • 父 span 的唯一 ID,以便我们可以在可观测性后端重构旅程

每个span代表系统中整体事务中的一个操作。大多数后端会以您可能从甘特图中熟悉的方式,根据时间来表示这些操作。

在这个简化示例中

  1. **Span A**:请求进入服务 A 以获取用户详细信息。这是**根 Span**,当然也是**Span B**的父级。大多数主流 Web 框架都能够自动检测这一点,这意味着它将自动为此入站请求创建一个跟踪 Span。
  2. **Span B**:服务 A 调用服务 B 获取用户详细信息。我们可以通过库自动检测 HTTP 调用,也可以手动在发出调用的代码“周围”添加跟踪信号。
  3. **Span C**:服务 B 收到请求。
  4. **Span D**:在处理请求的代码内部,一个子 Span 表示对数据库进行用户详细信息查询的 SQL 查询。
  5. **Span E**:我们手动检测一个信号,用于在未找到用户时添加用户。
  6. **Span F**:服务 B 已返回用户详细信息,服务 A 将该数据返回给调用方,这由我们的 Web 框架自动检测。

厂商中立的上下文传播

OTel 使用** baggage** 的概念,它标准化了跨编程语言和平台共享值的上下文格式,消除了团队为传播共享数据开发自定义解决方案的需求。

例如,如果只有“服务 A”知道用户 ID,我们可以将其放入“baggage”中,以便“服务 B”在作为子/依赖项被调用时可以访问它。

收集器:一个厂商中立的代理

在我看来,这个系统中的明星是**收集器**。虽然大多数语言都有直接将遥测数据发送到后端的导出器(这在开发过程中很好),但将数据快速卸载到收集器以处理资源密集型任务(例如)是有益的,例如

  • 导出到多个位置
  • 用元数据增强
  • 批处理
  • 加密
  • 后端无响应时的缓冲和重试
  • 控制流到后端以允许服务继续工作

收集器可以使用 OpenTelemetry 协议 (OTLP) 和专有协议,以多种格式接收和导出数据,并将其发送到可观测性工具。它通过充当接收器、处理器和导出器的**管道**来实现这一点。

接收器

接收器是将遥测信号从源头摄入到收集器中,然后进行处理并发送到可观测性后端的方式。

核心接收器用于使用 OTLP 的遥测,但贡献仓库中还有许多其他接收器可用于支持供应商格式并将其转换为 OTLP。

  • 一个文件日志接收器,它将跟踪并解析文件中的日志。
  • 一个Jaeger 接收器,如果您有现有的服务将跟踪导出到 Jaegar,这些跟踪可以重定向到您的收集器,并与现有 Jaegar 实例一起导出到新的后端。
  • 一个Kubernetes 集群接收器,用于从 k8s API 服务器收集集群级指标。

处理器

处理器可以在接收和导出数据之间运行。一些例子:

  • 一个编辑处理器,可以配置为防止敏感信息泄露到跟踪中。
  • 一个k8s 属性处理器,可以自动用 k8s 元数据标记通过收集器的遥测数据。
  • 一个批处理处理器,用于减少传输到后端使用的出站连接数量。

导出器

与应用程序直接使用的库类似,这些库用于将数据从收集器发送到可观测性后端或其他目的地。

除了核心 OTLP 导出器外,贡献仓库中还有许多可用的导出器。

Sidecar 模式

下面是一个典型用例的快照。我们有一个 .NET Web 应用程序,使用 OTLP 将日志、指标和跟踪导出到收集器。它还展示了我们如何选择在继续输出文件日志的同时进行过渡,使用文件日志接收器将它们拉入收集器。

这种部署方法是将一个收集器与每个服务一对一部署,与服务的生命周期共享。这倾向于将收集器的所有权归属于开发团队,并且如果您需要进行特定于服务的处理,则非常有用。

我们的收集器可以被设置为一个管道,将这些数据导出到我们选择的后端。

该管道的配置将如下所示(完整配置文件

service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [otlp, elasticsearch/trace]
    logs:
      receivers: [otlp]
      exporters: [otlp, elasticsearch/log, file/rotation_with_default_settings]
    metrics:
      receivers: [otlp]
      exporters: [otlp, prometheus]

作为单个网关

也可以将收集器部署为独立的**网关**组件,独立于服务进行扩展。这通常意味着收集器的所有权归平台团队所有,他们可以集中管理策略和权限。

理想的设置是每个服务或服务集合都有专用的收集器作为代理,由开发团队拥有。这些代理将导出到一个由运维团队作为网关运行的实例,以应用他们自己的流程,例如身份验证或元数据。

摘要

无论是开源还是商业的可观测性解决方案,在满足支持复杂现代架构的需求方面都做得很好。尚未解决的大问题是缺乏标准,这降低了我们灵活适应的能力,导致了某种程度的供应商锁定。

OpenTelemetry 是缺失的要素,它将显著改变现有格局。它非常容易采纳,具有真正的即插即用体验,并且通过库在专有协议和 OpenTelemetry 之间进行转换,提供了良好的过渡支持。

在某个时候,我将回顾 OpenTelemetry 在 .NET 中的现状。现在,启动我的演示仓库,尝试使用 OpenTelemetry 与 .NET 和 Azure Monitor。

历史

  • 2022年11月8日:初始版本
© . All rights reserved.