概述

OpenTelemetry 为何赢得 2026

截至 2026 年,OpenTelemetry(以下简称 OTel)已成为分布式可观测性领域的事实标准。根据 CNCF 年度调查,全球已有超过 85% 的云原生项目采用 OTel 作为首选遥测数据采集方案。1

OTel 成功的核心原因在于其统一性:

特性OpenTracingOpenCensusOpenTelemetry
统一 API
多语言支持有限有限完整
供应商无关
三大支柱融合Metrics 为主Traces + Metrics + Logs
CNCF 毕业状态归档归档

2019 年,CNCF 宣布将 OpenTracing 和 OpenCensus 合并为 OpenTelemetry,这一决策彻底改变了行业格局。两大标准合二为一,结束了「选边站队」的困境,开发者无需再在 Zipkin 和 Jaeger 之间做出取舍。

核心定位

OTel 不仅仅是一个追踪库,而是可观测性的统一层

┌─────────────────────────────────────────────────────────────┐
│                      Your Application                        │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │ Auto Inst.  │  │ Manual API  │  │ SDK Core    │          │
│  │ (HTTP/gRPC) │  │ (Business)   │  │ (Context)    │          │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘          │
│         └────────────────┼────────────────┘                  │
│                          ▼                                   │
│                   OTLP Protocol                              │
└──────────────────────────┬───────────────────────────────────┘
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                   OpenTelemetry Collector                     │
└──────────────────────────┬───────────────────────────────────┘
                           ▼
         ┌─────────────────┼─────────────────┐
         ▼                 ▼                 ▼
   ┌──────────┐      ┌──────────┐      ┌──────────┐
   │  Jaeger  │      │Prometheus│      │  Grafana │
   └──────────┘      └──────────┘      └──────────┘

核心概念

三大支柱

OTel 的核心理念是将追踪(Traces)、**指标(Metrics)日志(Logs)**统一在一个语义模型下:

Traces 记录请求在分布式系统中的完整流转路径,擅长回答「发生了什么」。

Metrics 是聚合后的数值指标,擅长回答「发生了什么多少」。

Logs 是离散的事件记录,擅长回答「详细上下文是什么」。

这三者相辅相成:通过 Trace 定位问题,通过 Metrics 判断影响范围,通过 Logs 深入根因。

Span、Trace ID 与 SpanContext

Span 是分布式追踪的基本单元,代表一个逻辑操作单元:

# Span 的生命周期
span = tracer.start_span("operation_name")
span.set_attribute("user.id", "12345")
span.add_event("Processing started")
# ... 业务逻辑 ...
span.set_status(Status(Code.OK))
span.end()

Trace ID 是 128 位全局唯一标识,贯穿整个请求链路。所有 Span 共享同一个 Trace ID。

SpanContext 是跨服务边界传递的上下文载体,包含:

  • trace_id:链路唯一标识
  • span_id:当前操作标识
  • trace_flags:采样标志(1 位)
  • tracestate:多租户或自定义键值对

上下文传播机制

上下文传播是分布式追踪的基石。当请求跨越服务边界时,SpanContext 必须被序列化和传递:

# W3C Trace Context 是标准传播格式
from opentelemetry.propagate import inject, extract
from opentelemetry.propagation.trace_context import TraceContextTextMapPropagator
 
# 发送方:注入上下文到 HTTP Headers
headers = {}
inject(headers)  # headers["traceparent"] = "00-..."
 
# 接收方:从 Headers 提取上下文
context = extract(request.headers)
with tracer.start_as_current_span("operation", context=context) as span:
    # 自动建立父子关系
    pass

Collector 架构

单 Collector vs 分层架构

OTel Collector 是处理遥测数据的核心组件。架构选择取决于系统规模:

单 Collector 架构

应用 → Agent(daemonset) → Collector → Backend

适用于:

  • 服务数量 < 20
  • 请求量 < 500 RPS
  • 团队规模 < 10 人

双层 Collector 架构

