4、PromQL入门:基本查询语法、选择器、时间范围、瞬时向量与区间向量,以及常用函数(rate、irate、increase等)

PromQL(Prometheus Query Language)是Prometheus内置的数据查询语言,它不仅是Grafana面板数据可视化的核心驱动,更是日常监控排障、告警规则编写、容量评估的基石。与SQL或LogQL不同,PromQL是围绕时序数据模型设计的,其核心操作对象是带有标签(Label)的指标(Metric)及其随时间变化的数据点。本章将从基本语法出发,深入剖析选择器、时间范围、瞬时向量与区间向量的本质区别,并重点讲解rate、irate、increase等常用函数的适用场景与底层逻辑,帮助学员建立扎实的查询思维。

PromQL 核心概念与查询链路 时序数据库 (TSDB) PromQL 查询 (即时/范围) 选择器 精确/正则/负向 时间范围 [5m] / [1h] 瞬时向量 当前时间点的一组序列 (每个序列一个值) 区间向量 时间范围内的一组序列 (每个序列多个值) 常用函数 rate / irate / increase 图表 / 告警 ● 数据采集 → 存储 → 查询 → 可视化/告警 ● 选择器决定“查哪些序列”,时间范围决定“看多长窗口” ● 函数将原始样本转换为可用的速率/增量指标

上图展示了PromQL查询的核心链路:从时序数据库出发,通过选择器筛选目标序列,结合时间范围确定数据窗口,最终得到瞬时向量或区间向量,再经由函数加工后用于图表展示或告警判定。下面我们将逐一拆解每个环节。

4.1 基本查询语法与选择器

核心原理

PromQL的查询表达式由指标名和标签选择器组成。指标名用于定位具体的监控项(如 http_requests_total),而标签选择器则用于过滤出符合特定维度条件的序列。一个完整的查询表达式形如:http_requests_total{status="500", method="GET"}。其中花括号内的部分就是标签选择器,它支持四种匹配操作:=(精确匹配)、!=(反向精确匹配)、=~(正则匹配)、!~(反向正则匹配)。

判断方法或操作流程

在实际使用中,选择器的编写遵循以下步骤:

  1. 确定指标名:通过 curl http://localhost:9090/api/v1/label/__name__/values 或Grafana的Explore页面查看所有可用的指标名。
  2. 筛选必要标签:根据业务维度(如实例、接口、状态码)添加标签条件。例如,要查看所有非200状态码的请求,可使用 http_requests_total{status!="200"}。
  3. 使用正则处理复杂维度:当需要匹配多个值或模糊匹配时,使用正则。例如 http_requests_total{handler=~"/api/v1/.*"} 匹配所有以 /api/v1/ 开头的接口。
  4. 注意空标签匹配:{label=""} 可以匹配到该标签不存在的序列,这在排查数据缺失时非常有用。

案例拆解或实战场景

假设我们有一个电商应用,需要监控不同支付渠道的成功率。指标为 payment_requests_total,标签包括 channel(alipay/wechat/card)和 result(success/failure)。要查询支付宝的成功请求数,表达式为:payment_requests_total{channel="alipay", result="success"}。若要同时查看支付宝和微信的失败请求,可使用正则:payment_requests_total{channel=~"alipay|wechat", result="failure"}。这种精确的维度筛选是后续计算成功率的基础。

常见误区或总结复盘

风险提示:不要滥用正则匹配。正则查询会扫描所有标签值,在标签基数极高(如用户ID)时会导致查询性能严重下降。建议将高基数标签(如用户ID、请求ID)从指标标签中移除,改用日志系统或Trace系统处理。

此外,注意标签值中的特殊字符(如点号、斜杠)在正则中需要转义。例如匹配 /api/v1 应写为 handler=~"/api/v1/.*",而不是 handler="/api/v1"(后者是精确匹配,不会匹配到带路径参数的序列)。

4.2 时间范围与向量类型

核心原理

PromQL查询分为瞬时查询和范围查询。瞬时查询返回的是查询时刻(或指定时间点)的数据,结果为瞬时向量(Instant Vector),每个时间序列只有一个样本值。范围查询则返回一个时间窗口内的所有样本,结果为区间向量(Range Vector),每个序列包含多个按时间排序的样本点。范围查询通过在指标选择器后添加方括号实现,如 http_requests_total[5m] 表示查询过去5分钟内的所有数据点。

判断方法或操作流程

选择瞬时还是区间向量,取决于后续操作:

  • 如果只是查看当前值(如当前CPU使用率),使用瞬时向量。
  • 如果需要计算速率、增量或进行趋势分析,必须使用区间向量作为函数输入。
  • 在Grafana面板中,通常由面板的“查询类型”设置决定,但理解底层差异有助于调试。

时间范围的选择需考虑采集间隔。例如,若采集间隔为15秒,[5m] 窗口内约有20个样本点,足以计算稳定的速率;而 [1m] 只有4个样本,计算出的速率波动会很大。

案例拆解或实战场景

