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" |
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) |
聚合操作还可以配合 by 和 without 来分组。你想想看,如果我想看每个节点的 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
)
这个查询看起来复杂,但拆开看其实很简单:
- 先算每个 CPU 核的 idle 比例
- 用 100 减去 idle 比例得到使用率
- 筛选出使用率 > 80% 的核
- 按 instance 统计数量
PromQL 就是这样,基础语法就那么几个,但组合起来能玩出花来。我建议你多动手试试,在 Prometheus 的 Web UI 里反复调,很快就能上手。
[5m]),结果 rate() 函数一直报错。后来养成习惯,写任何函数前先确认数据是瞬时向量还是范围向量。
好了,PromQL 的基础就这些。下一章咱们聊聊怎么用 Grafana 把这些查询变成漂亮的图表。