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) | 一个单纯的数字 | 42、3.14 |
| 字符串 (String) | 文本,目前用得少 | "hello" |
我个人习惯,90%的时间都在跟瞬时向量和区间向量打交道。标量一般用在计算里,比如 rate(x[5m]) * 100,那个100就是标量。
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]
区间向量不能直接画图,得配合 rate、avg_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 逻辑操作符
and、or、unless。用来组合多个条件。
# CPU高 且 内存也高
( cpu_high ) and ( mem_high )
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
嗯,这个函数不是万能的。如果数据波动很大,预测就不准。但用来做容量规划,够用了。
rate、avg、sum、topk 这四个函数练熟。其他的用到再查。
4.5 避坑指南
最后,分享几个我踩过的坑。
- 标签值大小写敏感:
device="eth0"和device="ETH0"是两个不同的东西。我曾经因为这个查了半天。 - 区间向量别乱用:
[5m]和[5m]看起来一样,但如果你在Grafana里用,时间范围变了,结果也会变。 - 除法注意分母为零:PromQL遇到除零会返回
NaN,不会报错。但你的图表上就会出现断点。 - 聚合函数默认不带标签:
avg(x)会丢掉所有标签。如果你需要保留某些标签,记得加by。
好了,PromQL的基础就这些。下一章我们实战一下,写几个真正的监控面板。到时候你会发现,这些基础打牢了,后面就是拼积木。