2、PromQL 基础回顾:瞬时向量与区间向量、标签匹配器、基础聚合操作

在深入多租户隔离实践之前,必须牢固掌握 PromQL 的三大核心基础:数据类型(瞬时向量与区间向量)、标签筛选机制(标签匹配器)以及基础聚合操作(sum、avg、min、max)。这些概念是构建租户级查询隔离的基石。

2.1 瞬时向量与区间向量

PromQL 查询返回的数据主要分为两种向量类型,理解它们的区别是正确使用聚合函数的前提。

向量类型 英文名称 含义 典型语法 返回结果
瞬时向量 Instant Vector 每个时间序列在当前时刻的一个最新样本值 http_requests_total 一组键值对,每个时间序列对应一个值
区间向量 Range Vector 每个时间序列在过去一段时间范围内的一组样本值 http_requests_total[5m] 一组键值对,每个时间序列对应一个样本数组
关键区别: 瞬时向量用于点查和聚合;区间向量用于趋势分析和速率计算(如 rate()、increase())。聚合操作(sum/avg/min/max)通常作用于瞬时向量。
瞬时向量与区间向量概念对比 瞬时向量 vs 区间向量 瞬时向量 查询时间点 T 当前最新值 每个序列返回 1 个值 示例:http_requests_total → {job="api", instance="1"} 1024 → {job="web", instance="2"} 2048 区间向量 查询时间范围 [T-5m, T] 5m 窗口 每个序列返回一组值 示例:http_requests_total[5m] → {job="api"} [1020, 1022, 1024] → {job="web"} [2040, 2044, 2048]

2.2 标签匹配器(Label Matchers)

标签匹配器是 PromQL 实现多租户隔离的核心武器。通过在查询中精确匹配租户标签,可以确保一个租户的查询不会泄漏到其他租户的数据中。PromQL 支持四种匹配器:

匹配器 含义 示例 说明
= 完全相等 tenant_id="acme" 精确匹配标签值,最常用
!= 不等于 tenant_id!="acme" 排除特定租户,用于黑名单场景
=~ 正则匹配 tenant_id=~"acme|beta" 匹配多个租户或模糊匹配
!~ 正则排除 tenant_id!~"test-.*" 排除符合正则的租户
最佳实践: 在多租户场景中,建议将 tenant_id 作为强制标签。所有查询入口(如 Grafana 变量、告警规则)都应自动注入 tenant_id="xxx" 匹配器,从源头隔离数据。

2.3 基础聚合操作(sum、avg、min、max)

聚合操作将多个时间序列合并为一个或一组结果。在多租户场景中,聚合通常与 by 或 without 子句配合使用,以保留租户维度。

聚合函数 作用 典型场景
sum 求和 计算租户总请求量、总资源消耗
avg 平均值 计算租户平均响应时间、平均 CPU 使用率
min 最小值 找出租户最低可用率、最低水位
max 最大值 找出租户峰值流量、最高延迟
租户隔离聚合示例:
sum by (tenant_id) (http_requests_total{tenant_id=~"acme|beta"})
该查询先通过标签匹配器筛选出 acme 和 beta 两个租户的数据,然后按 tenant_id 分组求和,返回每个租户的总请求量。
基础聚合操作流程 基础聚合操作流程(以 sum by 为例) 原始时间序列 tenant="acme", job="api" → 100 tenant="acme", job="web" → 200 tenant="beta", job="api" → 150 标签匹配器筛选 tenant_id=~"acme|beta" 过滤掉其他租户数据 保留 acme 和 beta 聚合操作 sum by (tenant_id) 按租户分组求和 保留 tenant_id 维度 聚合结果 tenant="acme" → 300 tenant="beta" → 150 每个租户一个结果 关键要点 聚合必须配合 by/without 保留租户维度 避免跨租户数据混合

2.4 聚合与标签保留

在多租户场景中,by 和 without 子句决定了哪些标签在聚合后保留:

  • by (tenant_id):显式指定保留 tenant_id 标签,其他标签被丢弃。这是多租户隔离的推荐方式。
  • without (instance):排除 instance 标签,保留其余所有标签(包括 tenant_id)。适用于需要保留多个维度的场景。
常见陷阱: 如果聚合时忘记使用 by 或 without,PromQL 会默认聚合所有维度,导致租户数据被合并,失去隔离性。例如:sum(http_requests_total) 会返回所有租户的总和,这在多租户场景中通常是错误的。