PromQL(Prometheus Query Language)是 Prometheus 监控系统的查询语言,也是整个云原生监控体系的核心。无论是构建 Grafana 仪表盘、编写告警规则,还是进行故障排查时的临时查询,都离不开 PromQL。我将从数据模型出发,逐步深入到聚合操作、常用函数和实战查询,最后覆盖子查询等高级技巧。
一、PromQL 数据模型
PromQL 有四种基本数据类型,理解它们是写对查询的前提:
| 类型 | 说明 | 示例 |
|---|---|---|
| 即时向量(Instant Vector) | 一组时间序列在当前时刻的采样值 | node_cpu_seconds_total |
| 范围向量(Range Vector) | 一组时间序列在过去一段时间内的所有采样值 | node_cpu_seconds_total[5m] |
| 标量(Scalar) | 一个简单的数值 | 3.14、1024 |
| 字符串(String) | 字符串值(较少使用) | "hello" |
最常用的两种:
- 即时向量:仪表盘和告警中最常见,返回"当前这一刻"各序列的值。
- 范围向量:用于
rate()、increase()等函数计算,必须带时间窗口[...]。
# 即时向量:返回当前所有序列
up
# 范围向量:返回过去5分钟内的所有采样点
up[5m]
# 标量
1 - 0.3
二、基础查询
2.1 Metric 选择与标签过滤
通过标签选择器可以精确过滤目标序列:
# 选择名为 node_cpu_seconds_total 的所有序列
node_cpu_seconds_total
# 按 mode 标签过滤
node_cpu_seconds_total{mode="idle"}
# 多标签组合(AND 关系)
node_cpu_seconds_total{instance="node-1:9100", mode="idle"}
# 标签正则匹配
node_cpu_seconds_total{instance=~"node-[0-9]+:9100"}
# 标签反向匹配(排除某些值)
node_cpu_seconds_total{mode!="idle"}
# 正则反向匹配
node_memory_MemTotal_bytes{instance!~"localhost.*"}
2.2 区间向量
在指标名后加 [时间窗口] 即可获得范围向量,时间单位支持 s(秒)、m(分钟)、h(小时)、d(天)、w(周)、y(年):
# 过去 5 分钟的采样点
http_requests_total[5m]
# 过去 1 小时
http_requests_total[1h]
# 过去 30 秒
http_requests_total[30s]
三、聚合操作
聚合操作用于对多组时间序列进行汇总计算。核心语法:
<aggr-op>([parameter,] <vector>) [without|by (<label list>)]
常用聚合算子
| 算子 | 说明 |
|---|---|
sum | 求和 |
avg | 平均值 |
max / min | 最大值 / 最小值 |
count | 计数 |
count_values | 按值分组计数 |
topk / bottomk | 前 K / 后 K |
quantile | 分位数 |
by 与 without
by 保留指定标签做分组,without 移除指定标签后对剩余标签分组:
# 按 instance 分组求 CPU 各模式的总和
sum by (instance) (node_cpu_seconds_total{mode="idle"})
# 移除 mode 和 cpu 标签后聚合(保留 instance、job 等)
sum without (cpu, mode) (node_cpu_seconds_total)
# 求每台机器 CPU 使用率最高的 top 3
topk(3, sum by (instance) (rate(node_cpu_seconds_total{mode!="idle"}[5m])))
topk 示例
# 流量最高的前 5 个 endpoint
topk(5, sum by (handler) (rate(http_requests_total[5m])))
四、常用函数
4.1 rate / irate / increase
这三个函数都只能作用于计数器(Counter)类型指标:
# rate:计算过去 5 分钟的平均增长率(推荐用于仪表盘和告警)
rate(http_requests_total[5m])
# irate:取最近两个采样点计算瞬时增长率(适合高精度短窗口图表)
irate(http_requests_total[5m])
# increase:计算过去 5 分钟的绝对增量
increase(http_requests_total[5m])
选择建议:
rate()适合告警和仪表盘,对数据抖动做了平滑处理。irate()适合超高精度短窗口(如[1m]),但对数据缺失敏感。increase()用于回答"过去 1 小时总共增加了多少"这类问题。
4.2 histogram_quantile
直方图分位数计算,用于 P50/P90/P99 延迟分析:
# 计算 P99 延迟(单桶写法)
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
# 多实例场景:先按 le 聚合再计算
histogram_quantile(
0.99,
sum by (le, instance) (rate(http_request_duration_seconds_bucket[5m]))
)
注意:如果多个实例都暴露了同名 histogram,必须先按
le聚合,否则histogram_quantile会在单个序列内查找所有桶,结果错误。
4.3 predict_linear
基于线性回归预测未来趋势,适合容量预测告警:
# 预测 1 小时后的磁盘使用量
predict_linear(node_filesystem_avail_bytes[1h], 4 * 3600)
# 磁盘将在 4 小时内写满
predict_linear(node_filesystem_avail_bytes[2h], 4 * 3600) < 0
4.4 其他高频函数
# 时间聚合:过去 1 小时每 5 分钟最大值
max_over_time(up[1h:5m])
# 一天前的同时间点
rate(http_requests_total[5m] offset 1d)
# 求百分比:已用内存占总内存的比例
1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)
# clamp_max 限制上限(如过滤异常值)
clamp_max(rate(http_requests_total[5m]), 1000)
五、实战查询示例
5.1 CPU 使用率
# 单机 CPU 使用率(%)
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# 所有机器 CPU 使用率 Top 5
topk(5,
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
)
原理:idle 时间占比的补数就是 CPU 使用率,使用 avg 是因为 Node Exporter 按 CPU 核心分别暴露数据。
5.2 内存使用率
# 内存使用率(%)
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)
/ node_memory_MemTotal_bytes * 100
# 按主机分组
100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)
5.3 P99 延迟
# 全局 P99 延迟(秒)
histogram_quantile(0.99,
sum by (le) (rate(http_request_duration_seconds_bucket[5m]))
)
# 按 endpoint 分组的 P99 延迟
histogram_quantile(0.99,
sum by (le, handler) (rate(http_request_duration_seconds_bucket[5m]))
)
5.4 错误率
# HTTP 5xx 错误率(%)
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m])) * 100
# 按服务分组
sum by (service) (rate(http_requests_total{status=~"5.."}[5m]))
/ sum by (service) (rate(http_requests_total[5m])) * 100
5.5 综合示例:多维度流量看板查询
# 总 QPS
sum(rate(http_requests_total[5m]))
# 按 status code 分类的 QPS
sum by (status) (rate(http_requests_total[5m]))
# 成功率(2xx + 3xx 占比)
sum(rate(http_requests_total{status=~"[23].."}[5m]))
/ sum(rate(http_requests_total[5m]))
六、高级技巧
6.1 子查询
子查询允许在任意即时查询表达式上施加范围和评估步长,语法为 <expr>[range:resolution]:
# 过去 1 小时内每 5 分钟的最大 CPU 使用率
max_over_time(
100 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100
)[1h:5m]
# 计算过去 1 小时内每分钟错误率的 5 分钟滑动平均
avg_over_time(
(sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m])))[1h:1m]
)
6.2 offset 修饰符
offset 用于将查询时间点回拨,常用于环比分析:
# 当前 QPS
sum(rate(http_requests_total[5m]))
# 一周前同时段的 QPS
sum(rate(http_requests_total[5m] offset 1w))
# QPS 周同比
sum(rate(http_requests_total[5m]))
- sum(rate(http_requests_total[5m] offset 1w))
6.3 @modifier(时间修饰符)
@ 修饰符可以将查询锚定到 UNIX 时间戳指定的绝对时间:
# 查询 UNIX 时间戳 1780000000 处的 CPU 使用率
node_cpu_seconds_total @ 1780000000
# 锚定到 2 小时前
rate(http_requests_total[5m] @ (time() - 2 * 3600))
# 结合 offset 使用
rate(http_requests_total[5m] @ (time() - 86400) offset 1h)
@修饰符从 Prometheus v2.25 起支持,适合构建"故障时间点回溯"查询。
6.4 记录规则(Recording Rules)
高频查询应使用记录规则预计算,避免每次查询都执行复杂表达式:
# prometheus-rules.yaml
groups:
- name: custom_rules
interval: 30s
rules:
- record: job:http_requests:rate5m
expr: sum by (job) (rate(http_requests_total[5m]))
- record: job:http_errors:ratio
expr: |
sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
/
sum by (job) (rate(http_requests_total[5m]))
- record: instance:cpu_usage:ratio
expr: 1 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m]))
在告警和仪表盘中直接引用预计算指标 job:http_requests:rate5m,可显著降低 Prometheus 查询负载。
七、常见陷阱
- Counter 重置:
rate()和increase()会自动处理 Counter 重置(如服务重启归零),但前提是你使用的是 Counter 类型指标而非 Gauge。 - rate 窗口过短:
[1m]窗口只有 2 个采样点时,rate结果抖动严重,建议至少[5m]。 - histogram_quantile 缺少聚合:多实例场景下未先按
le聚合直接调用,导致计算错误。 - 除零问题:分母可能为零时使用
clamp_min保护:
# 安全的比率计算
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ clamp_min(sum(rate(http_requests_total[5m])), 1)
总结
PromQL 的学习路径可以概括为:理解数据模型 → 掌握标签过滤 → 熟练使用聚合 → 用好核心函数(rate / histogram_quantile)→ 进阶子查询与记录规则。日常 SRE 工作中 80% 的查询场景都围绕 CPU、内存、延迟、错误率展开,把这些实战查询模板化、沉淀为记录规则,就能高效构建监控体系。
更多详情请参阅 Prometheus 官方文档 — Querying
参考资料与致谢
本文在撰写过程中参考了以下资料,感谢原作者的贡献:
- Prometheus 官方文档 — Querying basics — Prometheus 官方,参考了Prometheus 官方文档 — Querying basics相关内容