3、PromQL入门:PromQL基础语法、选择器与聚合操作、常用函数实战

监控系统搭好了,数据也进来了。但说实话,如果不会查数据,那 Prometheus 就是个摆设。PromQL 就是这门查询语言,我刚开始接触时也觉得有点绕,但用顺手了会发现它真的很强大。

3.1 PromQL 基础语法

PromQL 的查询结果有两种类型:瞬时向量范围向量。说白了,瞬时向量就是「当前这一刻的数据」,范围向量是「过去一段时间的数据」。

举个例子:

# 查询当前 CPU 使用率
node_cpu_seconds_total

# 查询过去 5 分钟的 CPU 使用率
node_cpu_seconds_total[5m]

嗯,这里要注意:不加中括号就是瞬时向量,加了就是范围向量。我在项目中经常犯这个错,查了半天发现数据不对,原来是忘了加时间范围。

PromQL 还支持四种数据类型:

类型 说明 示例
瞬时向量 一组时间序列,每个序列只有一个样本 node_memory_MemTotal_bytes
范围向量 一组时间序列,每个序列包含多个样本 node_memory_MemTotal_bytes[1h]
标量 一个单纯的数字 1024
字符串 文本值,用得少 "production"
我的小技巧:刚开始学 PromQL 时,建议先在 Prometheus 的 Web UI 的「Graph」页面里试。输入查询语句,点「Execute」,马上能看到结果。比看文档直观多了。

3.2 选择器:怎么精确找到你要的数据

光写个指标名,查出来的数据可能一大堆。比如 node_cpu_seconds_total 会返回所有 CPU 核的数据。这时候就需要用选择器来过滤。

PromQL 支持三种选择器:

  • 精确匹配(=):标签值必须完全相等
  • 正则匹配(=~):标签值匹配正则表达式
  • 反向匹配(!=, !~):不等于或不匹配

看几个例子:

# 只看 CPU 0 的数据
node_cpu_seconds_total{cpu="0"}

# 只看 user 和 system 模式
node_cpu_seconds_total{mode=~"user|system"}

# 排除 idle 模式
node_cpu_seconds_total{mode!="idle"}

我曾经在排查一个性能问题时,发现某个节点的 CPU 使用率异常高。用 node_cpu_seconds_total{mode!="idle"} 一查,发现是某个进程在疯狂占用 iowait。嗯,选择器用得好,排查效率翻倍。

3.3 聚合操作:把数据汇总起来

单个指标看完了,但有时候我们需要看整体情况。比如所有 CPU 核的平均使用率,或者所有节点的内存总量。这时候就要用聚合操作。

常用的聚合函数有:

函数 作用 示例
sum() 求和 sum(node_cpu_seconds_total)
avg() 求平均值 avg(node_cpu_seconds_total)
max() 最大值 max(node_memory_MemFree_bytes)
min() 最小值 min(node_memory_MemFree_bytes)
count() 计数 count(node_cpu_seconds_total)

聚合操作还可以配合 bywithout 来分组。你想想看,如果我想看每个节点的 CPU 平均使用率,可以这样写:

# 按 instance 分组,计算平均 CPU 使用率
avg by(instance) (node_cpu_seconds_total{mode="user"})

我个人习惯用 by 来指定保留哪些标签,这样逻辑更清晰。比如查每个机房的平均延迟:

avg by(datacenter) (http_request_duration_seconds)
重点:聚合操作会合并多个时间序列。如果不加 by,默认会聚合所有标签,结果就变成一个标量值。这在做全局大盘时很有用,但排查问题时容易丢失细节。

3.4 常用函数实战

PromQL 内置了几十个函数,但说实话,日常用得最多的就那么几个。我挑几个最实用的讲讲。

3.4.1 rate() 和 irate():计算速率

这两个函数专门处理 Counter 类型的数据。Counter 是只增不减的,比如请求总数、CPU 时间。直接看数值没意义,要看它的变化速率。

# 过去 5 分钟的平均每秒请求数
rate(http_requests_total[5m])

# 过去 5 分钟的瞬时每秒请求数(更敏感)
irate(http_requests_total[5m])

rate() 算的是平均值,适合看长期趋势。irate() 算的是最后两个点的变化率,适合看突发流量。我在做告警时,一般用 rate() 来设置阈值,因为更稳定,不容易误报。

3.4.2 increase():计算增量

这个函数直接告诉你「这段时间内增加了多少」。比如:

# 过去 1 小时内增加了多少请求
increase(http_requests_total[1h])

我曾经用这个函数来统计每天的 API 调用量,配合 Grafana 的表格展示,老板看了直点头。

3.4.3 histogram_quantile():计算分位数

这个函数专门配合 Histogram 类型使用。比如你想知道「99% 的请求在多少毫秒内完成」:

# 计算 P99 延迟
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
注意:使用 histogram_quantile() 时,必须保证数据是 Histogram 类型,并且有 _bucket 后缀的指标。否则算出来的结果毫无意义。

3.4.4 其他常用函数

  • delta():计算 Gauge 类型的变化量(比如温度变化)
  • predict_linear():线性预测,比如预测磁盘还能用多久
  • absent():检查指标是否存在,常用于告警

举个例子,预测磁盘满的时间:

# 预测 4 小时后磁盘使用率
predict_linear(node_filesystem_free_bytes[1h], 4 * 3600) < 0

这个函数我特别喜欢。有一次线上磁盘告警,我用它预测出还有 3 小时会满,赶紧让运维去扩容。结果 2 小时 50 分的时候磁盘真的满了,差点出事。嗯,从那以后我每次做容量规划都会用这个函数。

3.5 实战:组合查询

光讲单个函数没意思,咱们来组合一下。比如我想看「每个节点的 CPU 使用率超过 80% 的核数」:

# 先算每个核的使用率,再统计超过 80% 的核数
count by(instance) (
  (100 - avg by(instance, cpu) (rate(node_cpu_seconds_total{mode="idle"}[5m]) * 100)) > 80
)

这个查询看起来复杂,但拆开看其实很简单:

  1. 先算每个 CPU 核的 idle 比例
  2. 用 100 减去 idle 比例得到使用率
  3. 筛选出使用率 > 80% 的核
  4. 按 instance 统计数量

PromQL 就是这样,基础语法就那么几个,但组合起来能玩出花来。我建议你多动手试试,在 Prometheus 的 Web UI 里反复调,很快就能上手。

避坑指南:我曾经在写 PromQL 时,忘记加时间范围(比如 [5m]),结果 rate() 函数一直报错。后来养成习惯,写任何函数前先确认数据是瞬时向量还是范围向量。

好了,PromQL 的基础就这些。下一章咱们聊聊怎么用 Grafana 把这些查询变成漂亮的图表。