3. 租户标识策略:基于 Resource 属性的租户标记
在多租户数据管道中,租户标识是隔离与路由的基石。OpenTelemetry 的 Resource(资源)概念天然适合承载租户上下文——Resource 描述生成遥测数据的实体(如服务、主机、容器),而租户正是该实体的一个固有属性。本章将深入讲解如何通过 Resource 属性标记租户、使用 Attributes Processor 自动注入租户 ID,以及 Span 与 Metric 的标签设计规范。
3.1 基于 Resource 属性的租户标记策略
Resource 是 OpenTelemetry 数据模型中的第一级概念,与 Span、Metric、Log 并列。每个遥测数据点都关联一个 Resource,描述其来源。利用这一特性,我们可以将 tenant.id 或 tenant.name 作为 Resource 属性,实现全局租户标记。
| 属性键 | 类型 | 示例值 | 说明 |
|---|---|---|---|
tenant.id |
string | acme-corp-001 |
全局唯一租户标识符,推荐 UUID 或业务编码 |
tenant.name |
string | Acme Corporation |
租户可读名称,用于 UI 展示 |
tenant.tier |
string | premium |
租户服务等级,用于 QoS 与限流策略 |
tenant.region |
string | us-east-1 |
租户数据驻留区域,辅助合规路由 |
tenant.* 命名空间,避免与业务属性冲突。Resource 属性应在 SDK 初始化时从环境变量或配置文件注入,而非硬编码在代码中。
3.2 使用 Attributes Processor 注入租户 ID
在 OpenTelemetry Collector 中,Attributes Processor 是注入租户 ID 的核心组件。它可以在数据进入管道时,根据预定义规则向 Resource 或 Span 添加、更新或删除属性。对于多租户场景,我们通常将租户 ID 注入到 Resource 属性中,确保所有下游处理器和导出器都能感知租户上下文。
以下是一个典型的 Collector 配置片段,展示如何通过 Attributes Processor 注入租户 ID:
processors:
attributes/tenant-injector:
actions:
# 从请求头中提取租户 ID 并注入到 Resource 属性
- key: tenant.id
value: "${env:TENANT_ID}"
action: upsert
# 指定作用域为 resource,确保影响所有遥测类型
resource: true
# 如果环境变量不存在,使用默认值
- key: tenant.tier
value: "standard"
action: insert
resource: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [attributes/tenant-injector, batch]
exporters: [otlp/backend]
metrics:
receivers: [otlp]
processors: [attributes/tenant-injector, batch]
exporters: [otlp/backend]
resource: true 确保属性被写入 Resource 层级,而非仅作用于单个 Span 或 Metric 点。这样,即使数据经过聚合或采样,租户上下文也不会丢失。
3.3 Span 与 Metric 的租户标签设计
除了 Resource 级别的租户标记,Span 和 Metric 本身也需要携带租户标签,以支持细粒度的查询与路由。设计原则是:Resource 属性用于全局标识,Span/Metric 属性用于局部上下文。
3.3.1 Span 租户标签设计
对于分布式追踪中的 Span,租户标签应遵循以下规范:
- 必选标签:
tenant.id— 与 Resource 中的值一致,用于快速过滤。 - 可选标签:
tenant.user_id— 当 Span 代表用户级操作时,记录具体用户。 - 禁止标签: 避免在 Span 中重复 Resource 级别的静态属性(如
tenant.region),以减少数据冗余。
// 在 Span 创建时注入租户标签(Java 示例)
Span span = tracer.spanBuilder("processOrder")
.setAttribute("tenant.id", "acme-corp-001")
.setAttribute("tenant.user_id", "user-42")
.startSpan();
3.3.2 Metric 租户标签设计
Metric 的租户标签设计略有不同,因为 Metric 通常聚合多个数据点。推荐做法是:
- Resource 属性: 携带
tenant.id,作为 Metric 的第一级分组键。 - Metric 属性: 仅在需要区分同一 Metric 内的不同租户维度时添加(如
tenant.region)。 - 避免高基数标签: 不要将
tenant.user_id直接作为 Metric 标签,会导致基数爆炸。
3.4 租户标识策略架构总览
下图展示了从数据采集到导出的完整租户标识流程:
3.5 租户标签设计对比总结
| 遥测类型 | 推荐标签 | 注入层级 | 注意事项 |
|---|---|---|---|
| Resource(所有类型) | tenant.id, tenant.tier |
SDK 初始化 / Collector 注入 | 全局唯一,不可变 |
| Span | tenant.id, tenant.user_id |
应用代码 / Collector 注入 | 避免重复 Resource 属性 |
| Metric DataPoint | tenant.id(仅必要时) |
Collector 注入 | 警惕高基数,优先用 Resource |
| Log Record | tenant.id |
SDK 初始化 / Collector 注入 | 与 Resource 保持一致 |