3. 采样策略基础:Head-based Sampling 与 Tail-based Sampling 原理对比

在分布式系统中,采样是控制可观测性数据量与成本的核心手段。OpenTelemetry 支持两种截然不同的采样策略:Head-based Sampling(头部采样) 和 Tail-based Sampling(尾部采样)。理解它们的原理、适用场景与权衡,是设计高效采样方案的前提。

3.1 什么是 Head-based Sampling?

Head-based Sampling 在 Span 创建之初(即请求进入服务时)就决定是否采样。决策点位于 Trace 的根部,一旦做出决定,整个 Trace 的所有 Span 都会遵循该决定(采样或丢弃)。

  • 决策时机:Span 创建时(请求入口)
  • 决策依据:采样率、请求属性(如 HTTP 方法、路径)、固定概率
  • 优点:实现简单、性能开销低、无额外延迟
  • 缺点:无法基于完整 Trace 信息(如错误、延迟)做决策
典型场景:高吞吐量、低延迟要求的微服务,只需固定比例样本用于容量规划或基础监控。

3.2 什么是 Tail-based Sampling?

Tail-based Sampling 在 Trace 完成之后(所有 Span 已到达后端)再做决策。采样器可以查看完整的 Trace 信息,包括错误码、延迟分布、Span 数量等,从而智能地保留有价值的 Trace。

  • 决策时机:Trace 完成后(后端或 Collector 中)
  • 决策依据:完整 Trace 属性(错误、延迟、路径、业务标签)
  • 优点:能精准保留高价值 Trace(如错误、慢请求)
  • 缺点:需要缓存 Span 数据,增加内存与延迟开销
关键区别:Head-based 是“先决定,再采集”;Tail-based 是“先采集,再决定”。

3.3 核心原理对比

对比维度 Head-based Sampling Tail-based Sampling
决策时机 Span 创建时(请求入口) Trace 完成后(后端)
决策信息 仅请求头、固定规则 完整 Trace 属性、错误、延迟
内存开销 低(无缓存) 高(需缓存 Span 直到 Trace 完成)
延迟影响 无额外延迟 增加 Trace 完成后的处理延迟
采样精度 粗粒度(固定概率) 细粒度(基于内容)
典型实现 OpenTelemetry SDK 内置 Sampler OpenTelemetry Collector 处理器

3.4 架构流程对比

下图展示了两种采样策略在分布式 Trace 采集链路中的位置与决策流程。

Head-based vs Tail-based Sampling 架构对比 Head-based vs Tail-based Sampling 架构对比 Head-based Sampling 服务 A(入口) 服务 B 决策点:Span 创建时 采样率 10% → 保留或丢弃整个 Trace 保留 Trace 丢弃 Trace 优点:低开销、无延迟 缺点:无法基于错误/延迟决策 Tail-based Sampling 服务 A 服务 B Collector 缓存所有 Span 等待 Trace 完成 决策点:Trace 完成后 基于错误、延迟、路径智能保留 保留高价值 Trace 丢弃低价值 Trace

3.5 决策流程对比

以下流程图展示了两种策略在 Trace 生命周期中的决策路径差异。

Head-based vs Tail-based 决策流程 Head-based vs Tail-based 决策流程 请求到达服务 Head-based:Span 创建时决策 采样率 10%? 保留整个 Trace 丢弃整个 Trace Tail-based:所有 Span 采集 Collector 缓存等待 Trace 完成 基于错误/延迟/路径决策 保留高价值 Trace 丢弃低价值 Trace

3.6 适用场景与权衡

场景 推荐策略 原因
高吞吐量、低延迟要求 Head-based 无额外延迟,内存开销低
错误/慢请求诊断 Tail-based 能精准保留异常 Trace
容量规划、基础监控 Head-based 固定比例样本足够
全链路业务分析 Tail-based 需要完整 Trace 信息
资源受限环境 Head-based 无需缓存,节省内存
SLO 告警与根因分析 Tail-based 保留关键错误 Trace
实践建议:生产环境中常采用混合策略——Head-based 控制整体成本,Tail-based 针对错误/慢请求做二次采样。OpenTelemetry Collector 支持通过 tail_sampling 处理器实现这种组合。

3.7 代码示例:Head-based 采样配置

// OpenTelemetry SDK 配置 Head-based 采样(固定概率 10%)
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.sampling import TraceIdRatioBased

# 10% 采样率
sampler = TraceIdRatioBased(rate=0.1)
provider = TracerProvider(sampler=sampler)

# 或者基于规则采样(保留所有错误 Trace)
from opentelemetry.sdk.trace.sampling import ParentBased, ALWAYS_ON

# 父 Span 采样则子 Span 跟随,错误 Span 始终采样
sampler = ParentBased(root=TraceIdRatioBased(rate=0.1),
                      remote_parent_sampled=ALWAYS_ON)

3.8 代码示例:Tail-based 采样配置

# OpenTelemetry Collector 配置 Tail-based 采样
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317

processors:
  tail_sampling:
    decision_wait: 30s           # 等待 Trace 完成的最大时间
    num_traces: 10000            # 缓存的最大 Trace 数
    expected_new_traces_per_sec: 1000
    
    policies:
      # 策略1:保留所有错误 Trace
      - name: error-policy
        type: status_code
        status_code:
          status_codes:
            - ERROR
      
      # 策略2:保留延迟超过 500ms 的 Trace
      - name: latency-policy
        type: latency
        latency:
          threshold_ms: 500
      
      # 策略3:固定概率采样(兜底)
      - name: probabilistic-policy
        type: probabilistic
        probabilistic:
          sampling_percentage: 10

exporters:
  otlp:
    endpoint: your-backend:4317

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [tail_sampling]
      exporters: [otlp]
关键参数说明:decision_wait 控制 Trace 缓存时间,过长会增加内存压力,过短可能导致慢 Trace 未完成就被丢弃。num_traces 限制最大缓存数,防止 OOM。

3.9 本章小结

  • Head-based Sampling:在 Span 创建时决策,低开销、无延迟,但无法基于完整 Trace 信息做精细选择。
  • Tail-based Sampling:在 Trace 完成后决策,能精准保留高价值 Trace,但需要缓存和额外处理延迟。
  • 选择依据:根据业务需求、资源限制和诊断目标权衡。高吞吐场景用 Head-based,错误诊断场景用 Tail-based。
  • 混合策略:生产环境推荐组合使用,用 Head-based 控制成本,用 Tail-based 兜底关键 Trace。