2. 核心概念:Span、Trace、Metric、Log在管道中的流转路径

在多租户隔离管道中,理解四种核心信号——Span、Trace、Metric、Log——的流转路径,是划分服务边界的前提。每种信号从产生到消费,经过的节点、携带的元数据、以及隔离策略均不相同。本节将逐一拆解其生命周期,并给出管道中的关键边界点。

2.1 四种信号的管道角色对比

信号类型 核心数据单元 主要用途 隔离粒度 典型传输协议
Span 单个操作单元(含开始/结束时间、属性、事件) 分布式追踪链路构建 TraceId + SpanId gRPC / HTTP (OTLP)
Trace 由同一条 TraceId 串联的 Span 集合 端到端请求路径还原 TraceId 命名空间 无独立协议,由 Span 聚合
Metric 时间序列数据点(Counter、Histogram、Gauge) 聚合统计与告警 InstrumentationScope + 属性标签 gRPC / HTTP (OTLP)
Log 带时间戳的结构化日志记录 事件记录与故障排查 资源属性 + 日志流 gRPC / HTTP (OTLP) 或文件采集
关键认知: 在 OpenTelemetry 管道中,Trace 不是独立传输的信号,而是由多个 Span 通过共享 TraceId 在消费端(如 Jaeger、Tempo)重建的逻辑集合。隔离策略必须作用在 Span 层面,而非 Trace 层面。

2.2 Span 的流转路径

Span 是分布式追踪的最小原子单元,其流转路径贯穿整个管道:

  1. 创建:在服务端或客户端通过 Tracer 创建,记录操作名称、开始时间、结束时间、状态、属性(Attributes)和事件(Events)。
  2. 上下文注入:通过 W3C TraceContext 或 B3 格式,将 TraceId、SpanId、TraceFlags 注入到请求头中,跨服务传播。
  3. 本地导出:SpanProcessor 将 Span 批量或实时传递给 SpanExporter。
  4. 序列化与传输:SpanExporter 将 Span 编码为 OTLP Protobuf 格式,通过 gRPC 或 HTTP 发送到 Collector。
  5. Collector 处理:在 Collector 中经过接收器(Receiver)、处理器(Processor)、导出器(Exporter)管道,可能进行采样、属性修改、租户标签注入。
  6. 后端存储:最终写入追踪后端(如 Jaeger、Tempo、Zipkin)。
多租户边界点: Span 在 Collector 的 Processor 阶段,通过 attributesprocessor 或 transformprocessor 注入租户标识(如 tenant.id),后端据此实现数据隔离。

2.3 Metric 的流转路径

Metric 信号用于聚合统计,其流转路径与 Span 有显著差异:

  • 采集:通过 Meter 创建 Counter、Histogram、Gauge 等仪器,在代码中记录数据点。
  • 聚合:MetricReader 按固定时间窗口(如 10s)对原始数据点进行聚合,生成时间序列。
  • 导出:MetricExporter 将聚合后的 Metric 数据发送到 Collector。
  • Collector 处理:支持降采样、标签修改、租户路由。常用 metricstransformprocessor 重命名指标或添加租户标签。
  • 存储与查询:写入 Prometheus、VictoriaMetrics、Thanos 等时序数据库。
隔离陷阱: Metric 的标签(Label)是隔离的关键。如果租户标签未在 Collector 中统一注入,不同租户的指标会混在一起,导致告警误报或计费错误。务必在 Collector 的 Processor 阶段强制添加 tenant_id 标签。

2.4 Log 的流转路径

Log 信号在 OpenTelemetry 中相对较新,其流转路径如下:

阶段 说明 多租户关注点
日志产生 应用通过 Logger 记录结构化日志,包含时间戳、级别、消息体、资源属性 资源属性中应包含租户标识
日志采集 通过 Filelog Receiver 或 OTLP Receiver 采集 文件路径或日志流需按租户隔离
日志处理 Collector 中可进行解析、过滤、租户标签注入 使用 logstransformprocessor 提取租户字段
日志存储 写入 Elasticsearch、Loki、ClickHouse 等 索引或表按租户分片

2.5 四种信号在 Collector 管道中的统一流转图

下图展示了 Span、Metric、Log 三种信号(Trace 由 Span 聚合)在 OpenTelemetry Collector 管道中的并行流转路径,并标注了多租户隔离的关键边界点。

OpenTelemetry 四种信号在 Collector 管道中的流转路径 四种信号在 Collector 管道中的流转路径 Span 源 Metric 源 Log 源 Receiver OTLP Receiver Filelog Receiver Prometheus Receiver (统一接收入口) Processor batchprocessor memorylimiter attributesprocessor (注入 tenant.id) transformprocessor (租户路由规则) Exporter otlpexporter prometheusexporter loggingexporter (按租户分发) 多租户隔离边界点: ① Processor 阶段注入租户标签(tenant.id) ② Exporter 阶段按租户分发到不同后端 ③ Receiver 阶段通过租户 Token 进行身份校验 租户 A 后端 租户 B 后端 租户 C 后端

2.6 信号流转中的关键隔离决策点

根据上述流转路径,在多租户管道中需要重点关注的决策点包括:

  • 身份注入时机:租户标识应在 Collector 的 Processor 阶段统一注入,而非依赖应用端,避免应用绕过或遗漏。
  • 采样策略:不同租户可能有不同的采样率(如付费租户 100% 采样,免费租户 10% 采样),需在 Collector 中按租户标签配置 tailsamplingprocessor。
  • 限流与背压:每个租户的数据量不同,需在 Receiver 或 Processor 阶段按租户进行限流,防止一个租户打满管道影响其他租户。
  • 数据路由:Exporter 阶段根据租户标签将数据分发到不同的后端实例或索引,实现存储层隔离。
最佳实践: 在 Collector 配置中,使用 transformprocessor 结合 OTTL(OpenTelemetry Transformation Language)统一处理所有信号的租户标签注入,确保 Span、Metric、Log 三种信号在进入 Exporter 前都携带一致的 tenant.id 属性。

2.7 信号流转的代码示例(Collector 配置片段)

以下是一个 Collector 配置片段,展示了如何在 Processor 阶段为所有信号注入租户标签:

processors:
  transform:
    error_mode: ignore
    trace_statements:
      - context: span
        statements:
          - set(attributes["tenant.id"], resource.attributes["tenant.id"])
    metric_statements:
      - context: datapoint
        statements:
          - set(attributes["tenant.id"], resource.attributes["tenant.id"])
    log_statements:
      - context: log
        statements:
          - set(attributes["tenant.id"], resource.attributes["tenant.id"])
  
  batch:
    timeout: 5s
    send_batch_size: 1024

exporters:
  otlp/tenant_a:
    endpoint: "backend-a:4317"
    headers:
      "X-Tenant-ID": "tenant-a"
  otlp/tenant_b:
    endpoint: "backend-b:4317"
    headers:
      "X-Tenant-ID": "tenant-b"

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [transform, batch]
      exporters: [otlp/tenant_a, otlp/tenant_b]
    metrics:
      receivers: [otlp]
      processors: [transform, batch]
      exporters: [otlp/tenant_a, otlp/tenant_b]
    logs:
      receivers: [otlp]
      processors: [transform, batch]
      exporters: [otlp/tenant_a, otlp/tenant_b]

上述配置中,transform 处理器将资源属性中的 tenant.id 复制到每个信号的属性中,确保后续 Exporter 可以根据该标签进行路由分发。