使用 OpenTelemetry 的 .NET 可观测性
运行应用时,你想了解应用的运行情况,并在潜在问题变大之前检测它们。 可以通过从应用发出遥测数据(例如日志或指标),然后监视和分析该数据来完成此目标。
什么是可观测性?
分布式系统上下文中的可观测性是指能够监视和分析有关每个组件状态的遥测数据,能够观测性能变化,并诊断这些变化发生的原因。 与调试不同,调试是侵入性的,可能会影响应用的操作,可观测性旨在对主操作透明,并且对性能的影响足够小,可以连续使用。
可观测性通常使用以下组合来实现:
- 日志,记录单个操作,例如传入请求、特定组件中的故障或正在下单的订单。
- 指标,用于测量计数器和仪表,例如已完成的请求数、活动请求数、已销售的小组件;或请求延迟的直方图。
- 分布式跟踪,用于跟踪分布式系统中各组件的请求和活动,以便查看花费的时间并跟踪特定故障的位置。
一起,日志、指标和分布式跟踪有时称为 可观测性的三大支柱。
每个支柱可能包括来自以下方面的遥测数据:
- .NET 运行时,例如垃圾回收器或 JIT 编译器。
- 库,例如来自 Kestrel(ASP.NET Web 服务器)和
HttpClient
。 - 由代码发出的特定于应用的遥测。
.NET 中的可观测性方法
有几种不同的方法可以在 .NET 应用中实现可观测性:
- 通过引用和使用 OpenTelemetry 等库,在代码中显式显示。 如果有权访问源代码并可以重新生成应用,那么这是最强大和可配置的机制。
- 进程外 EventPipe。 像 dotnet-monitor 这样的工具可以侦听日志和指标,然后在不影响任何代码的情况下处理它们。
- 使用启动挂钩,程序集可以被注入到进程中,然后可以收集检测。 这种方法的一个例子是 OpenTelemetry .NET 自动检测。
什么是 OpenTelemetry?
OpenTelemetry (OTel) 是用于收集和发出遥测数据的跨平台开放标准。 OpenTelemetry 包括:
- 用于库的 API,用于在代码运行时记录遥测数据。
- 应用开发者用来配置记录数据的哪一部分将通过网络发送,发送到哪里,以及如何对其进行筛选、缓冲、扩充和转换的 API。
- 语义约定为遥测数据的命名和内容提供了指导。 重要的是,产生遥测数据的应用和接收数据的工具要就不同类型数据表示什么以及什么类型的数据有用达成一致,以便这些工具能够提供有效的分析。
- 导出程序的接口。 导出程序是允许以特定格式将遥测数据传输到不同遥测后端的插件。
- OTLP 有线协议是用于传输遥测数据的供应商中性网络协议选项。 一些工具和供应商支持该协议,除了他们可能拥有的预先存在的专有协议之外。
使用 OTel 可以使用各种 APM 系统,包括开放源代码系统,如 Prometheus 和 Grafana、Azure Monitor - Microsoft 在 Azure 中的 APM 产品,或与 OpenTelemetry 合作的许多 APM 供应商。
大多数语言和平台都有 OpenTelemetry 实现,包括 .NET。
OpenTelemetry 的 .NET 实现
.NET OpenTelemetry 实现与其他平台有点不同,因为 .NET 在框架中提供了日志记录、指标和活动 API。 这表示 OTel 不需要为库创建者提供 API 以供使用。 .NET OTel 实现使用以下平台 API 进行检测:
- 适用于日志记录的 Microsoft.Extensions.Logging.ILogger<TCategoryName>
- 适用于指标的 System.Diagnostics.Metrics.Meter
- 适用于分布式跟踪的 System.Diagnostics.ActivitySource 和 System.Diagnostics.Activity。
OTel 的作用在于,它从这些 API 和其他来源(通过检测库)收集遥测数据,然后将其导出到应用程序性能监视 (APM) 系统中进行存储和分析。 OTel 作为行业标准带来的好处是,它是通用的收集机制,遥测数据的通用架构和语义,以及 APM 如何与 OTel 集成的 API。 使用 OTel 表示应用不需要使用 APM 特定的 API 或数据结构;其工作违反 OTel 标准。 APM 可以实现特定于 APM 的导出程序组件,也可以使用 OTLP,这是用于将遥测数据导出到 APM 系统的新有线标准。
OpenTelemetry 包
.NET 中的 OpenTelemetry 实现为一系列 NuGet 包,这些包形成了两个类别:
- 核心 API
- 检测 - 这些包从运行库和公共库中收集检测。
- 导出程序 - 这些与 APM 系统接口,如 Prometheus、Jaeger 和 OTLP。
下表介绍了主要包。
包名称 | 说明 |
---|---|
OpenTelemetry | 提供核心 OTEL 功能的主库 |
OpenTelemetry.Instrumentation.AspNetCore | ASP.NET Core 和 Kestrel 的检测 |
OpenTelemetry.Instrumentation.GrpcNetClient | gRPC 客户端用于跟踪出站 gRPC 调用的检测 |
OpenTelemetry.Instrumentation.Http | HttpClient 和 HttpWebRequest 的检测,用于跟踪出站 HTTP 调用 |
OpenTelemetry.Instrumentation.SqlClient | SqlClient 的检测,用于跟踪数据库操作 |
OpenTelemetry.Exporter.Console | 控制台的导出程序,通常用于诊断正在导出的遥测数据 |
OpenTelemetry.Exporter.OpenTelemetryProtocol | 使用 OTLP 协议的导出程序 |
OpenTelemetry.Exporter.Prometheus.AspNetCore | Prometheus 的导出程序使用 ASP.NET Core 终结点实现 |
OpenTelemetry.Exporter.Zipkin | 适用于 Zipkin 跟踪的导出程序 |
示例
本主题继续介绍在 .NET 中使用 OpenTelemetry 的几个示例演练:
- 示例:使用 OTLP 和独立的 Aspire 仪表板
- 示例:将 OpenTelemetry 与 Azure Monitor 和 Application Insights 配合使用
- 示例:将 OpenTelemetry 与 Prometheus、Grafana 和 Jaeger 配合使用
.NET Aspire 中的 OpenTelemetry
.NET Aspire 是 .NET 的一组扩展,便于创建和使用分布式应用程序。 使用 .NET Aspire 的好处之一是,遥测是内置的,使用适用于 .NET 的 OpenTelemetry 库。 .NET Aspire 的默认项目模板包含一个项目,其中一 ServiceDefaults
部分是设置和配置 OTel。 服务默认值项目由 .NET Aspire 解决方案中的每个服务引用和初始化。
服务默认值项目模板包括 OTel SDK、ASP.NET、HttpClient 和运行时检测包,以及该文件中 Extensions.cs
配置的项目模板。 对于导出遥测 .NET Aspire,默认情况下包括 OTLP 导出程序,以便它可以使用 Aspire 仪表板提供遥测可视化。
Aspire 仪表板旨在将遥测观察引入本地调试周期,使开发人员不仅能够确保应用程序生成遥测数据,还使用该遥测数据在本地诊断这些应用程序。 能够观察服务之间的调用在调试时与生产时一样有用。 当你从 Visual Studio 或dotnet run
AppHost
项目 F5 AppHost
项目时,将自动启动 .NET Aspire 仪表板。
有关 .NET Aspire 的更多详细信息,请参阅:
不使用 .NET Aspire 业务流程重用服务默认值项目
为 ASP.NET 项目配置 OTel 的最简单方法是使用 Aspire Service Defaults 项目,即使不使用 .NET Aspire 的其余部分(例如 AppHost)进行业务流程。 服务默认值项目通过 Visual Studio dotnet new
或作为项目模板提供。 它配置 OTel 并设置 OTLP 导出程序。 然后 ,可以使用 OTel 环境变量 将 OTLP 终结点配置为向其发送遥测数据,并为应用程序提供资源属性。
在 .NET Aspire 外部使用 ServiceDefault 的步骤如下:
- 使用 Visual Studio 中的“添加新项目”将 ServiceDefaults 项目添加到解决方案,或使用
dotnet new aspire-servicedefaults --output ServiceDefaults
- 从 ASP.NET 应用程序引用 ServiceDefaults 项目。 在 Visual Studio 中使用“添加 -> 项目引用”并选择 ServiceDefaults 项目”
- 将其 OpenTelemetry 安装程序函数作为应用程序生成器初始化的一部分调用。
var builder = WebApplication.CreateBuilder(args);
builder.ConfigureOpenTelemetry();
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
如果需要 AddServiceDefaults()
,服务默认值可以通过或特定函数设置以下附加功能:
- 运行状况检查和
/health
/alive
终结点 - 服务发现,在没有 .NET Aspire 的其余部分的情况下将不执行任何操作
- 为 HttpClient 配置复原能力,以便在发生故障时重试请求