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