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" 而非依赖默认值。
PromQL 数据类型与告警自愈流程关系 Prometheus TSDB PromQL 查询引擎 Instant Vector 当前时刻快照 Range Vector 时间窗口样本集 Scalar 单一数值 String 标签/消息 告警规则 expr(仅接受 Instant Vector) 必须转换 rate()/avg_over_time() 自愈动作(Webhook / 脚本) 关键约束 • 告警 expr 只接受 Instant Vector • Range Vector 需转换

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 时长。