OpenTelemetry 介绍
OpenTelemetry(简称 OTel)是由 CNCF(云原生计算基金会)孵化的开源项目,旨在提供统一的可观测框架和工具集(APIs、SDK),用于生成、收集、处理、传输遥测数据(Telemetry Data),包括指标(Metrics)、追踪(Traces)和日志(Logs),帮助用户分析应用程序的性能和行为。OpenTelemetry 是由 OpenTracing(Uber)和 OpenCensus(Google)两大可观测框架合并后的产物,具备厂商无关性,已成为云原生系统中可观测性(Observability)领域的工业级标准。其架构如下图所示:
主要包含如下3个部分:
- Instrumentation:支持API(一组抽象接口并无实现,无法单独运行的类库)、SDK(对API的具体实现,能单独运行的服务)、零代码(类似代理机制,具体语言实现方式不同,针对特定库如HTTP、RPC、数据库访问、消息队列访问)方式使用 OpenTelemetry
- OTLP: OpenTelemetry 定义的数据传输协议
- OpenTelemetry Collector:是一个厂商无关的服务,用于收集(Receiver)、处理(Processor)和传输(Exporter)遥测数据。它可以作为应用的Sidecar或者单独的代理进程运行,接收不同来源的遥测数据,并将其导出到多种后端系统(如 Prometheus、Jaeger、Zipkin 等)进行存储、分析。
核心功能
数据模型
- Traces:记录请求在分布式系统中的访问路径,包含 Trace ID 和 Span(操作单元)信息。
- Span:一次具体访问路径,包含开始/结束时间、标签(Tags)、事件(Events)、状态(Status)。
- Trace:记录一次请求,每个Trace会关联一个或多个Span。
- Metrics:数值指标(如 CPU 使用率、请求速率)。
- 支持 Counter、Gauge、Histogram 等指标类型。
- Logs:结构化日志,支持与 Traces 关联(通过 Trace ID 进行关联),方便问题定位。
传输协议
- **OTLP(OpenTelemetry Protocol)**:统一的遥测数据传输协议,支持 gRPC 和 HTTP。
- 兼容性:可无缝对接 Prometheus、Zipkin、Jaeger 等后端存储分析系统。
数据采集(Instrumentation)
- 手动埋点:OpenTelemetry 提供了一组 API接口,允许开发者在应用程序中插入遥测数据收集代码,同时支持多种编程语言。
from opentelemetry import trace tracer = trace.get_tracer("my_tracer") with tracer.start_as_current_span("custom_operation"): # 业务逻辑
- 自动埋点:SDK 实现了 API接口具体功能,通过集成 SDK,应用程序自动采集框架(如 HTTP 调用、RPC 调用、数据库调用)的遥测数据。
- 目前支持的编程语言:Java、Python、Go、.NET、Node.js 等。
数据管理
- Processor:对遥测数据进行过滤、聚合或转换,支持自定义数据处理逻辑。
- Batch Processor:批量压缩数据,减少网络开销。
- Simple Processor:直接转发原始数据。
- Exporter:将数据发送到后端存储分析系统(如 Jaeger、Prometheus、Zipkin等)。
# 配置导出到 Jaeger exporters: jaeger: endpoint: "jaeger:14250" insecure: true
核心优势
- 标准化
- 统一 指标(Metrics)、追踪(Traces)、日志(Logs) 的采集、处理与传输,终结了多套 SDK 并存的混乱局面;
- 支持指标数据(Metrics)收集、处理,如请求计数、延迟等指标帮助宏观上快速发现系统问题;
- 支持分布式追踪数据(Traces)收集和处理,允许开发者追踪请求在微服务架构中的调用链,帮助识别性能瓶颈、定位故障;
- 支持日志数据(Logs)收集、处理,提供全面的观察系统运行情况、定位故障能力。
- 多语言支持
- 支持多种编程语言,例如 Java、JavaScript、Python、Go、C# 等,在不同技术栈中使用相同的遥测数据采集框架,不会因技术栈不同导致可观测技术体系碎片化。
- 功能灵活扩展
- 通过 收集器(Collector) 组件实现遥测数据接收、路由、过滤和转发,支持自定义 Processor 和 Exporter来处理、传输遥测数据。
- 云原生友好
- 原生支持 Kubernetes、Service Mesh(如 Istio)等云原生技术框架。
使用场景
分布式追踪(Distributed Tracing)
- 问题定位:追踪微服务调用链,快速定位延迟或故障。
- 故障排查:分布式追踪功能可以帮助开发者快速定位故障,了解请求的详细处理流程。
- 依赖分析:可视化微服务调用关系(如通过 Jaeger UI)。
性能监控(Performance Monitoring)
- 指标聚合:统计吞吐量、错误率、延迟分布(P90/P99)。
- 告警联动:通过对接 Prometheus、Grafana 实现数据实时告警。
- 通过收集和分析指标,开发者可以监控应用程序的性能,及时发现和解决问题。
日志关联(Log Correlation)
- Trace-Driven Logging:通过 Trace ID 关联日志信息,还原请求的完整上下文信息。
// 日志示例 {"trace_id": "4bf92f35...", "message": "DB query failed", "level": "error"}
基础设施监控
- Kubernetes 监控:采集 Pod/Node 资源指标,结合 OpenTelemetry Collector (配置Prometheus接收器(Receiver)定时抓取)实现基础设施监控及应用监控数据的统一收集处理。
生态与工具
- OpenTelemetry Collector
- 负责接收、处理、导出数据,支持插件化方式扩展数据处理逻辑
- 该组件是可选组件(如果没有Collector,应用集成SDK、API之后可直接对接存储分析系统如ElasticSearch、Jaeger、Prometheus等),用于集中式收集、处理、导出遥测数据。
- 可视化工具
- Prometheus/Grafana:指标数据(Metrics)监控与仪表盘。
- Jaeger:分布式追踪数据(Traces)可视化(如微服务调用链)。
- Elasticsearch/Fluentd:日志数据(Logs)存储与分析。
- 服务网格集成
- 与微服务网格框架 Istio、Linkerd 集成,自动采集微服务之间调用请求性能指标和追踪数据。
部署与使用
OpenTelemetry Collector 部署模式
- Sidecar 模式:通过 Kubernetes 平台在每个应用程序 Pod 中部署 OpenTelemetry Collector,减少应用侵入性。
- Gateway 模式:集中式 OpenTelemetry Collector 集群,统一收集所有遥测数据并转发到不同后端存储分析系统。
指标数据(Metrics)示例
在代码中使用OpenTelemetry API生成度量指标数据(Metrics),将指标数据(Metrics)以 Prometheus 兼容格式输出到 localhost:8080/metrics 页面,Prometheus 实例定时抓取该页面指标数据进行存储、分析。
package main
import (
"context"
"log"
"net/http"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/controller/push"
"go.opentelemetry.io/otel/sdk/resource"
"go.opentelemetry.io/otel/exporters/prometheus"
)
func main() {
// 创建 Prometheus 导出器
exporter, err := prometheus.New()
if err != nil {
log.Fatalf("failed to create Prometheus exporter: %v", err)
}
// 创建资源
res, err := resource.New(context.Background(), resource.WithAttributes())
if err != nil {
log.Fatalf("failed to create resource: %v", err)
}
// 创建指标控制器
controller := push.New(
controller.WithExporter(exporter),
controller.WithResource(res),
controller.WithCollectPeriod(2*time.Second),
)
// 启动控制器
if err := controller.Start(context.Background()); err != nil {
log.Fatalf("failed to start controller: %v", err)
}
defer func() {
if err := controller.Stop(context.Background()); err != nil {
log.Fatalf("failed to stop controller: %v", err)
}
}()
// 注册 Prometheus HTTP 处理程序
http.Handle("/metrics", exporter)
go func() {
log.Fatal(http.ListenAndServe(":8080", nil))
}()
// 创建一个计数器
meter := otel.Meter("example-meter")
counter := metric.Must(meter).NewInt64Counter("example_counter")
// 模拟指标收集
for {
counter.Add(context.Background(), 1)
time.Sleep(1 * time.Second)
}
}
追踪数据(Traces)示例
在代码中使用OpenTelemetry API生成请求调用追踪数据(Traces),并将追踪数据(Traces)写入Jaeger进行可视化分析。
package main
import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/jaeger"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)
func main() {
// 1. 创建 Jaeger Exporter
exporter, _ := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint("jaeger:14268/api/traces")))
// 2. 配置 Trace Provider
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(resource.NewWithAttributes("service.name", "my-app")),
)
otel.SetTracerProvider(tp)
// 3. 业务代码埋点
tracer := otel.Tracer("main")
ctx, span := tracer.Start(context.Background(), "hello-span")
defer span.End()
}
日志数据(Logs)示例
在代码中使用OpenTelemetry API生成日志数据(Logs),将日志数据(Logs)导出到支持 OTLP 的后端,例如 localhost:4317(可使用 OpenTelemetry Collector,统一收集后导出到 ElasticSearch)。
package main
import (
"context"
"log"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/sdk/resource"
"go.opentelemetry.io/otel/sdk/log"
"go.opentelemetry.io/otel/exporters/otlp"
"google.golang.org/grpc"
)
func main() {
// 创建 OTLP 导出器
ctx := context.Background()
conn, err := grpc.Dial("localhost:4317", grpc.WithInsecure())
if err != nil {
log.Fatalf("failed to create gRPC connection: %v", err)
}
exporter, err := otlp.NewExporter(otlp.WithGRPCConn(conn))
if err != nil {
log.Fatalf("failed to create OTLP exporter: %v", err)
}
// 创建资源
res, err := resource.New(ctx, resource.WithAttributes())
if err != nil {
log.Fatalf("failed to create resource: %v", err)
}
// 创建日志记录器
logger := log.New(
log.WithResource(res),
log.WithExporter(exporter),
log.WithFlushInterval(5*time.Second),
)
// 启动日志记录器
if err := logger.Start(ctx); err != nil {
log.Fatalf("failed to start logger: %v", err)
}
defer func() {
if err := logger.Stop(ctx); err != nil {
log.Fatalf("failed to stop logger: %v", err)
}
}()
// 生成日志
for {
logger.Info("This is an info log message")
logger.Error("This is an error log message")
time.Sleep(2 * time.Second)
}
}
总结
OpenTelemetry 通过标准化可观测数据的采集、处理与传输,成为构建 可观测性体系 的基石。无论是微服务、Serverless 还是传统单体应用,均可通过 OTel 构建可观测能力,帮助应用开发者处理故障诊断、性能分析、性能优化、根因定位,其强大的社区支持和灵活的扩展能力,使其成为云原生时代 不可或缺的工具。