应用 → Agent(daemonset) → Gateway(集群) → Backend

适用于:

  • 服务数量 > 80
  • 请求量 > 5000 RPS
  • 多地域部署
规模等级服务数RPS推荐架构Collector 实例数
小型< 20< 500单层1-2
中型20-80500-5000单层 + HA3-5
大型> 80> 5000双层10+

Agent 模式:Daemonset vs Sidecar

Daemonset 模式(推荐):

# otel-agent-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: otel-agent
spec:
  selector:
    matchLabels:
      app: otel-agent
  template:
    spec:
      containers:
      - name: otel-agent
        image: otel/opentelemetry-collector-contrib:0.96.0
        args: ["--config=/etc/otel-agent.yaml"]
        env:
        - name: HOST_IP
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
        volumeMounts:
        - name: config
          mountPath: /etc
        ports:
        - name: otlp
          containerPort: 4317
          hostPort: 4317
      volumes:
      - name: config
        configMap:
          name: otel-agent-config

优势:资源利用率高,节点级别聚合减少网络开销。

Sidecar 模式

优势:完全隔离,灵活性高。劣势:资源开销大,管理复杂。

推荐场景:多租户环境、需要强隔离的服务。


生产最佳实践

自动埋点:起点而非终点

自动埋点是快速接入 OTel 的最佳方式,但不适合作为唯一手段:

# Python 自动埋点配置
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
from opentelemetry.instrumentation.pymongo import PymongoInstrumentor
 
# 初始化所有自动埋点
FlaskInstrumentor().instrument_app(app)
RequestsInstrumentor().instrument()
PymongoInstrumentor().instrument()

自动埋点的局限:

场景自动埋点能力
HTTP 入站请求✓ 完整支持
数据库调用✓ 主流驱动支持
消息队列△ 部分支持
业务关键路径✗ 无法覆盖
复杂异步逻辑✗ 上下文断裂

手动埋点:关键业务路径

对于核心业务逻辑,必须使用手动埋点:

# 业务关键路径的手动埋点
tracer = trace.get_tracer(__name__)
 
def process_payment(order_id: str, amount: Decimal):
    with tracer.start_as_current_span("payment.process") as span:
        span.set_attribute("payment.order_id", order_id)
        span.set_attribute("payment.amount", float(amount))
        span.set_attribute("payment.currency", "CNY")
        
        # 调用外部支付网关
        with tracer.start_as_current_span("payment.gateway_call") as gateway_span:
            gateway_span.set_attribute("gateway.provider", "alipay")
            try:
                result = payment_gateway.pay(order_id, amount)
                span.set_attribute("payment.status", "success")
            except PaymentException as e:
                span.set_status(trace.Status(trace.StatusCode.ERROR, str(e)))
                span.record_exception(e)
                raise

语义约定

OTel 定义了标准的属性命名约定,遵循语义约定能确保跨服务、跨团队的一致性:

类别属性键示例值
HTTPhttp.methodGET, POST
HTTPhttp.urlhttps://api.example.com/users
HTTPhttp.status_code200, 404
数据库db.systempostgresql, mysql, redis
数据库db.nameusers_db
数据库db.operationSELECT, INSERT
RPCrpc.systemgrpc, jsonrpc
RPCrpc.method/user.Service/GetUser
消息messaging.systemkafka, rabbitmq
消息messaging.destinationorder-created

采样策略

头部采样 vs 尾部采样

头部采样(Head-based Sampling) 在请求入口处决定采样,决策早、开销低:

# 头部采样配置
processors:
  probabilistic_sampler:
    sampling_percentage: 10  # 全局 10% 采样

优势:低开销、无需等待请求结束。劣势:可能丢失异常和慢请求。

尾部采样(Tail-based Sampling) 在请求结束后根据结果采样:

