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
/同线程的函数之间传递context
event
和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
的冰山一角, 更多功能可以参考官方文档以及后续的更新