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 数据模型架构总览
下图展示了多租户数据模型的整体架构,从采集器注入租户标签,到指标命名规范,再到标签命名空间隔离,形成完整的隔离链路。
3.5 隔离策略对比
下表对比了三种常见的多租户隔离策略,帮助理解为何我们选择标签级隔离:
| 隔离策略 | 实现方式 | PromQL 查询复杂度 | 扩展性 | 推荐场景 |
|---|---|---|---|---|
| 指标名称前缀 | 每个租户使用不同指标名,如 t1001_job_total |
高(需正则匹配) | 差(指标基数爆炸) | 不推荐 |
| 独立 Prometheus 实例 | 每个租户部署独立 Prometheus | 低(无需隔离) | 差(资源浪费) | 强合规、超大规模 |
| 标签级隔离(推荐) | 统一指标名 + tenant_id 标签 |
低(by tenant_id) | 好(共享存储) | 通用多租户平台 |
实践建议:在采集作业平台初期就引入
tenant_id 标签,并固化指标命名规范。后期迁移成本远高于前期设计成本。标签级隔离在共享存储和查询灵活性之间取得了最佳平衡。