PromQL 详解:Prometheus 查询语言完全指南
PromQL(Prometheus Query Language)是 Prometheus 的查询语言,用于选择和聚合时间序列数据。它是 Prometheus 可观测性的核心,支持从简单的指标查询到复杂的多维分析、告警规则定义和趋势预测。
本文将全面、系统地讲解 PromQL 的语法、数据类型、函数、操作符、查询模式和最佳实践,帮助你掌握从入门到高级的 PromQL 技能。
一、PromQL 核心概念
1. 数据模型回顾
Prometheus 的数据由 时间序列(Time Series) 组成,每条序列由:
- 指标名称(Metric Name)
- 标签(Labels)
- 样本(Samples):
(timestamp, value)数据点
2. PromQL 的三大数据类型
| 类型 | 说明 | 示例 |
|---|---|---|
| 瞬时向量(Instant Vector) | 某一时刻的多条时间序列 | http_requests_total{job="api"} |
| 范围向量(Range Vector) | 一段时间内的多条时间序列 | http_requests_total[5m] |
| 标量(Scalar) | 简单数字(无时间序列) | 123, 3.14 |
✅ PromQL 查询结果通常是瞬时向量或标量。
二、基础查询语法
1. 瞬时向量选择器(Instant Vector Selector)
查询某一时刻的指标数据。
基本语法
metric_name{label_key="value", ...}
示例
# 所有 http_requests_total 指标
http_requests_total
# 过滤 job="api-server" 的指标
http_requests_total{job="api-server"}
# 多标签过滤
http_requests_total{job="api-server", status="500"}
# 使用正则匹配
http_requests_total{method=~"GET|POST"} # =~ 表示正则匹配
http_requests_total{instance!~".*:9090"} # != 表示不等于,!~ 表示不匹配正则
2. 范围向量选择器(Range Vector Selector)
查询过去一段时间内的指标数据,用于计算速率、分位数等。
语法
metric_name[<duration>]
<duration>:时间范围,如5m,1h,2d
示例
# 过去 5 分钟的所有样本
http_requests_total[5m]
# 过去 1 小时的请求耗时
http_request_duration_seconds[1h]
✅ 范围向量不能直接显示,必须配合函数使用(如
rate())。
三、PromQL 操作符
1. 算术操作符
| 操作符 | 说明 |
|---|---|
+, -, *, /, %, ^ | 加减乘除、取模、幂运算 |
示例
# 计算错误率
rate(http_requests_total{status="500"}[5m]) / rate(http_requests_total[5m])
# 内存使用百分比
(node_memory_MemTotal_bytes - node_memory_MemFree_bytes) / node_memory_MemTotal_bytes
2. 比较操作符
| 操作符 | 说明 |
|---|---|
==, != | 等于、不等于 |
>, <, >=, <= | 大于、小于等 |
== bool, != bool | 返回布尔值(用于过滤) |
示例
# 返回值 > 100 的时间序列
node_filesystem_avail_bytes > 100
# 返回布尔结果(0 或 1)
node_filesystem_avail_bytes > bool 100
3. 逻辑/集合操作符
| 操作符 | 说明 |
|---|---|
and | 交集(保留两边都存在的序列) |
or | 并集(合并序列) |
unless | 差集(左边存在但右边不存在) |
示例
# 保留 job="api" 且 status="500" 的序列
http_requests_total{job="api"} and http_requests_total{status="500"}
# 合并两个指标
http_requests_total{job="api"} or http_requests_total{job="frontend"}
# 排除特定实例
http_requests_total unless http_requests_total{instance="backup"}
四、核心函数详解
1. rate() 与 irate()
计算每秒增长率,用于 Counter 指标。
rate(counter[range])
- 计算区间内的平均增长率
- 平滑,适合告警和图表
# 过去 5 分钟平均每秒请求数
rate(http_requests_total[5m])
irate(counter[range])
- 计算最近两个样本的增长率
- 对波动敏感,适合瞬时变化检测
# 最近两次抓取的增长率
irate(http_requests_total[5m])
✅ 生产推荐:
rate()用于告警,irate()用于瞬时监控。
2. increase()
计算时间范围内 Counter 的增长总量。
# 过去 1 小时请求数
increase(http_requests_total[1h])
✅ 等价于
rate() * 时间秒数,但返回整数。
3. sum(), avg(), min(), max(), count()
聚合函数,支持 by 和 without 分组。
语法
sum by (label1, label2) (vector)
示例
# 按 job 聚合请求总数
sum by (job) (rate(http_requests_total[5m]))
# 按 method 统计平均耗时
avg by (method) (rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m]))
# 统计实例数量
count without (instance) (up)
✅
by:保留指定标签;without:去掉指定标签。
4. histogram_quantile()
从 Histogram 中计算分位数。
语法
histogram_quantile(<phi>, <vector>)
phi:分位数(0.5, 0.95, 0.99)<vector>:_bucket指标
示例
# 计算 99 分位响应延迟
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job))
# 计算 P95
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[10m]))
✅ 必须对
_bucket使用rate()并按le分组。
5. topk() 与 bottomk()
返回前 N 个或后 N 个序列。
# 请求最多的前 5 个实例
topk(5, sum by (instance) (rate(http_requests_total[5m])))
# 延迟最低的 3 个服务
bottomk(3, avg by (job) (http_request_duration_seconds))
6. delta() 与 changes()
delta(gauge[range])
- 计算 Gauge 在区间内的变化量
- 适用于周期性重置的 Gauge
# 磁盘使用量变化
delta(node_filesystem_size_bytes[1h])
changes(gauge[range])
- 计算 Gauge 在区间内的变化次数
# 状态变化次数
changes(process_state[1h])
7. resets()
计算 Counter 在区间内的重置次数(如进程重启)。
# 过去 1 小时重启次数
resets(process_start_time_seconds[1h])
8. absent() 与 present()
检查指标是否存在。
# 如果 no_such_metric 不存在,返回 1
absent(no_such_metric)
# 如果 up 为 0,表示实例宕机
absent(up{job="api"} == 1)
✅ 常用于告警规则中检测实例宕机。
五、高级查询模式
1. 计算平均耗时(Timer / Histogram)
# 方法 1:Sum / Count
rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m])
# 方法 2:使用 histogram_quantile 计算分位数
histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
2. 计算错误率
# 5xx 错误率
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])
3. 计算成功率
# 2xx + 3xx 占比
sum(rate(http_requests_total{status=~"2..|3.."}[5m])) by (job)
/ sum(rate(http_requests_total[5m])) by (job)
4. 预测磁盘耗尽时间
# 预测磁盘在多少小时内耗尽
node_filesystem_avail_bytes / rate(node_filesystem_avail_bytes[1h])
六、PromQL 在告警规则中的应用
# rules/alerts.yml
groups:
- name: example
rules:
- alert: HighRequestLatency
expr: >
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
> 1
for: 10m
labels:
severity: warning
annotations:
summary: "High latency on {{ $labels.job }}"
description: "99th percentile latency is > 1s for 10 minutes."
- alert: InstanceDown
expr: absent(up{job="api"} == 1)
for: 5m
annotations:
description: "{{ $labels.instance }} has disappeared from Prometheus."
七、PromQL 性能优化建议
| 优化项 | 建议 |
|---|---|
| ✅ 避免大范围查询 | 1h 比 7d 快得多 |
✅ 使用 rate() 而不是 increase() 做速率计算 | 更稳定 |
✅ 聚合时使用 by 明确分组 | 避免隐式聚合 |
| ✅ 避免高基数标签 | 会导致查询变慢 |
| ✅ 使用 Recording Rules 预计算复杂查询 | 提升查询性能 |
✅ 合理设置 scrape_interval | 与查询范围匹配 |
八、常用 PromQL 查询速查表
| 需求 | PromQL 查询 |
|---|---|
| 每秒请求数 | rate(http_requests_total[5m]) |
| 错误率 | rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) |
| P99 延迟 | histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le)) |
| 平均耗时 | rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m]) |
| 实例是否存活 | up == 1 |
| CPU 使用率 | 1 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance) |
| 内存使用率 | (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes |
| 磁盘剩余 | node_filesystem_avail_bytes / node_filesystem_size_bytes |
九、总结
PromQL 是 Prometheus 的灵魂,掌握它意味着你能:
- ✅ 实时监控系统健康
- ✅ 精准定位性能瓶颈
- ✅ 编写有效的告警规则
- ✅ 实现复杂的可观测性分析
学习路径建议:
- 基础:瞬时/范围向量、算术操作
- 核心:
rate(),sum(),histogram_quantile() - 进阶:
relabel结合查询、Recording Rules - 实战:Grafana 面板 + 告警规则
📌 官方文档:https://prometheus.io/docs/prometheus/latest/querying/basics/
通过不断练习和实践,PromQL 将成为你排查问题、保障系统稳定的最强武器。
PromQL 查询语言全解析
2667

被折叠的 条评论
为什么被折叠?



