4. PromQL基础:PromQL数据类型、选择器、操作符、常用函数

好,咱们进入PromQL的世界。说实话,刚开始接触PromQL的时候,我也觉得它有点怪——跟SQL完全不是一个路子。但用顺手了你会发现,它天生就是为监控和时序数据设计的,简洁、高效、暴力。

这一章,我带你把PromQL的底裤扒干净。数据类型、选择器、操作符、常用函数,一个一个来。

4.1 PromQL的数据类型

PromQL里只有四种数据类型,不多,但每个都有它的脾气。

类型 说明 例子
瞬时向量 (Instant Vector) 某一时刻的一组时间序列 node_cpu_seconds_total
区间向量 (Range Vector) 一段时间内的一组时间序列 node_cpu_seconds_total[5m]
标量 (Scalar) 一个单纯的数字 423.14
字符串 (String) 文本,目前用得少 "hello"

我个人习惯,90%的时间都在跟瞬时向量和区间向量打交道。标量一般用在计算里,比如 rate(x[5m]) * 100,那个100就是标量。

小提示: 瞬时向量是PromQL的“一等公民”。几乎所有操作符和函数,都是围绕它设计的。

4.2 选择器:怎么捞数据

选择器就是你的“数据捞子”。PromQL里主要有三种写法。

4.2.1 精确匹配

最直接的写法。用 = 表示等于,!= 表示不等于。

# 只看eth0网卡
node_network_receive_bytes_total{device="eth0"}

# 排除eth0
node_network_receive_bytes_total{device!="eth0"}

嗯,这里要注意:标签值必须用双引号括起来。

4.2.2 正则匹配

这个我特别喜欢。用 =~ 表示匹配正则,!~ 表示不匹配。

# 所有以eth开头的网卡
node_network_receive_bytes_total{device=~"eth.*"}

# 排除虚拟网卡
node_network_receive_bytes_total{device!~"veth.*|docker.*"}

我在项目中遇到过一个问题:某个节点网卡特别多,用精确匹配写了一大串。后来改成正则,一行搞定。你想想看,维护起来多舒服。

4.2.3 区间向量选择器

这个写法就是在指标名后面加个方括号,里面写时间范围。

# 过去5分钟的数据
node_cpu_seconds_total[5m]

# 过去1小时的数据
node_cpu_seconds_total[1h]

区间向量不能直接画图,得配合 rateavg_over_time 这类函数用。这个我们后面会讲。

注意: 区间向量的时间范围不能太大,否则数据量会爆炸。我曾经见过有人写 [7d],直接把Prometheus内存打满。建议生产环境控制在1小时以内。

4.3 操作符:加减乘除与逻辑

PromQL的操作符分三类:算术、比较、逻辑。说白了就是让你能对指标做各种运算。

4.3.1 算术操作符

加减乘除、取模、幂运算,都有。

# CPU使用率(百分比)
(1 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m]))) * 100

# 内存使用率
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100

你看,这些公式其实都是算术操作符拼出来的。

4.3.2 比较操作符

大于、小于、等于、不等于。返回的结果是0或1。

# 找出CPU使用率超过80%的节点
(1 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m]))) > 0.8

这个写法在告警规则里特别常见。我建议你把它记牢。

4.3.3 逻辑操作符

andorunless。用来组合多个条件。

# CPU高 且 内存也高
( cpu_high ) and ( mem_high )
核心要点: 逻辑操作符是按标签匹配的。只有标签完全一致的时间序列才会参与运算。这一点跟SQL的JOIN有点像,但更严格。

4.4 常用函数:实战必备

PromQL有几十个函数,但常用的其实就十来个。我挑几个最核心的讲。

4.4.1 rate() 和 irate()

这两个函数专门处理Counter类型的数据。Counter是只增不减的,比如请求总数、CPU总时间。

# 每秒请求数(平滑)
rate(http_requests_total[5m])

# 每秒请求数(瞬时)
irate(http_requests_total[5m])

我个人习惯:看趋势用 rate,看尖刺用 irate。irate对突增特别敏感,但容易抖动。

4.4.2 avg()、sum()、max()、min()

聚合函数,用来把多个时间序列合并成一个。

# 所有机器的平均CPU使用率
avg(rate(node_cpu_seconds_total{mode="idle"}[5m]))

# 按实例分组求和
sum by(instance) (rate(http_requests_total[5m]))

这里有个坑:avg 默认是全局平均。如果你想按某个标签分组,得用 by 子句。

4.4.3 topk() 和 bottomk()

取前N个或后N个。这个在排障时特别好用。

# CPU使用率最高的5个进程
topk(5, rate(node_cpu_seconds_total[5m]))

我曾经用 topk(10, ...) 快速定位到某个异常进程,省了半小时的手动排查时间。

4.4.4 predict_linear()

这个函数有点意思。它用线性回归预测未来趋势。

# 预测磁盘4小时后会不会满
predict_linear(node_filesystem_free_bytes[1h], 4*3600) < 0

嗯,这个函数不是万能的。如果数据波动很大,预测就不准。但用来做容量规划,够用了。

实战建议: 刚开始学PromQL,别贪多。先把 rateavgsumtopk 这四个函数练熟。其他的用到再查。

4.5 避坑指南

最后,分享几个我踩过的坑。

  • 标签值大小写敏感device="eth0"device="ETH0" 是两个不同的东西。我曾经因为这个查了半天。
  • 区间向量别乱用[5m][5m] 看起来一样,但如果你在Grafana里用,时间范围变了,结果也会变。
  • 除法注意分母为零:PromQL遇到除零会返回 NaN,不会报错。但你的图表上就会出现断点。
  • 聚合函数默认不带标签avg(x) 会丢掉所有标签。如果你需要保留某些标签,记得加 by

好了,PromQL的基础就这些。下一章我们实战一下,写几个真正的监控面板。到时候你会发现,这些基础打牢了,后面就是拼积木。