# 尾部采样配置
processors:
  tail_sampling:
    decision_wait: 10s
    num_traces: 100000
    policies:
      # 错误请求 100% 采样
      - name: errors-policy
        type: status_code
        status_code: { status_codes: [ERROR] }
      # 慢请求 100% 采样
      - name: slow-traces-policy
        type: latency
        latency: { threshold_ms: 2000 }
      # 关键服务 100% 采样
      - name: critical-services-policy
        type: string_attribute
        string_attribute: { key: service.name, values: [payment-service, order-service] }
      # 其他请求 5% 采样
      - name: probabilistic-policy
        type: probabilistic
        probabilistic: { sampling_percentage: 5 }

父级采样

父级采样(Parent-based Sampling)根据父 Span 是否被采样决定子 Span:

processors:
  parent_based:
    root:
      type: probabilistic
      probabilistic: { sampling_percentage: 20 }
    trace_header:
      type: probabilistic
      probabilistic: { sampling_percentage: 100 }

这种模式确保:如果父请求被采样,所有子 Span 都被包含。

自适应采样

大规模系统推荐使用自适应采样策略:

processors:
  tail_sampling:
    decision_wait: 10s
    policies:
      # 高价值请求:认证用户、付费订单
      - name: high-value-policy
        type: string_attribute
        string_attribute:
          key: user.tier
          values: [premium, enterprise]
        sampling_percentage: 100
      
      # 异常请求:始终采样
      - name: errors-policy
        type: status_code
        status_code: { status_codes: [ERROR] }
        sampling_percentage: 100
      
      # 慢请求:超过 P99 阈值
      - name: slow-traces-policy
        type: latency
        latency: { threshold_ms: 3000 }
        sampling_percentage: 100
      
      # 正常请求:按比例采样
      - name: normal-policy
        type: probabilistic
        probabilistic: { sampling_percentage: 5 }

上下文传播

HTTP Header 传播

W3C Trace Context 是 Web 场景的标准:

traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
tracestate: congo=t61rcWkgMzE
  • 00:版本号
  • 4bf92f3577b34da6a3ce929d0e0e4736:Trace ID(32 字符)
  • 00f067aa0ba902b7:Span ID(16 字符)
  • 01:采样标志(01=已采样)

消息队列传播

异步消息系统需要特殊处理:

# Kafka 消息传播
from opentelemetry import trace
from opentelemetry.propagate import inject, extract
from opentelemetry.instrumentation.confluent_kafka import ConfluentKafkaInstrumentor
 
ConfluentKafkaInstrumentor().instrument()
 
# 生产者:注入上下文到消息 Headers
producer = KafkaProducer(...)
headers = {}
inject(headers)
producer.send("order-topic", value=order_data, headers=list(headers.items()))
 
# 消费者:提取上下文
consumer = KafkaConsumer("order-topic", value_deserializer=...)
for message in consumer:
    context = extract(message.headers())
    with tracer.start_as_current_span("process_order", context=context) as span:
        process_order(message.value())

异步任务框架

线程池、Future、AsyncIO 等场景容易出现上下文断裂:

# Python ThreadPoolExecutor 场景
from concurrent.futures import ThreadPoolExecutor
from opentelemetry import trace
 
executor = ThreadPoolExecutor(max_workers=10)
 
def async_task(task_id: int):
    # 手动传递当前上下文
    ctx = trace.set_span_in_context(trace.get_current_span())
    return executor.submit(process_task, task_id, ctx)
 
def process_task(task_id: int, parent_ctx):
    # 在新线程中激活父上下文
    with tracer.start_as_current_span(f"task_{task_id}", context=parent_ctx):
        # 处理任务
        pass

成本控制

基数管理

高基数是 OTel 成本失控的主因:

属性类型低基数示例高基数风险
http.status_code200, 404, 500-
user.id-用户数 = 基数
session.id-每次会话 = 新基数
request.id-每请求 = 新基数

防御策略

# 避免高基数属性
span.set_attribute("http.status_code", 200)  # ✓ OK
 
# 错误做法:request.id 作为属性会爆炸
span.set_attribute("request.id", request_id)  # ✗ 高基数
 
