2. OpenTelemetry 基础:OTel 架构概览、Signal 与 Collector 组件
在构建多租户可观测体系之前,必须深入理解 OpenTelemetry(OTel)的核心架构。本章将拆解 OTel 的三大支柱:Signal(信号)、架构组件与Collector(收集器),为后续的租户隔离链路追踪打下坚实的理论基础。
2.1 OTel 整体架构概览
OpenTelemetry 采用 “产生 → 处理 → 导出” 的三层管道架构。数据从应用中的 Instrumentation(埋点) 产生,经过 Collector 的接收、处理、聚合,最终导出到后端存储(如 Jaeger、Prometheus、Datadog)。
下图展示了 OTel 的核心组件及其数据流向:
架构要点: OTel 的管道设计使得数据可以在 Collector 层进行统一的过滤、采样、脱敏和路由,这是实现多租户隔离的基础。租户标签(如
tenant.id)可以在 Processor 阶段注入。
2.2 Signal(信号):Trace / Metric / Log
OTel 将可观测数据抽象为三种核心 Signal。理解它们的定义、关系与差异,是正确使用 OTel 的前提。
| Signal | 定义 | 核心数据模型 | 典型用途 |
|---|---|---|---|
| Trace(链路) | 记录请求在分布式系统中的完整路径,包含 Span 的父子关系。 | Span(名称、开始/结束时间、SpanContext、Attributes、Events) | 请求延迟分析、错误定位、依赖关系拓扑 |
| Metric(指标) | 对系统状态进行数值化聚合测量,如请求数、CPU 使用率。 | Instrument(Counter/Histogram/Gauge)、DataPoint、Attributes | 系统监控、告警、容量规划、SLO 跟踪 |
| Log(日志) | 带时间戳的离散事件记录,通常包含结构化或非结构化文本。 | LogRecord(时间戳、Body、Severity、Attributes) | 详细错误排查、审计、业务事件记录 |
Signal 关联: 在 OTel 中,Trace 和 Log 可以通过
trace_id 和 span_id 进行关联。Metric 虽然不直接包含 Trace ID,但可以通过 Attributes(如 service.name、tenant.id)与 Trace 和 Log 进行上下文关联,形成完整的可观测性视图。
2.3 Collector 组件详解
OpenTelemetry Collector 是一个与供应商无关的代理,负责接收、处理和导出遥测数据。它是 OTel 架构中最灵活的组件,也是实现租户隔离策略的核心战场。
Collector 由以下核心组件构成:
- Receivers(接收器):负责从各种来源接收数据。常见的有
otlp(接收 OTLP 协议数据)、jaeger、prometheus、filelog等。 - Processors(处理器):对数据进行处理、过滤、转换、增强。这是实现租户隔离的关键环节,例如:
attributes:添加、修改或删除属性(如注入tenant.id)。filter:根据条件过滤数据(如丢弃非生产租户的调试日志)。batch:批量处理数据以提高吞吐量。memory_limiter:防止内存溢出。
- Exporters(导出器):将处理后的数据发送到后端存储或分析平台。常见的有
otlp、jaeger、prometheus、datadog、splunk等。 - Pipelines(管道):将 Receivers、Processors 和 Exporters 串联起来,形成完整的数据处理流。一个 Collector 可以定义多个 Pipeline,用于处理不同的 Signal 或租户。
- Extensions(扩展):提供健康检查、性能分析、pprof 等辅助功能。
下图展示了 Collector 内部的数据处理流程:
⚠️ 租户隔离关键点: 在 Processor 阶段,可以通过
attributes 处理器为所有 Span 和 Metric 注入租户标签(如 tenant.id)。后续的 filter 处理器可以根据该标签进行数据路由,确保不同租户的数据被导出到不同的后端或索引,实现逻辑隔离。
2.4 三种 Signal 的租户隔离策略对比
在实现租户隔离时,Trace、Metric 和 Log 的处理方式略有不同。下表总结了各自的隔离策略:
| Signal | 隔离粒度 | 常用标签 | Collector 处理策略 |
|---|---|---|---|
| Trace | Span 级别 | tenant.id, tenant.name |
在 Processor 中注入标签,通过 filter 或 routing 导出到不同后端 |
| Metric | DataPoint 级别 | tenant.id, service.namespace |
通过 Attributes 携带租户信息,在 Prometheus 中使用标签进行查询隔离 |
| Log | LogRecord 级别 | tenant.id, tenant.region |
在日志正文或 Attributes 中嵌入租户 ID,通过 filelog receiver 解析并路由 |
最佳实践: 建议在应用层(SDK 初始化时)就通过
Resource 或 Span 的 Attributes 携带租户信息。Collector 层负责验证、补充和路由,而不是凭空生成租户标签。这样可以保证数据源的准确性。