技术博客

OpenTelemetry 2026 正式毕业:四大可观测性支柱统一实战指南

2026 年 5 月,CNCF 宣布 OpenTelemetry 正式毕业,成为云原生可观测性的事实标准。OTel 现在统一了四大信号:Traces(链路追踪)、Metrics(指标)、Logs(日志)、Continuous Profiling(持续性能剖析,2026 年进入 RC)。本文讲解 OpenTelemetry 的核心架构、SDK 接入(Python/Go)、Collector 配置与部署、与 Prometheus/Jaeger/Grafana 的集成,以及在 Kubernetes 上的完整可观测性方案落地。

OpenTelemetry可观测性TracesMetricsLogsPrometheusJaegerKubernetes

2026 年 5 月 21 日,CNCF 宣布 OpenTelemetry 正式毕业(Graduation),与 Kubernetes、Prometheus、Envoy 并列为 CNCF 顶级项目。

这不只是一个里程碑——它意味着 OTel 的 API、SDK 和 OTLP 协议已足够稳定,适合在生产环境中全面采用,不再需要担心频繁的 Breaking Change。

更重要的是:OpenTelemetry 现在统一了四大可观测性信号。Traces、Metrics、Logs 早已 GA,Continuous Profiling(持续性能剖析)在 2026 年 Q1 进入 Release Candidate。这是历史上第一次,一个开放标准把所有可观测性维度都纳入同一个 SDK 和传输协议(OTLP)。


为什么选 OpenTelemetry

在 OTel 之前的问题:
  每个可观测性工具有自己的 SDK
  Jaeger SDK + Prometheus client + 自定义日志库 = 三套 SDK 都要装
  换 APM 工具?全部代码重写

OTel 的解法:
  一套 SDK,对接所有后端(Jaeger/Zipkin/Tempo/Grafana/Datadog...)
  一种协议(OTLP),所有支持 OTel 的后端都能接收
  换后端不改应用代码,只改 Collector 配置

2026 年现状:
  48.5% 的组织已经在使用 OpenTelemetry
  Python OTel SDK 过去 12 个月下载超过 13 亿次
  所有主流云厂商(AWS/Azure/GCP)原生支持 OTLP

核心架构

应用端(SDK):
  应用代码 → OTel SDK(自动/手动埋点)
  → 生成 Traces/Metrics/Logs/Profiles
  → 通过 OTLP 发送到 Collector

OTel Collector(中间层):
  接收来自应用的遥测数据
  做数据处理(过滤/采样/转换/富化)
  转发到多个后端(Prometheus/Jaeger/Loki/Grafana...)

后端(存储和展示):
  Traces:Jaeger / Grafana Tempo
  Metrics:Prometheus / Grafana Mimir
  Logs:Grafana Loki / Elasticsearch
  Profiling:Pyroscope(Grafana 旗下)
  展示:Grafana(统一 Dashboard)

SDK 接入

Python 自动埋点(零代码修改)

# 安装自动埋点包
pip install opentelemetry-distro opentelemetry-exporter-otlp

# 为常见框架安装自动插件(Flask/Django/requests/SQLAlchemy 等)
opentelemetry-bootstrap -a install
# 方式一:启动时自动注入(不修改应用代码)
# opentelemetry-instrument python app.py
# 环境变量配置:
# OTEL_SERVICE_NAME=my-service
# OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
# OTEL_TRACES_EXPORTER=otlp
# OTEL_METRICS_EXPORTER=otlp
# OTEL_LOGS_EXPORTER=otlp

# 方式二:代码中手动配置(更灵活)
from opentelemetry import trace, metrics
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader

# 初始化 Tracer
tracer_provider = TracerProvider()
tracer_provider.add_span_processor(
    BatchSpanProcessor(OTLPSpanExporter(endpoint="http://otel-collector:4317"))
)
trace.set_tracer_provider(tracer_provider)
tracer = trace.get_tracer("my-service")

# 初始化 Meter
metric_reader = PeriodicExportingMetricReader(
    OTLPMetricExporter(endpoint="http://otel-collector:4317"),
    export_interval_millis=30000
)
meter_provider = MeterProvider(metric_readers=[metric_reader])
metrics.set_meter_provider(meter_provider)
meter = metrics.get_meter("my-service")

# 使用示例
request_counter = meter.create_counter("http_requests_total")
request_latency = meter.create_histogram("http_request_duration_seconds")

def handle_request(request):
    with tracer.start_as_current_span("handle_request") as span:
        span.set_attribute("http.method", request.method)
        span.set_attribute("http.url", request.url)
        
        request_counter.add(1, {"method": request.method, "path": request.path})
        
        import time
        start = time.time()
        response = process(request)
        duration = time.time() - start
        
        request_latency.record(duration, {"status": str(response.status_code)})
        span.set_attribute("http.status_code", response.status_code)
        return response

Go SDK 接入

package main

import (
    "context"
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
    "go.opentelemetry.io/otel/sdk/resource"
    "go.opentelemetry.io/otel/sdk/trace"
    semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
)

func initTracer(ctx context.Context) (*trace.TracerProvider, error) {
    // 创建 OTLP gRPC 导出器
    exporter, err := otlptracegrpc.New(ctx,
        otlptracegrpc.WithEndpoint("otel-collector:4317"),
        otlptracegrpc.WithInsecure(),
    )
    if err != nil {
        return nil, err
    }

    // 定义服务资源属性
    res := resource.NewWithAttributes(
        semconv.SchemaURL,
        semconv.ServiceName("my-go-service"),
        semconv.ServiceVersion("1.0.0"),
    )

    tp := trace.NewTracerProvider(
        trace.WithBatcher(exporter),
        trace.WithResource(res),
        trace.WithSampler(trace.TraceIDRatioBased(0.1)), // 采样率 10%
    )
    otel.SetTracerProvider(tp)
    return tp, nil
}