# 正确做法:将 request.id 作为 Event 而非 Attribute
span.add_event("request_id", {"request.id": request_id})

数据保留策略

分层保留控制存储成本:

层级保留期存储介质用途
热数据0-7 天SSD/本地实时排查
温数据8-30 天HDD/网络存储趋势分析
冷数据31-365 天对象存储合规审计
归档> 1 年归档存储法律要求

分层采样策略

生产环境推荐「关键路径 100%,普通路径 5-10%」的分层策略:

processors:
  tail_sampling:
    decision_wait: 15s
    policies:
      # 支付链路:100%
      - name: payment-path
        type: and
        and:
          conditions:
            - string_attribute: { key: service.name, values: [payment-service] }
            - string_attribute: { key: operation.type, values: [payment] }
        sampling_percentage: 100
      
      # 认证请求:100%
      - name: auth-requests
        type: string_attribute
        string_attribute: { key: auth.required, values: [true] }
        sampling_percentage: 100
      
      # 异常和慢请求:100%
      - name: errors-and-slow
        type: or
        or:
          conditions:
            - status_code: { status_codes: [ERROR] }
            - latency: { threshold_ms: 2000 }
        sampling_percentage: 100
      
      # 默认采样率:5%
      - name: default
        type: probabilistic
        probabilistic: { sampling_percentage: 5 }

常见陷阱

高基数爆炸

症状:存储成本月环比增长超过 50%,查询延迟显著增加。

根因:将 user.idsession.idrequest.id 等高唯一性值设为 Span 属性。

解决方案

# 错误示例
span.set_attribute("db.statement", f"SELECT * FROM users WHERE id={user_id}")
 
# 正确示例:参数化查询
span.set_attribute("db.system", "postgresql")
span.set_attribute("db.operation", "SELECT")
span.set_attribute("db.table", "users")
span.set_attribute("db.bind_args.count", 1)
 
# request_id 放入 Event 而非 Attribute
span.add_event("request_id", {"request.id": request_id})

异步边界上下文断裂

症状:Trace 中间出现 Span 断开,子服务 Span 不在父 Span 下。

根因:异步任务未正确传递 SpanContext。

解决方案

# Python asyncio 场景
import asyncio
from opentelemetry import trace
 
async def async_operation():
    # 获取当前上下文
    current_span = trace.get_current_span()
    ctx = trace.set_span_in_context(current_span)
    
    # 传递上下文到新 Task
    task = asyncio.create_task(called_operation(ctx))
    await task
 
async def called_operation(ctx):
    with tracer.start_as_current_span("async_child", context=ctx):
        pass

Collector 单点故障

症状:所有追踪数据丢失,系统无任何可观测性。

根因:Collector 部署无高可用,网络链路无冗余。

解决方案

# Collector 高可用配置
service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch, memory_limiter]
      exporters: [jaeger, otlp/2]  # 多个后端
 
exporters:
  otlp:
    endpoint: jaeger-collector-1:4317
  otlp/2:
    endpoint: jaeger-collector-2:4317
    # 失败时重试
    retry_on_failure:
      enabled: true
      initial_interval: 1s
      max_interval: 30s
      max_attempts: 5

Span 命名不一致

症状:同类操作在不同服务中命名各异,难以聚合查询。

根因:缺乏命名规范,开发者各行其是。

解决方案:制定团队命名规范并固化到 Code Review:

操作类型命名格式示例
HTTP 入站{METHOD} {ROUTE}GET /api/users/{id}
数据库{OPERATION} {TABLE}SELECT users
缓存{OPERATION} {KEY_PATTERN}GET user:{id}
消息{PRODUCE/CONSUME} {TOPIC}CONSUME order-topic

相关主题

分布式追踪 | 分布式系统概述 | 服务网格


参考资料

Footnotes

  1. CNCF Annual Survey 2025 - https://www.cncf.io/reports/cncf-annual-survey-2025/