4. PromQL 入门:即时查询与范围查询、选择器与标签匹配、常用函数(rate、increase、avg)

好,咱们进入 PromQL 的学习。说实话,PromQL 是 Prometheus 的灵魂。你采集了那么多指标,最终怎么用起来?全靠这门查询语言。我刚开始接触时也觉得语法有点怪,但用顺手了就会发现——它其实很符合运维直觉。

4.1 即时查询 vs 范围查询

先搞清楚这两个概念。说白了,就是「查一个时间点」还是「查一段时间」的区别。

4.1.1 即时查询(Instant Query)

即时查询返回的是当前时刻的一个样本值。比如:

node_cpu_seconds_total

这条语句会返回所有 CPU 核在当前时刻的累计运行时间。嗯,这里要注意——它只返回一个时间点,不是一段区间。

我在项目中遇到过一个问题:用即时查询看 CPU 使用率,结果发现数值忽高忽低。为什么?因为即时查询只抓取最新值,而 CPU 计数器是不断累加的。你看到的其实是「当前累计值」,不是「使用率」。所以后来我改用 rate 函数,这个后面会讲。

即时查询的特点:

  • 返回单个时间点的值
  • 适合查看当前状态
  • 常用于告警规则

4.1.2 范围查询(Range Query)

范围查询就厉害了。它返回一段时间内的所有样本点。语法上多了一个中括号:

node_cpu_seconds_total[5m]

这条语句会返回过去 5 分钟内,每个 CPU 核的所有采样值。你想想看,有了这些历史数据,你才能做趋势分析、计算速率、求平均值。

我个人习惯用 1m、5m、1h 这几个时间窗口。太短了样本点不够,太长了数据量太大。具体用哪个,取决于你的采集间隔和业务场景。

小技巧:范围查询的结果是一个「矩阵」,不是「向量」。你不能直接对它做加减运算,得先用函数处理一下。

4.2 选择器与标签匹配

Prometheus 的指标都是带标签的。比如 node_cpu_seconds_total 这个指标,它可能有 cpu="0"mode="idle" 这样的标签。你想精确筛选数据,就得用选择器。

4.2.1 精确匹配

最常用的就是等号匹配:

node_cpu_seconds_total{cpu="0", mode="idle"}

这条语句只返回 CPU 0 的空闲时间。我在项目中经常用这种方式来缩小查询范围,避免返回太多无用数据。

4.2.2 正则匹配

有时候你想匹配一组标签值。比如查所有 CPU 核的空闲时间:

node_cpu_seconds_total{cpu=~"0|1|2", mode="idle"}

这里 =~ 表示正则匹配。也可以用 != 排除某些值,用 !~ 排除正则匹配的值。

避坑指南:我曾经在正则表达式里写了个 .*,结果匹配到了所有标签值,导致查询超时。正则匹配虽然灵活,但性能开销大,别滥用。

4.2.3 标签匹配的常见模式

操作符 含义 示例
= 精确匹配 job="node"
!= 不等于 job!="node"
=~ 正则匹配 job=~"node|web"
!~ 正则排除 job!~"node.*"

4.3 常用函数:rate、increase、avg

好了,前面都是基础。现在咱们聊聊真正干活用的函数。我敢说,你日常 80% 的查询都离不开这三个。

4.3.1 rate():计算每秒增长率

rate() 是 PromQL 里最常用的函数。它计算一个计数器指标在指定时间窗口内的每秒平均增长率

rate(node_cpu_seconds_total{mode="idle"}[5m])

这条语句返回过去 5 分钟内,CPU 空闲时间的每秒增长率。你想想看,CPU 计数器是不断累加的,直接看原始值没有意义。但用 rate 处理后,你就能看到「每秒增加了多少」,这才是真正的使用率。

我在项目中遇到过一个问题:用 rate 查 CPU 使用率,结果发现数值超过 100%。为什么?因为 CPU 有多个核,每个核的 idle 时间加起来可能超过 1 秒。后来我改用 1 - rate(node_cpu_seconds_total{mode="idle"}[5m]) 来算使用率,这才对了。

rate() 的注意事项:

  • 只适用于 Counter 类型的指标
  • 时间窗口至少是采集间隔的 4 倍(比如采集间隔 15s,窗口至少 1m)
  • 如果指标重置了(比如重启),rate 会自动处理

4.3.2 increase():计算增量

increase() 和 rate 很像,但它返回的是总增量,不是每秒增长率。

increase(node_network_receive_bytes_total[1h])

这条语句返回过去 1 小时内,网络接口接收的总字节数。说白了,就是「这段时间里增加了多少」。

我个人习惯用 increase 来算流量、请求量、错误数这类指标。比如你想知道过去 5 分钟有多少 500 错误:

increase(http_requests_total{status="500"}[5m])

小技巧:increase 和 rate 的底层计算逻辑是一样的。区别只在于单位——rate 是「每秒」,increase 是「总量」。如果你需要看趋势,用 rate;如果需要看绝对值,用 increase。

4.3.3 avg():求平均值

avg() 就简单了,它对一组时间序列求平均值。

avg(rate(node_cpu_seconds_total{mode="idle"}[5m]))

这条语句先计算每个 CPU 核的空闲率,然后对所有核求平均。结果就是一个数字——整个机器的平均 CPU 空闲率。

avg 经常和 by 子句一起用,按某个标签分组求平均:

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

这条语句按机器分组,返回每台机器的平均 CPU 空闲率。我在项目中用这个来对比不同机器的负载情况,一眼就能看出哪台机器压力大。

避坑指南:我曾经用 avg 对一组差异很大的指标求平均,结果得到一个「四不像」的值。比如有的机器 CPU 100%,有的 10%,平均下来 55%——这个值没有任何实际意义。所以用 avg 之前,先想想你的数据是不是适合求平均。

4.4 实战:组合使用

好了,咱们把上面这些知识串起来,写一个完整的查询。假设你想看每台机器的 CPU 使用率(过去 5 分钟的平均值):

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

这条语句做了几件事:

  1. 用 rate 计算每个 CPU 核的空闲率
  2. 用 avg by (instance) 按机器求平均
  3. 用 100 减去空闲率,得到使用率

嗯,这就是一个典型的 PromQL 查询。你想想看,从原始计数器到最终的可视化数据,中间就这几步。但每一步都有讲究——选对时间窗口、用对函数、匹配对标签。

我个人建议,刚开始学 PromQL 时,多在 Prometheus 的 Web UI 上试。输入一条查询,看看结果,调整一下,再看看。慢慢你就会找到感觉。

总结一下:

  • 即时查询看当前值,范围查询看历史趋势
  • 标签匹配帮你精确筛选数据
  • rate 算增长率,increase 算增量,avg 算平均值
  • 组合使用才能写出真正有用的查询

下一章咱们聊聊告警规则怎么写。到时候你会看到,PromQL 的威力远不止查数据这么简单。