📈 第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)。