// 使用 tracer
func doWork(ctx context.Context) {
    tracer := otel.Tracer("my-go-service")
    ctx, span := tracer.Start(ctx, "doWork")
    defer span.End()

    span.SetAttributes(
        attribute.String("key", "value"),
        attribute.Int("count", 42),
    )
    // 实际业务逻辑...
}

OTel Collector 配置

Collector 是 OTel 架构的核心,负责接收、处理、转发遥测数据。

# otel-collector-config.yaml
receivers:
  otlp:                    # 接收来自应用的 OTLP 数据
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

  prometheus:              # 也可以抓取 Prometheus 格式的指标
    config:
      scrape_configs:
      - job_name: 'node-exporter'
        static_configs:
        - targets: ['node-exporter:9100']

processors:
  batch:                   # 批量发送,减少连接开销
    timeout: 10s
    send_batch_size: 1024

  memory_limiter:          # 防止 Collector OOM
    limit_mib: 400
    spike_limit_mib: 100
    check_interval: 5s

  resourcedetection:       # 自动添加 K8s 环境信息(Pod/Node/Namespace)
    detectors: [k8snode, env]
    timeout: 2s

  filter/drop_health:      # 过滤掉健康检查的 trace(减少噪音)
    traces:
      span:
      - 'attributes["http.route"] == "/health"'
      - 'attributes["http.route"] == "/ready"'

exporters:
  otlp/jaeger:             # 发送 Traces 到 Jaeger
    endpoint: jaeger-collector:4317
    tls:
      insecure: true

  prometheusremotewrite:   # 发送 Metrics 到 Prometheus
    endpoint: http://prometheus:9090/api/v1/write

  loki:                    # 发送 Logs 到 Loki
    endpoint: http://loki:3100/loki/api/v1/push

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, resourcedetection, filter/drop_health, batch]
      exporters: [otlp/jaeger]

    metrics:
      receivers: [otlp, prometheus]
      processors: [memory_limiter, resourcedetection, batch]
      exporters: [prometheusremotewrite]

    logs:
      receivers: [otlp]
      processors: [memory_limiter, resourcedetection, batch]
      exporters: [loki]

在 Kubernetes 上部署 Collector

# 以 DaemonSet 部署 Collector(每个节点一个)
# 适合采集节点级别的日志和指标

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: otel-collector
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: otel-collector
  template:
    metadata:
      labels:
        app: otel-collector
    spec:
      serviceAccountName: otel-collector
      containers:
      - name: collector
        image: otel/opentelemetry-collector-contrib:0.113.0
        args:
        - --config=/conf/config.yaml
        ports:
        - containerPort: 4317    # OTLP gRPC
          protocol: TCP
        - containerPort: 4318    # OTLP HTTP
          protocol: TCP
        - containerPort: 8888    # Collector 自身的 Prometheus 指标
          protocol: TCP
        resources:
          requests:
            cpu: "100m"
            memory: "200Mi"
          limits:
            cpu: "500m"
            memory: "500Mi"
        volumeMounts:
        - name: config
          mountPath: /conf
      volumes:
      - name: config
        configMap:
          name: otel-collector-config

---
# Service(应用通过这个地址发送数据)
apiVersion: v1
kind: Service
metadata:
  name: otel-collector
  namespace: monitoring
spec:
  selector:
    app: otel-collector
  ports:
  - name: otlp-grpc
    port: 4317
    targetPort: 4317
  - name: otlp-http
    port: 4318
    targetPort: 4318

新特性:Continuous Profiling(持续性能剖析)

OTel 2026 年最重要的新增信号——Profiling 在 Q1 进入 RC 状态。

什么是 Continuous Profiling:
  持续采集应用在生产环境中的 CPU/内存/goroutine 使用情况
  和 Traces 关联:看到慢请求时,直接找到是哪个函数慢了
  
对比传统 Profiling 工具(pprof/py-spy):
  传统:需要手动触发,只能查看某一时刻的快照
  Continuous Profiling:一直在跑,出问题时回溯历史数据

OTel Profiling 信号(RC 阶段):
  目前后端:Pyroscope(Grafana 旗下)
  支持语言:Go/Python/Java/Node.js/Ruby
  与 Trace 关联:同一个 Span 可以看到对应的 flamegraph

Python 示例(早期支持):
# 在 Python 应用中启用 Profiling
from opentelemetry.sdk.extension.profiling import ProfilingExporter

# Profiling 导出到 Pyroscope
profiling_exporter = ProfilingExporter(
    endpoint="http://pyroscope:4040",
    application_name="my-service"
)
# 其余配置与标准 OTel SDK 相同

小结

OpenTelemetry 毕业意味着可以放心在生产环境全面采用,不用再担心接口变动。更重要的是,四大信号(Traces + Metrics + Logs + Profiling)统一到一套 SDK 和传输协议,结束了多套 SDK 并存的混乱局面。

从实施角度看,推荐的路线是:先部署 OTel Collector,再逐步接入各语言 SDK。Collector 作为数据中转层,让后端的选择保持灵活,今天用 Jaeger 明天换 Grafana Tempo,应用代码不需要改动。