假设我们要监控Nginx的QPS(每秒请求数)。原始指标为 nginx_http_requests_total(Counter类型)。直接查询该指标只能看到累计值,无法反映当前速率。正确的做法是使用 rate(nginx_http_requests_total[5m])。这里 [5m] 指定了区间向量,rate 函数计算该窗口内每秒平均增长率。如果改用 irate(nginx_http_requests_total[5m]),则计算的是窗口内最后两个样本点的瞬时速率,对突发流量更敏感,但曲线更尖锐。

常见误区或总结复盘

经验提醒:区间向量的时间范围不宜过短,至少应包含4-5个采集周期。否则,rate 函数可能因样本不足而返回 NaN 或产生剧烈抖动。同时,过长的窗口(如 [1h])会平滑掉短时突刺,不利于告警检测。

另一个常见误区是混淆 increase 与 rate。 increase(v[5m]) 返回窗口内Counter的增量值(如5分钟内请求增加了多少次),而 rate 返回的是每秒平均速率。两者关系为:increase(v[5m]) = rate(v[5m]) * 300(300秒)。在告警规则中,若需要判断“5分钟内错误数超过100”,应使用 increase(errors_total[5m]) > 100,而不是 rate。

4.3 常用函数:rate、irate、increase 深度解析

核心原理

这三个函数均用于处理Counter类型指标(只增不减的累计值)。rate 计算区间向量在指定时间窗口内的每秒平均增长率,其算法是:取窗口内第一个和最后一个样本值,计算差值并除以时间差(秒)。irate 计算的是瞬时增长率,它仅使用窗口内最后两个样本点,计算它们的差值除以时间差。increase 则直接返回窗口内Counter的增量值(即最后一个值减去第一个值)。

判断方法或操作流程

选择哪个函数,取决于监控目标:

函数输出含义适用场景特点
rate()每秒平均速率长期趋势、告警阈值(如QPS > 1000)平滑,抗抖动,适合稳定指标
irate()每秒瞬时速率突发流量检测、短时峰值分析灵敏,反映最新变化,但曲线毛刺多
increase()窗口内总增量统计总量(如5分钟错误数)直观,适合与固定阈值比较

案例拆解或实战场景

我们以CPU使用率监控为例。假设指标 node_cpu_seconds_total 是Counter类型,标签 mode 区分cpu、idle、user等。要计算CPU使用率,需先计算非空闲时间的速率,再除以总时间速率:

100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

这里使用 rate 是因为CPU使用率是连续变化的,需要平滑的平均值。若改用 irate,则曲线会频繁跳动,不利于观察整体趋势。而在告警规则中,若希望快速响应CPU飙高,可使用 irate 设置短窗口(如 [1m])来捕捉瞬时尖峰。

常见误区或总结复盘

风险提示:Counter指标在重启或重置时会归零,导致 rate 和 increase 计算出现负值或异常跳变。Prometheus的 rate 函数会自动处理Counter重置(检测到值下降时,按从零开始计算),但 increase 在遇到重置时可能会返回错误结果。因此,在涉及可能重置的Counter时,优先使用 rate 或 irate。

另外,irate 对样本间隔非常敏感。如果采集间隔不规律(如某些实例延迟上报),irate 可能产生极端值。此时应使用 rate 并适当增大窗口来平滑数据。最后,所有函数都要求输入是区间向量,如果误传瞬时向量,查询会报错。

4.4 综合实战:构建一个完整的监控查询

核心原理

将选择器、时间范围、函数和聚合操作(如 sum、avg、by)组合,可以构建复杂的监控查询。聚合操作允许我们按标签维度合并多个序列,例如按实例汇总所有接口的请求速率。

操作流程

假设我们要监控一个微服务集群的总QPS,并按实例维度拆分。步骤如下:

  1. 确定基础指标:http_requests_total(Counter,标签:instance、path、method)。
  2. 计算每个序列的速率:rate(http_requests_total[5m])。
  3. 按实例聚合:sum by (instance) (rate(http_requests_total[5m]))。
  4. 若需总QPS:去掉 by 子句,直接 sum(rate(http_requests_total[5m]))。

案例拆解

某次故障排查中,我们发现支付接口响应时间上升。通过Grafana查询:histogram_quantile(0.95, sum by (le) (rate(http_request_duration_seconds_bucket{path="/api/pay"}[5m]))),得到95分位延迟。同时,用 sum by (instance) (rate(http_requests_total{path="/api/pay", status="500"}[5m])) 查看错误率。通过对比发现,错误率集中在某个实例,进一步定位到该实例的磁盘IO瓶颈。这个案例展示了PromQL从全局到局部、从现象到根因的排查路径。

常见误区或总结复盘

复盘要点:1) 始终确认指标类型(Counter/Gauge/Histogram),不同函数适用于不同类型;2) 聚合操作会丢失标签维度,需谨慎使用 by 子句保留必要维度;3) 在Grafana中调试时,先用Explore页面验证查询结果,再创建面板;4) 对于高基数标签(如 path 包含用户ID),应提前设计标签降基方案。

最后,建议在团队内建立PromQL查询规范,例如:统一使用 rate 而非 irate 作为默认速率函数;所有告警规则必须使用 for 子句设置持续时间,避免瞬时抖动误报;定期审查慢查询,利用 label_replace 或Recording Rule优化复杂表达式。掌握PromQL不仅是语法学习,更是监控思维的建设过程。