2. PromQL 基础回顾:瞬时向量、区间向量、匹配模式
在深入误差预算台账的聚合优化之前,必须牢固掌握 PromQL 的三大核心概念:瞬时向量、区间向量以及向量匹配模式。这些是构建任何复杂查询的基石,也是理解后续聚合操作与性能优化的前提。
2.1 瞬时向量与区间向量
PromQL 查询返回的数据类型决定了你能对时间序列执行何种操作。下表清晰区分了两种最常用的向量类型:
| 特性 | 瞬时向量 (Instant Vector) | 区间向量 (Range Vector) |
|---|---|---|
| 定义 | 每个时间序列在单个时间点上的最新样本值。 | 每个时间序列在一段时间范围内的一组样本值。 |
| 语法示例 | http_requests_total{status="200"} |
http_requests_total{status="200"}[5m] |
| 返回结果 | 一组键值对(标签集 → 值)。 | 一组键值对(标签集 → 值数组)。 |
| 典型用途 | 当前状态查询、告警规则、简单算术运算。 | 速率计算(rate/irate)、分位数计算(quantile_over_time)、滑动窗口聚合。 |
| 在误差预算中的角色 | 获取当前 SLI 值或当前错误计数。 | 计算过去窗口(如 1h、7d)内的错误率或可用性。 |
关键区分: 瞬时向量是“快照”,区间向量是“片段”。在误差预算计算中,
rate() 函数必须作用于区间向量,因为它需要观察一段时间内的增量来计算每秒速率。
以下 SVG 展示了 PromQL 引擎如何从时间序列数据库中提取这两种向量:
2.2 向量匹配模式
当使用二元运算符(如 +、-、/、and、or)连接两个向量时,PromQL 需要确定如何匹配标签。理解匹配模式是避免查询错误和性能问题的关键。
2.2.1 一对一匹配 (One-to-One)
这是最严格的模式。运算符两侧的向量必须具有完全相同的标签集。PromQL 会逐对匹配具有相同标签的时间序列。如果一侧存在另一侧没有的标签组合,该序列会被丢弃。
- 语法:
vector1 <operator> vector2 - 典型场景: 对两个具有完全相同标签维度的指标进行运算,例如计算两个计数器之间的差值。
- 误差预算案例: 计算每个服务实例的当前错误率与历史基线错误率的差值,要求两个指标具有完全相同的
service、instance标签。
2.2.2 多对一 / 一对多匹配 (Many-to-One / One-to-Many)
当一侧向量拥有更细粒度的标签(更多维度)时,需要使用 group_left 或 group_right 关键字。这允许将“多”侧的多条序列聚合到“一”侧的一条序列上。
- 语法:
vector1 <operator> on(label_list) group_left(label_list) vector2 - 关键点: 必须使用
on()子句显式指定用于匹配的标签。未在on()中列出的标签,在“多”侧会被保留,在“一”侧则被忽略。 - 误差预算案例: 将每个实例的详细错误率(带有
instance标签)与一个全局的 SLO 目标(没有instance标签)进行比较。此时,全局 SLO 是“一”侧,实例错误率是“多”侧,使用group_left。
性能警告: 滥用
group_left 或 group_right 会导致 PromQL 引擎产生巨大的笛卡尔积,严重消耗内存和 CPU。在误差预算台账中,应优先通过数据建模(如统一标签)来避免这种模式,或确保“多”侧的基数(唯一标签组合数)在可控范围内。
下面的 SVG 图直观对比了三种匹配模式的数据流:
2.3 实战代码示例:匹配模式在误差预算中的误用
假设我们有两个指标:
sli_errors_total{service="api", instance="host1"}(细粒度)slo_target{service="api"}(粗粒度,值为 0.99)
错误写法(导致空结果或错误):
# 错误:标签不匹配,无法进行一对一运算
sli_errors_total / slo_target
正确写法(使用多对一匹配):
# 正确:使用 on(service) 指定匹配键,group_left 保留 instance 标签
sli_errors_total / on(service) group_left() slo_target
优化要点: 在误差预算台账中,我们通常会将 SLO 目标作为配置项注入到 Prometheus 的标签中(例如通过 relabel_configs),使其与 SLI 指标具有相同的标签结构。这样就能使用最高效的“一对一”匹配,避免
group_left 带来的性能开销。