3、多租户数据模型设计:租户标签(tenant_id)的引入、指标命名规范、标签命名空间隔离策略

在多租户采集作业平台中,数据模型的设计直接决定了 PromQL 聚合查询能否准确、高效地实现租户隔离。如果指标和标签设计不当,轻则导致查询结果混淆,重则引发跨租户数据泄露。本节从三个核心维度展开:租户标签的引入、指标命名规范以及标签命名空间隔离策略。

3.1 租户标签(tenant_id)的引入

租户标签是数据隔离的基石。在 Prometheus 指标体系中,标签(Label)是唯一能够区分数据归属的维度。我们选择在指标采集侧强制注入 tenant_id 标签,而非依赖指标名称前缀或外部元数据。

设计原则:每个时间序列必须且只能携带一个 tenant_id 标签,该标签在采集器(Agent)端由平台根据认证信息自动注入,禁止用户侧修改。

以下是一个典型的带租户标签的指标示例:

# 采集作业成功次数指标(带租户标签)
collect_job_success_total{tenant_id="t-1001", job_name="data_sync", instance="node-1"} 1024

# 采集作业延迟指标(带租户标签)
collect_job_latency_seconds{tenant_id="t-1001", job_name="data_sync", instance="node-1"} 0.35

引入 tenant_id 标签后,PromQL 聚合查询可以精确限定数据范围:

# 查询租户 t-1001 下所有作业的成功总数
sum by (job_name) (collect_job_success_total{tenant_id="t-1001"})

# 查询所有租户的作业延迟 P99(按租户聚合)
quantile by (tenant_id) (0.99, collect_job_latency_seconds)

3.2 指标命名规范

统一的指标命名规范能够降低多租户环境下的管理复杂度,避免命名冲突,并提升 PromQL 查询的可读性。我们采用以下三层命名结构:

层级 命名段 说明 示例
1 命名空间前缀 固定为 collect_,标识采集作业平台 collect_
2 业务实体 描述采集对象,如 job、task、source job
3 度量类型 描述度量维度,如 total、latency_seconds、errors latency_seconds

完整指标名称示例:

  • collect_job_total — 采集作业总数
  • collect_job_latency_seconds — 采集作业延迟(秒)
  • collect_task_errors_total — 采集任务错误总数
  • collect_source_throughput_bytes — 数据源吞吐量(字节)
避坑提示:禁止在指标名称中嵌入租户标识(如 collect_job_total_t1001)。租户信息必须通过标签表达,否则会导致指标基数爆炸,且无法使用 PromQL 的 by 子句灵活聚合。

3.3 标签命名空间隔离策略

在多租户场景下,标签的命名空间管理至关重要。不同租户可能使用相同的业务标签名(如 job_name、region),但它们的值域必须隔离。我们采用以下策略:

3.3.1 强制保留标签

以下标签由平台强制注入,用户不可覆盖:

标签名 类型 说明 注入时机
tenant_id 保留 租户唯一标识 采集器启动时
collector_id 保留 采集器实例 ID 采集器启动时
namespace 保留 采集作业命名空间 作业配置下发时

3.3.2 用户自定义标签前缀

允许租户在自定义标签时使用 custom_ 前缀,避免与保留标签冲突:

# 用户自定义标签示例
collect_job_total{tenant_id="t-1001", custom_env="production", custom_region="us-east-1"}

3.3.3 标签值域隔离

即使不同租户使用相同的标签名,其值域也通过 tenant_id 天然隔离。PromQL 查询时,只需在 by 子句中指定 tenant_id,即可保证聚合结果不跨租户。

隔离效果验证:以下查询分别返回租户 A 和租户 B 的作业延迟分布,即使它们都使用了 job_name 标签,结果也不会混淆。
# 租户 A 的延迟分布
histogram_quantile(0.95, sum by (le, tenant_id) (rate(collect_job_latency_seconds_bucket{tenant_id="t-1001"}[5m])))

# 租户 B 的延迟分布
histogram_quantile(0.95, sum by (le, tenant_id) (rate(collect_job_latency_seconds_bucket{tenant_id="t-1002"}[5m])))

3.4 数据模型架构总览

下图展示了多租户数据模型的整体架构,从采集器注入租户标签,到指标命名规范,再到标签命名空间隔离,形成完整的隔离链路。

多租户数据模型隔离架构 采集器 Agent 注入 tenant_id 标签 指标命名规范 collect_<实体>_<度量> 标签命名空间隔离 保留标签 + 自定义前缀 Prometheus 时间序列数据库 每个序列携带 tenant_id 标签 PromQL 聚合查询 通过 tenant_id 实现租户级聚合 说明:tenant_id 标签贯穿采集、存储、查询全链路,是租户隔离的核心纽带

3.5 隔离策略对比

下表对比了三种常见的多租户隔离策略,帮助理解为何我们选择标签级隔离:

隔离策略 实现方式 PromQL 查询复杂度 扩展性 推荐场景
指标名称前缀 每个租户使用不同指标名,如 t1001_job_total 高(需正则匹配) 差(指标基数爆炸) 不推荐
独立 Prometheus 实例 每个租户部署独立 Prometheus 低(无需隔离) 差(资源浪费) 强合规、超大规模
标签级隔离(推荐) 统一指标名 + tenant_id 标签 低(by tenant_id) 好(共享存储) 通用多租户平台
实践建议:在采集作业平台初期就引入 tenant_id 标签,并固化指标命名规范。后期迁移成本远高于前期设计成本。标签级隔离在共享存储和查询灵活性之间取得了最佳平衡。