📈 第04章 · PromQL 查询
instant/range 查询语法
PromQL 查询¶
Prometheus 的数据本身只是一堆"时间轴上的值",真要用它做判断、画图、出报告,靠的是查询语言 PromQL。它是把时间和标签组合起来的"SQL",却能直接在时序上千聚合、算速率、做比较。这一章先分清"即时查询"和"区间查询"两种形态,再给一组可以直接照抄的常规模板。
先分清:Instant 与 Range¶
Prometheus 的 HTTP 查询 API 有两个端点,返回的数据结构完全不同:
| 端点 | 查询类型 | 返回 | 用途 |
|---|---|---|---|
/api/v1/query |
即时查询 (instant) | 每个时序一个值(vector) | 看"现在"某指标是多少 |
/api/v1/query_range |
区间查询 (range) | 每个时序一串值(matrix) | 画趋势、出报告、回放 |
即时查询适合"现在 CPU 多少%"这类快照;区间查询给定起止时间和步长,适合画折线图。两者采用同一套 PromQL 表达式,只是调用方式不同。
# 即时查询:现在 CPU 使用率
curl -s "localhost:9090/api/v1/query" --data-urlencode \
'query=100-(avg(irate(node_cpu_seconds_total{mode="idle"}[5m]))*100)'
# 区间查询:最近 1 小时、每 60s 一个点
curl -s "localhost:9090/api/v1/query_range" --data-urlencode \
'query=up{job="node"}' \
--data-urlencode 'start=2026-09-08T00:00:00Z' \
--data-urlencode 'end=2026-09-08T01:00:00Z' \
--data-urlencode 'step=60'
区间查询返回的是 matrix,每条结果含一串 [[时间戳, 值], ...]:
{"status":"success","data":{"resultType":"matrix",
"result":[{"metric":{"__name__":"up","job":"node"},
"values":[[1788825600,"1"],[1788825660,"1"], ...]}]}}
step=60 就是每 60 秒取一个点,这也是后面监控报告脚本固定用的参数。
选择器:挑出想要的时间序列¶
PromQL 的核心是"表达式 + 标签筛选"。挑一个指标、加过滤条件:
up # 所有 up 指标,每个时序一个值
up{job="node"} # 只看 node 目标的存活
node_memory_MemTotal_bytes{instance="localhost:9100"}
node_cpu_seconds_total{mode!="idle"} # mode 不等于 idle
| 匹配符 | 含义 | 例子 |
|---|---|---|
= |
精确相等 | mode="idle" |
!= |
不等 | mode!="idle" |
=~ |
正则匹配 | mode=~"user|system" |
!~ |
正则不匹配 | mode!~"idle|iowait" |
聚合:把多条时序合并算¶
真实机器有 N 个 CPU、多张磁盘网卡,往往要先归并成一条:
| 聚合 | 作用 | 典型 |
|---|---|---|
sum |
求和 | 多块磁盘的读速度 |
avg |
平均 | 多核 CPU 使用率 |
count |
计数 | 统计多少个目标 up |
max / min |
最大/最小 | 找出最满的磁盘 |
配合 by / without 指定维度:
avg by (mode)(node_cpu_seconds_total) # 各 mode 平均
sum by (instance)(rate(node_network_receive_bytes_total[5m])) # 每台主机的收速
速率函数:Counter 变速率¶
node_cpu_seconds_total、node_disk_read_bytes_total 这类 Counter 一直在涨,直接看没意义,要用 rate/irate 转成"每秒增量":
| 函数 | 说明 | 建议 |
|---|---|---|
rate(x[5m]) |
求 5 分钟窗口内的平均速率,平滑稳定 | 长时间趋势、报表 |
irate(x[5m]) |
基于窗口内最近两个点求瞬时速率,更敏感 | 实时告警、仪表 |
rate(node_network_receive_bytes_total[5m]) # 每秒收多少字节(平均)
irate(node_cpu_seconds_total{mode="idle"}[5m]) # 瞬时空闲率
常规模板:直接抄¶
以下几组是本机验证过的、直接用得上的查询:
# CPU 使用率(%)——1 减去空闲率
100 - (avg(irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# 内存使用率(%)
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100
# 根分区使用率(%)
1 - node_filesystem_free_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}
# 负载
node_load1
node_procs_running
# 各主机是否存活(1=up,0=down)
up{job="node"}
# 网络收/发速度(合并全网卡)
sum(rate(node_network_receive_bytes_total[5m]))
sum(rate(node_network_transmit_bytes_total[5m]))
# 磁盘读写速度
sum(rate(node_disk_read_bytes_total[5m]))
sum(rate(node_disk_written_bytes_total[5m]))
在服务器上核对一组真实数字(即时查询):
CPU : 42.9
内存 : 45.5
磁盘 : 7.4(空闲)
网络收: 87672 字节/秒
用 CLI 直接查(替代浏览器)¶
没有浏览器时,用 curl + --data-urlencode 最省事(避免 + 号等特殊字符被吃):
q(){ curl -s "localhost:9090/api/v1/query" --data-urlencode "query=$1" \
| python3 -m json.tool; }
q 'up{job="node"}'
q '100-(avg(irate(node_cpu_seconds_total{mode="idle"}[5m]))*100)'
提示 一条命令就拿到 JSON,是脚本里取数的基础。第 7 章监控报告脚本就是用这种方式,把查询结果喂给 matplotlib 画图。
易错点¶
- 用错端点:Instant 查询却传
step、Range 查询却期待单值,会得到结构不匹配的结果。 - 括号与维度不匹配:
[5m]窗口写法是[5m],不要写成[5min]或[5。 - Counter 不套
rate/irate:直接查_total只能看到"累计涨了多少",看不到"现在多快"。 - 省略标签导致维度爆炸:
up随便查询会返回所有实例,一屏刷屏;要聚合或加{job=...}。 sum(rate(...))记by:多网卡/多盘要sum by(instance),否则数值翻倍或合并语义不清。
相关命令¶
curl -s "localhost:9090/api/v1/query" --data-urlencode 'query=...'、curl -s "localhost:9090/api/v1/query_range"、promtool query instant / promtool query range(无需浏览器直接跑 PromQL)。