2. PromQL 基础回顾:数据类型与核心概念
在深入告警自愈剧本的 PromQL 优化之前,必须牢固掌握 PromQL 的四种数据类型及其核心概念。这些类型决定了查询引擎如何解析表达式、如何聚合数据以及如何触发告警。理解它们之间的差异,是编写高效、准确告警规则的前提。
2.1 四种数据类型总览
PromQL 的查询结果严格分为四种类型,每种类型对应不同的操作符和函数。下表从定义、典型场景和告警用途三个维度进行对比:
| 数据类型 | 定义 | 典型场景 | 告警自愈中的用途 |
|---|---|---|---|
| Instant Vector | 同一时间戳下的一组时间序列,每个序列包含一个样本值。 | node_cpu_seconds_total{ mode="idle" } |
告警规则中的 expr 必须返回 Instant Vector;自愈动作的触发条件判断。 |
| Range Vector | 一组时间序列,每个序列包含一段时间范围内的多个样本值。 | node_cpu_seconds_total{ mode="idle" }[5m] |
计算速率、趋势、滑动窗口聚合(如 avg_over_time),用于检测慢速故障。 |
| Scalar | 一个单一的数值,没有时间戳和标签。 | 1、3.14、time() |
算术运算的右操作数、阈值比较、自愈脚本中的参数传递。 |
| String | 一个简单的字符串值,在 PromQL 中功能有限。 | "warning"、alertname 标签值 |
告警标签的静态值、自愈通知中的消息模板。 |
核心原则:Prometheus 告警规则中的
expr 字段只接受 Instant Vector 类型。任何返回 Range Vector、Scalar 或 String 的表达式都无法直接作为告警条件,必须通过函数或操作符转换为 Instant Vector。
2.2 Instant Vector(瞬时向量)—— 告警的基石
Instant Vector 是 PromQL 中最常用、最重要的数据类型。它表示在 一个特定时间点 上,所有匹配的时间序列及其最新样本值。每个时间序列由一组标签唯一标识。
- 语法特征:选择器后不加时间范围,如
http_requests_total{ status="500" }。 - 内部结构:每个元素包含
{标签集合} → 值。 - 告警语义:当表达式返回的 Instant Vector 中至少有一个样本值满足阈值条件时,告警即被触发。
# 返回当前所有 5xx 请求的瞬时计数(每个 status 标签组合一个序列)
http_requests_total{ status=~"5.." }
# 告警规则示例:如果任何 5xx 请求的瞬时值大于 100,则触发告警
# expr: http_requests_total{ status=~"5.." } > 100
2.3 Range Vector(范围向量)—— 趋势与窗口分析
Range Vector 在 Instant Vector 的基础上增加了 时间维度。它返回每个时间序列在过去一段时间窗口内的所有样本值,而不是仅返回最新值。这是计算速率、增长率和滑动平均的基础。
- 语法特征:选择器后紧跟时间范围,如
http_requests_total[5m]。 - 内部结构:每个元素包含
{标签集合} → [值1, 值2, ...]。 - 常见转换函数:
rate()、irate()、increase()、avg_over_time()、max_over_time()等,这些函数将 Range Vector 转换为 Instant Vector。
# 返回过去 5 分钟内,每个 5xx 状态码的请求样本列表
http_requests_total{ status=~"5.." }[5m]
# 计算过去 5 分钟的平均每秒速率(返回 Instant Vector)
rate(http_requests_total{ status=~"5.." }[5m])
告警自愈陷阱:直接在告警规则中使用 Range Vector(如
http_requests_total[5m] > 100)会导致语法错误。必须先用 rate、avg_over_time 等函数将其转换为 Instant Vector。此外,时间窗口的选择直接影响告警的灵敏度和稳定性——窗口过短易产生抖动,窗口过长则延迟告警。
2.4 Scalar(标量)与 String(字符串)
Scalar 和 String 在 PromQL 中通常作为辅助角色出现,但在告警自愈剧本中扮演着不可或缺的支撑作用。
| 类型 | 来源 | 在告警自愈中的典型用法 |
|---|---|---|
| Scalar | 数字字面量、time()、scalar() 函数 |
作为比较操作的右值(如 > 0.8 中的 0.8);在自愈脚本中作为参数传递给 Webhook。 |
| String | 标签值、"string" 字面量 |
告警标签的静态赋值(如 severity="critical");自愈通知模板中的占位符内容。 |
# Scalar 示例:获取当前 Unix 时间戳
time()
# String 示例:在告警规则中设置静态标签
# labels:
# team: "platform"
# runbook: "https://wiki.example.com/runbook"
2.5 核心概念:时间序列、标签与匹配模式
理解数据类型后,还需掌握三个贯穿 PromQL 始终的核心概念:
- 时间序列(Time Series):由指标名 + 一组标签唯一标识的数据流。例如
node_memory_MemAvailable_bytes{ instance="server1", job="node" }是一个独立的时间序列。 - 标签(Label):键值对,用于对时间序列进行多维度的筛选和聚合。标签是 Prometheus 数据模型的灵魂。
- 匹配模式:在向量选择器中,支持精确匹配(
=)、正则匹配(=~)、反向匹配(!=、!~)。
告警自愈优化要点:在编写告警规则时,应尽量使用精确的标签匹配来缩小查询范围,避免使用
{__name__=~".+"} 等全量匹配。这不仅能提升查询性能,还能减少误告警。例如,针对 CPU 使用率告警,应明确指定 mode!="idle" 而非依赖默认值。
2.6 数据类型转换:从 Range Vector 到 Instant Vector
由于告警规则只接受 Instant Vector,将 Range Vector 转换为 Instant Vector 是编写告警表达式的核心技能。下表列出了最常用的转换函数及其适用场景:
| 函数 | 输入 | 输出 | 典型告警场景 |
|---|---|---|---|
rate() |
Counter 类型的 Range Vector | 每秒平均增长率(Instant Vector) | QPS 突增、错误率飙升 |
irate() |
Counter 类型的 Range Vector | 每秒瞬时增长率(基于最后两个样本) | 对突发敏感的高频告警 |
increase() |
Counter 类型的 Range Vector | 时间窗口内的增量(Instant Vector) | 磁盘空间增长量、请求总数增量 |
avg_over_time() |
Gauge 类型的 Range Vector | 时间窗口内的平均值(Instant Vector) | 平均 CPU 使用率、平均延迟 |
max_over_time() |
Gauge 类型的 Range Vector | 时间窗口内的最大值(Instant Vector) | 峰值内存、峰值连接数 |
quantile_over_time() |
Gauge 类型的 Range Vector | 时间窗口内的分位数(Instant Vector) | P99 延迟告警 |
# 错误率告警:将 Range Vector 通过 rate() 转换为 Instant Vector
# 过去 5 分钟的错误请求速率 / 总请求速率 > 5%
rate(http_requests_total{ status=~"5.." }[5m])
/
rate(http_requests_total[5m])
> 0.05
# 内存峰值告警:将 Range Vector 通过 max_over_time() 转换
max_over_time(node_memory_MemAvailable_bytes[10m]) < 1e9
优化实践:在告警自愈剧本中,优先使用
rate() 而非 irate() 来避免短时抖动导致的误告警。对于需要平滑趋势的场景,可结合 avg_over_time(rate(...)[5m]) 实现双重平滑。同时,时间窗口的选择应与告警检查周期(for 语句)协调,通常窗口长度应大于等于 for 时长。