1 基本介绍
OpenTelemetry 是一个帮助开发者 监控 和 追踪应用程序 的开源工具。它能收集应用程序的各种数据,比如 日志(应用程序的输出信息)、指标(比如请求数量、CPU 使用率)和 追踪信息(记录请求的整个过程)。这些数据可以用来了解应用的运行状况和性能问题。
OpenTelemetry 对程序员有什么用?
- 发现问题:通过追踪应用中的请求流程,程序员可以快速找到性能瓶颈或异常。
- 监控应用健康状态:通过收集应用的日志和性能指标,帮助程序员实时监控应用的运行情况。
- 优化性能:根据收集的数据,程序员可以发现慢的操作或服务,进行针对性的优化。
2 核心概念
在 OpenTelemetry 中,有几个核心概念对于实现分布式追踪、监控和日志记录至关重要,分别是 Context & Propagation,Span,以及 Signals(包括 Traces、Metrics、Logs、Baggage)。以下是对这些概念的介绍:
2.1 Context & Propagation
- Context:在分布式系统中,
Context代表一个请求的上下文信息,用于在各个服务、进程或线程之间携带追踪信息。它允许不同服务在处理请求时共享同一条追踪线索。Context中可以包含追踪的标识信息(如Trace ID、Span ID),以及一些额外的数据(如Baggage)。 - Propagation:
Propagation是上下文的传播机制,用于在系统的不同部分之间传递追踪信息。它的主要作用是确保在请求跨越多个服务时,追踪信息能够继续传播,从而实现端到端的分布式追踪。OpenTelemetry 支持多种 Propagation 格式,例如 W3C Trace Context 和 Baggage 规范。
2.2 Span
- Span 是 OpenTelemetry 中最基本的追踪单位,它表示系统中操作或事件的一个时段。每个
Span都会记录以下关键信息:- 操作名称:描述当前操作或事件的名称。
- 开始时间和持续时间:记录操作从何时开始、进行了多长时间。
- Span ID 和 Trace ID:唯一标识这个
Span及其所属的整个追踪链(Trace)。 - 父级 Span:
Span可以是其他Span的子级,这样可以形成一个Span树,表示请求在各个服务或模块中的调用关系。 - Attributes:描述
Span的一些键值对属性,如 HTTP 状态码、请求路径等。 - Events:记录在
Span的生命周期中发生的特定事件。 - Links:可以将当前
Span与其他Span关联。
2.3 Signals (Traces, Metrics, Logs, Baggage)
在 OpenTelemetry 中,Signals(包括 Traces、Metrics、Logs 和 Baggage)是核心的观测数据类型。每种 Signal 的采集、处理和导出都依赖于 Provider、Exporters 等组件,而 Span 是 Traces 的基础单元。这些组件协作,确保系统的可观测性数据能够被正确采集和传输。以下是对 Signals、Provider、Exporters 和 Span 之间关系的详细说明:
2.3.1 Traces (追踪)
Traces 是 OpenTelemetry 中用于跟踪单个请求或事务如何在分布式系统中流动的信号。Trace 由多个 Span 组成,每个 Span 代表一次操作的时间段。
- Provider: 对于
Traces来说,TracerProvider是负责创建Tracer对象的组件。Tracer用于创建和管理Span。通常在应用程序的初始化过程中会设置一个全局的TracerProvider。 - Span:
Span是构成Trace的基础单位,包含该操作的开始时间、持续时间、父子关系等信息。开发者可以通过Tracer创建Span,标识代码中某一段操作的开始和结束。 - Exporters:
Span结束后,采集的数据会传递给Exporter。Exporter是将追踪数据(Span)发送到外部系统(如 Jaeger、Zipkin 或其他追踪平台)的组件。通过Exporter,可以选择如何持久化或分析这些追踪信息。
举例来说,当一个 HTTP 请求到达服务器时,应用会生成一个 Span 来记录这个请求的处理过程。每当请求跨服务时,就会创建新的 Span,并将其与前一个 Span 链接形成完整的 Trace。最终,通过 Exporter,这些 Trace 会被发送到外部平台进行分析。
2.3.2 Metrics (指标)
Metrics 用于监控系统的性能和行为。它们通过定量数据(如请求数、延迟、内存使用量等)来帮助开发人员理解系统的健康状况。
- Provider:
MeterProvider是Metrics数据的核心提供者,它负责创建Meter对象。Meter则是用于创建和记录Metrics的接口。 - Metrics Instruments:
Meter允许开发者定义和操作不同类型的指标工具,例如Counter(计数器),Histogram(直方图)和Gauge(测量仪)。这些工具用于采集和聚合系统的运行数据。 - Exporters: 采集到的
Metrics需要通过MetricsExporter导出到外部监控平台(如 Prometheus、Datadog)。Exporter可以定期将指标数据推送到外部系统,以便进行持续监控和报警。
例如,应用可以定义一个 Counter 来跟踪总请求数,使用 Histogram 来记录请求的延迟分布。这些数据通过 Exporter 发送到 Prometheus 等平台,可以实时监控应用的运行状态。
2.3.3 Logs (日志)
Logs 是时间序列事件的记录,通常用于捕获应用程序中的具体操作或错误。与 Span 和 Metrics 结构化的数据不同,日志通常是非结构化的,但在调试和故障排查中非常有价值。
- Provider: 日志的管理由
LoggerProvider负责,LoggerProvider会生成Logger对象。开发者可以通过Logger记录应用的运行状态、异常信息等。 - Logs Data Model:
OpenTelemetry的日志数据模型包括时间戳、事件描述和上下文信息,类似于Span的一些属性。Logger可以将这些信息捕获并存储。 - Exporters: 日志数据通过
LogsExporter导出到外部系统(如 Elasticsearch、Splunk),从而实现集中化的日志存储与查询。
开发者可以在特定时间点记录日志信息,例如在发生错误时生成一条日志。这些日志可以与 Traces 和 Metrics 一起使用,以帮助更快速地定位系统问题。
2.3.4 Baggage (上下文信息)
Baggage 是 OpenTelemetry 中的一种特殊机制,用于跨服务传播键值对信息。与 Span 和 Metrics 不同,Baggage 通常不用于直接观测,而是携带与请求相关的元数据。
- Propagation:
Baggage的数据随着Trace在分布式系统中传播。每个服务都可以在处理请求时读取或修改这些数据。Baggage可以帮助服务之间共享一些全局上下文信息,例如用户 ID、地理位置等。 - Provider:
Baggage并没有专门的Provider,它作为Context机制的一部分,通常与Trace一起传播。 - Exporters:
Baggage数据通常不会直接导出到外部系统,但可以作为Span的一部分包含在Trace数据中,通过Trace Exporter进行传递和分析。
Provider、Exporters 与 Span 的关系:
- Provider: 在每种信号的上下文中,
Provider是核心管理器,负责生成适当的Tracer(用于Traces)、Meter(用于Metrics)或Logger(用于Logs)。Provider控制整个信号的采集流程,定义了如何创建、记录和传递这些数据。- Exporters: 无论是
Span(Traces)、Metrics还是Logs,所有的观测数据最终都需要通过Exporter发送到外部的观测平台。Exporter决定了数据的出口方向,比如将Span数据发送到 Jaeger,将Metrics发送到 Prometheus。- Span 的作用: 对于
Traces而言,Span是核心单位。它用于记录和表示请求的生命周期和调用链。通过Span的聚合,形成完整的Trace,从而帮助开发者追踪和分析请求在分布式系统中的路径与延迟。这三者共同组成了
OpenTelemetry的观测数据流程:**Provider负责生成观测信号实例,Span等信号用于记录和标识系统中的操作,Exporter最终将这些数据发送到外部系统以供分析和监控。**
3 实战
这里我使用Rust语言,使用opentelemetry-rust库,来实现一个简单的demo。官方的Rust的demo太简陋了, 所以这里我基于官方的代码写了一个稍微复杂一点的demo。
demo主要演示作用:
- 初始化
provider和exporter http/同线程的函数之间传递contextevent和metric的记录- 导出数据
demo完整代码: dice_server
3.1 依赖
1 | [package] |
3.2 初始化provider和exporter
1 | fn init_meter_provider() -> Result<opentelemetry_sdk::metrics::SdkMeterProvider, MetricsError> { |
3.3 http之间传递context
http之间传递context的本质是将context信息注入到http的header中, 官方提供的demo使用的是hyper库, 其注入过程很简单, 但这里我使用日常开发中更常用的actix-web库, 所以这里需要自己实现http之间的context传递:
1 | use opentelemetry::Context; |
这个函数的主要目的是将追踪上下文注入到 HTTP 请求头中,以便在分布式系统中传递追踪信息:
1 | let mut request = awc::Client::default().get("http://127.0.0.1:8080/gen_num"); |
当然, 在另一个http的接收端, 需要将context从http的header中提取出来:
1 | fn extract_context(req: &HttpRequest) -> Context { |
接收端路由函数可以如下处理:
1 |
|
同线程之间传递
context
直接传递Context的引用即可
3.4 父子Context关系的生成
不同函数调用之间以及http之间, 需要生成父子Context关系, 这样方便在span中查看调用关系, 这里我实现了一个简单的函数来生成父子Context:
1 | fn get_cx_from_parent_cx<'a>( |
3.5 记录event和metric
3.5.1 event记录事件
使用Context.span方法即可对event进行记录或操作
1 |
|
3.5.2 metric记录指标
metric需要先初始化指标, 这里以Counter为例:
1 | // 定义一个结构体来保存我们的计数器 |
路由函数的操作:
1 |
|
3.6 导出数据和可视化
这里借助jaeger来可视化数据, 可以使用docker来快速启动jaeger服务:
1 | docker run -d -p16686:16686 -p4317:4317 -e COLLECTOR_OTLP_ENABLED=true jaegertracing/all-in-one:latest |
访问http://127.0.0.1:16686即可看到可视化界面:
4 总结
OpenTelemetry 是一个功能强大的分布式追踪和度量库,它提供了一套统一的 API 和 SDK,支持多种语言和平台。通过 OpenTelemetry,开发者可以方便地在分布式系统中进行追踪和监控,从而更好地理解和优化系统性能。
这里仅仅演示了opentelemetry的冰山一角, 更多功能可以参考官方文档以及后续的更新