跳到主要内容

PromQL 语法、示例与优化

PromQL 操作的是带标签的时间序列。每写一条复杂表达式,都先在 Prometheus Graph 或 Grafana Explore 执行最简单的裸指标,确认指标名、标签和单位,再逐层增加选择器、函数和聚合。

1. 数据类型与选择器​

类型示例说明
Instant vectorup当前时刻每条序列的一个样本
Range vectorup[5m]每条序列在 5 分钟窗口内的样本范围
Scalar0.95单个数值,可与向量运算
String较少直接使用函数参数中的字符串值
# 查询所有 up 时间序列,结果带 job、instance 等原始标签
up

# 精确匹配:只看生产 node-exporter
up{job="node-exporter", environment="production"}

# 正则匹配:同时选择 checkout 和 payment 服务
http_requests_total{service=~"checkout|payment"}

# 负向匹配:排除成功和重定向状态码
http_requests_total{code!~"2..|3.."}

# Range vector:过去 5 分钟样本,作为 rate() 的输入
http_requests_total[5m]

=/!= 是精确匹配,=~/!~ 是正则匹配。高基数标签上使用宽泛正则会增加查询成本;优先使用 cluster、environment、namespace、service 等稳定过滤条件。

2. 运算符与聚合​

PromQL 支持算术、比较和集合运算。比较默认只保留满足条件的样本;加上 bool 后保留所有匹配样本,并将结果改为 0 或 1。

# 算术:计算内存使用率,结果单位为百分比
100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)

# 比较:只返回使用率高于 85 的序列
(100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) > 85

# bool 比较:所有序列都会返回,超过阈值为 1,否则为 0
(100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) > bool 85

# 聚合:按 service 汇总每秒请求数,丢弃其余标签
sum by (service) (rate(http_requests_total[5m]))

# 聚合:保留除 instance、pod 外的全部标签后求和
sum without (instance, pod) (rate(http_requests_total[5m]))

常用聚合包括 sum、avg、min、max、count、stddev、topk 和 bottomk。聚合前先确认是否应保留 cluster、namespace、service 等业务边界,避免把多个环境混在一起。

3. Counter、Gauge 与常用函数​

函数输入适用场景注意事项
rate()Counter Range vector稳定的每秒速率窗口至少覆盖 4 个抓取周期
irate()Counter Range vector瞬时变化图表对抖动敏感,不用于常规告警
increase()Counter Range vector窗口内累计次数适合批任务、失败次数
avg_over_time()Gauge Range vector窗口平均值不要用于 Counter 累计值
histogram_quantile()Histogram bucket 速率P95/P99 延迟聚合必须保留 le 标签
predict_linear()Gauge Range vector容量趋势预测仅适合近似稳定的趋势
# Counter:过去 5 分钟平均每秒请求数
rate(http_requests_total[5m])

# Counter:过去 1 小时累计失败次数,按 job 汇总
sum by (job) (increase(batch_job_failures_total[1h]))

# Gauge:过去 30 分钟平均可用内存,按实例展示
avg_over_time(node_memory_MemAvailable_bytes[30m])

4. 向量匹配​

二元运算要求两侧标签可匹配。默认使用两侧相同标签匹配;on() 指定匹配键,ignoring() 忽略某些标签。group_left/group_right 只在确认一对多关系时使用。

# 错误率:分子和分母都按 cluster、service 聚合,确保标签维度一致
sum by (cluster, service) (rate(http_requests_total{code=~"5.."}[5m]))
/
sum by (cluster, service) (rate(http_requests_total[5m]))

# 将服务所属团队信息关联到服务错误数;team_info 每个 service 只能有一条
sum by (service) (rate(http_requests_total{code=~"5.."}[5m]))
* on (service) group_left (team) service_team_info

若出现 “many-to-many matching not allowed”,分别运行算式两边,检查各自的标签和序列数量,再决定是否先聚合或修复元数据唯一性。

5. 常见查询案例​

CPU 使用率​

# 计算每台主机最近 5 分钟平均 CPU 使用率(百分比)
# 先按 instance 对 idle CPU 秒数取平均,再用 100 减去空闲比例
100 - avg by (instance) (
rate(node_cpu_seconds_total{mode="idle"}[5m])
) * 100

内存、磁盘和网络​

# 内存使用率:MemAvailable 已考虑可回收缓存,通常比 Free 更有意义
100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)

# 根分区使用率:排除 tmpfs、overlay 等不代表宿主机磁盘容量的文件系统
100 * (1 - node_filesystem_avail_bytes{mountpoint="/",fstype!~"tmpfs|overlay"}
/ node_filesystem_size_bytes{mountpoint="/",fstype!~"tmpfs|overlay"})

# 每实例网络接收速率,单位为 bytes/s;排除 loopback 和临时 veth 接口
sum by (instance) (
rate(node_network_receive_bytes_total{device!~"lo|veth.*"}[5m])
)

QPS、错误率与延迟​

# QPS:按服务汇总最近 5 分钟每秒请求数
sum by (service) (rate(http_requests_total[5m]))

# 5xx 错误率:结果为 0 到 1,Grafana 可格式化为百分比
sum by (service) (rate(http_requests_total{code=~"5.."}[5m]))
/
sum by (service) (rate(http_requests_total[5m]))

# P95 延迟:Histogram bucket 聚合时必须包含 le 和 service 标签
histogram_quantile(0.95,
sum by (le, service) (
rate(http_request_duration_seconds_bucket[5m])
)
)

Histogram 分位数是近似值,精度由 bucket 边界决定。若延迟 SLO 为 300 ms,bucket 设计必须覆盖该阈值附近,而不是只保留 1 秒和 5 秒等粗粒度桶。

6. 查询性能优化​

  1. 先限制时间范围、cluster/namespace/service 标签,再执行聚合。
  2. 对重复且昂贵的表达式创建 Recording Rule,供 Dashboard 与告警共享。
  3. Grafana 使用 $__rate_interval,避免用户缩放时间范围后速率窗口不合理。
  4. 避免在告警中使用 irate()、无界正则和深层子查询。
  5. 使用 Prometheus 查询页面、Grafana Query Inspector 与 prometheus_engine_query_duration_seconds 找出慢查询。

指标不存在、结果为空或 TSDB 异常时,参见 Prometheus 故障排查。