3. PromQL 入门与实践:基础语法、选择器、操作符与常用函数

PromQL(Prometheus Query Language)是 Prometheus 内置的数据查询语言,也是告警规则与自愈剧本的数据基石。在 Ansible 自愈场景中,PromQL 负责回答“当前系统状态是否异常”,而 Ansible 负责执行“如何修复异常”。本章将系统讲解 PromQL 的核心语法、选择器、操作符以及生产环境最常用的四个函数。

3.1 PromQL 基础语法与数据类型

PromQL 表达式求值后返回以下四种数据类型之一:

数据类型说明示例
瞬时向量 (Instant Vector)一组时间序列,每个序列包含一个最新采样值node_cpu_seconds_total
区间向量 (Range Vector)一组时间序列,每个序列包含一段时间范围内的多个采样值node_cpu_seconds_total[5m]
标量 (Scalar)一个简单的数字浮点值3.14
字符串 (String)一个简单的字符串值(目前仅用于某些函数)"critical"
实践要点:告警规则和 Ansible 自愈触发条件几乎全部基于瞬时向量。区间向量主要用于 rate、increase 等聚合函数内部计算,不直接作为告警条件输出。

3.2 选择器:精准定位监控指标

选择器用于从 Prometheus 时间序列数据库中筛选出目标指标。根据返回类型分为瞬时向量选择器和区间向量选择器。

3.2.1 瞬时向量选择器

语法:<metric_name>{<label_match>}

  • 精确匹配:= 例:node_memory_MemAvailable_bytes{instance="web-01"}
  • 正则匹配:=~ 例:node_memory_MemAvailable_bytes{instance=~"web-.*"}
  • 反向匹配:!= 例:node_memory_MemAvailable_bytes{instance!="web-01"}
  • 反向正则:!~ 例:node_memory_MemAvailable_bytes{instance!~"db-.*"}

3.2.2 区间向量选择器

在指标名或选择器后附加 [<duration>],返回过去一段时间内的所有样本。

# 过去 5 分钟所有 web 节点的 CPU 使用率原始数据
node_cpu_seconds_total{instance=~"web-.*",mode="idle"}[5m]
常见误区:区间向量不能直接用于算术运算或告警条件判断。必须先通过 rate、increase、avg_over_time 等函数将其转换为瞬时向量。

3.3 操作符:连接与计算

PromQL 支持四类操作符,用于构建复杂的告警表达式。

操作符类别符号典型用途
算术+ - * / % ^计算 CPU 使用率、内存使用百分比
比较== != > < >= <=触发告警阈值判断
逻辑/集合and or unless组合多个告警条件
向量匹配on ignoring group_left group_right多指标关联计算(如 CPU 使用率 = 1 - idle/total)

3.3.1 向量匹配示例:计算 CPU 使用率

# 计算每个实例的 CPU 使用率(非 idle 时间占比)
(1 - avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m]))
      / avg by(instance)(rate(node_cpu_seconds_total[5m]))) * 100
自愈场景提示:当 CPU 使用率 > 90% 持续 5 分钟时,Ansible 可以触发自动扩容或重启异常进程。比较操作符 > 是告警规则的核心。

3.4 常用函数:rate, increase, histogram_quantile

以下四个函数是告警规则和自愈剧本中使用频率最高的 PromQL 函数。

3.4.1 rate() — 计算每秒平均增长率

适用于 Counter 类型指标(如请求总数、CPU 时间片总数)。计算区间向量在指定时间窗口内的每秒平均增长率。

# 过去 5 分钟,每个实例每秒 HTTP 请求数
rate(http_requests_total[5m])

# 过去 5 分钟,每个实例每秒 CPU 非 idle 时间
rate(node_cpu_seconds_total{mode!="idle"}[5m])

3.4.2 increase() — 计算区间内的增量

与 rate 类似,但返回的是整个时间窗口内的增量,而非每秒速率。

# 过去 1 小时内,每个实例的 HTTP 请求总数增量
increase(http_requests_total[1h])

# 过去 5 分钟内,每个实例接收的字节数增量
increase(node_network_receive_bytes_total[5m])
选择建议:告警规则中优先使用 rate(速率更直观,阈值不随窗口大小变化);容量规划或计费场景使用 increase(总量更易理解)。

3.4.3 histogram_quantile() — 计算分位数

适用于 Histogram 类型指标(如请求延迟、响应大小分布)。根据累积直方图计算指定分位数(0 ≤ φ ≤ 1)。

# 过去 5 分钟,每个实例的 P99 请求延迟(单位:秒)
histogram_quantile(0.99,
  rate(http_request_duration_seconds_bucket[5m])
)

# 过去 5 分钟,每个实例的 P50 请求延迟
histogram_quantile(0.50,
  rate(http_request_duration_seconds_bucket[5m])
)
重要限制:histogram_quantile 必须在 rate 或 increase 之后计算,且输入必须是 _bucket 后缀的累积直方图指标。分位数计算对样本数量敏感,样本太少时结果可能不准确。

3.5 PromQL 核心函数与选择器关系图

PromQL 核心函数与选择器关系图 时间序列数据库 选择器过滤 瞬时向量 区间向量 [5m] 算术/比较操作符 rate / increase 告警规则 / Ansible 触发 histogram_quantile 输入:_bucket 区间向量 输出:分位数瞬时向量 必须配合 rate() 使用

3.6 综合实践:构建一条自愈告警表达式

以下示例展示如何将 PromQL 选择器、操作符和函数组合成一条可用于 Ansible 自愈的告警规则。

# 场景:当 web 节点 P99 延迟 > 2s 且持续 5 分钟时触发告警
# 表达式分解:
# 1. 选择 web 实例的延迟直方图
# 2. 计算过去 5 分钟的每秒 bucket 增长率
# 3. 计算 P99 分位数
# 4. 与阈值 2 比较

- alert: WebP99High
  expr: |
    histogram_quantile(0.99,
      rate(http_request_duration_seconds_bucket{job="web"}[5m])
    ) > 2
  for: 5m
  labels:
    severity: critical
  annotations:
    summary: "Web 服务 P99 延迟超过 2s (当前值: {{ $value | humanizeDuration }})"
Ansible 自愈联动:当 Prometheus 触发 WebP99High 告警后,Ansible Tower/AWX 通过 webhook 接收告警,自动执行以下剧本:
1. 重启异常节点的 Nginx/应用进程
2. 如果 2 分钟内未恢复,则从负载均衡摘除该节点
3. 通知值班工程师介入

3.7 本章小结

  • 选择器是 PromQL 的入口,掌握 =、=~、!=、!~ 四种匹配模式即可覆盖 95% 场景。
  • 区间向量必须配合 rate、increase 等函数使用,不能直接参与告警条件判断。
  • rate 用于计算每秒速率,increase 用于计算增量,histogram_quantile 用于计算延迟/响应大小分位数。
  • 告警规则中的 for 字段与 PromQL 中的时间窗口 [5m] 是两个独立概念:前者是告警持续多久才触发,后者是计算数据的时间范围。