PromQL 详细教程

PromQL(Prometheus Query Language)是 Prometheus 监控系统的核心查询语言,专门用于查询和聚合时间序列数据。它采用函数式编程风格,支持复杂的函数组合和嵌套,能够实时查询监控数据并生成可视化图表或告警规则。

一、数据模型与数据类型

1.1 时间序列结构

Prometheus 将所有监控数据存储为时间序列,每条时间序列由以下部分组成:

  • 指标名称:反映被监控样本的含义(如 http_requests_total
  • 标签集合:描述样本的特征维度(如 {method="GET", status="200"}
  • 时间戳:精确到毫秒的时间点
  • 样本值:float64 浮点型数据

1.2 四种数据类型

数据类型 说明 示例
瞬时向量 某一时刻的一组时间序列,每个序列只有一个样本 up{job="prometheus"}
区间向量 一段时间范围内的一组时间序列,包含多个样本 http_requests_total[5m]
标量 单一数值,没有时间序列 123
字符串 文本值,主要用于返回信息 "this is a string"

注意:范围向量不能直接显示,必须配合函数(如 rate())使用。

二、基础查询语法

2.1 瞬时向量选择器

# 查询所有该指标的时间序列
http_requests_total

# 带标签过滤
http_requests_total{method="GET", status="200"}

# 正则匹配
http_requests_total{status=~"2.."}  # 匹配所有2xx状态码
http_requests_total{status!~"5.."}  # 排除所有5xx状态码

2.2 范围向量选择器

# 最近5分钟的数据
http_requests_total[5m]

# 最近1小时内,每30秒的数据点
http_requests_total[1h:30s]

# 偏移量修饰符(查询5分钟前的数据)
http_requests_total offset 5m

时间单位ms(毫秒)、s(秒)、m(分钟)、h(小时)、d(天)、w(周)、y(年)

2.3 标签匹配操作符

操作符 说明 示例
= 精确匹配 {job="prometheus"}
!= 不等于 {job!="node-exporter"}
=~ 正则匹配 {job=~"prom.*"}
!~ 正则不匹配 {job!~"node.*"}

重要规则:选择器必须指定一个名称或至少一个与空字符串不匹配的标签匹配器。

三、操作符

3.1 算术运算符

# 加减乘除
http_requests_total + 100
http_requests_total - 50
http_requests_total * 2
http_requests_total / 1024

# 取模和幂运算
node_memory_MemAvailable_bytes % 1024
node_cpu_seconds_total ^ 2

3.2 比较运算符

# 布尔过滤
up == 1  # 状态为"up"的目标
node_load1 > 10  # 负载大于10

# 使用bool修饰符返回0或1
node_load1 > bool 10

3.3 逻辑运算符

# 与操作
up == 1 and rate(http_requests_total[5m]) > 100

# 或操作
up == 0 or rate(http_requests_total[5m]) == 0

# 排除操作
http_requests_total unless http_requests_total{status="500"}

3.4 聚合运算符

# 求和
sum(http_requests_total)

# 按标签分组求和
sum(http_requests_total) by (job, method)

# 平均值
avg(node_cpu_seconds_total{mode="idle"})

# 最大值和最小值
max(node_memory_MemTotal_bytes)
min(node_memory_MemAvailable_bytes)

# 计数
count(http_requests_total)

# 前5个最大值
topk(5, http_requests_total)

# 后5个最小值
bottomk(5, http_requests_total)

# 分位数(中位数)
quantile(0.5, http_requests_total)

分组语法

  • by (label1, label2):仅保留指定标签作为分组依据
  • without (label1, label2):删除指定标签,剩余标签作为分组依据

四、常用内置函数

4.1 速率计算函数

# 计算区间向量的平均增长速率
rate(http_requests_total[5m])

# 计算区间向量的瞬时增长率(使用最后两个样本)
irate(http_requests_total[5m])

# 计算区间向量的增量
increase(http_requests_total[5m])

使用场景

  • rate():适合长期趋势分析和告警规则
  • irate():灵敏度更高,适合绘制瞬时变化图表

4.2 时间窗口函数

# 过去5分钟内的平均值
avg_over_time(node_cpu_seconds_total[5m])

# 过去1小时内的最大值
max_over_time(node_memory_MemAvailable_bytes[1h])

# 过去2分钟内的变化次数
changes(node_load1[2m])

4.3 预测函数

# 基于2小时数据预测4小时后的磁盘空间
predict_linear(node_filesystem_free_bytes[2h], 4 * 3600)

4.4 直方图分位数计算

# 计算90分位数的响应时间
histogram_quantile(0.9, 
  rate(http_request_duration_seconds_bucket[5m]))

4.5 标签操作函数

# 标签替换
label_replace(up, "host", "$1", "instance", "(.*):.*")

# 标签连接
label_join(up, "instance_job", "-", "instance", "job")

五、向量匹配模式

5.1 一对一匹配

# 按instance标签匹配
method_code:http_errors:rate5m{code="500"} / on(instance) method:http_requests:rate5m

# 忽略code标签匹配
method_code:http_errors:rate5m / ignoring(code) method:http_requests:rate5m

5.2 多对一匹配

# 左侧为"多",右侧为"一"
method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m

5.3 一对多匹配

# 右侧为"多",左侧为"一"
method:http_requests:rate5m * ignoring(code) group_right method_code:http_errors:rate5m

匹配规则

  • 默认情况下,两个向量需要具有完全相同的标签集才能匹配
  • 使用 on()ignoring() 可以控制匹配的标签维度

六、实战案例

6.1 CPU使用率监控

# 单个实例的CPU使用率
100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance) * 100)

# 集群整体CPU使用率
100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

6.2 内存使用率精确计算

# 准确的内存使用率(排除缓存和缓冲区)
(
  (node_memory_MemTotal_bytes - node_memory_MemFree_bytes - 
   node_memory_Buffers_bytes - node_memory_Cached_bytes) / 
  node_memory_MemTotal_bytes
) * 100

# 内存可用率
(node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100

6.3 磁盘空间监控

# 磁盘空间使用率
(
  (node_filesystem_size_bytes - node_filesystem_free_bytes) / 
  node_filesystem_size_bytes
) * 100

# 排除虚拟文件系统
(
  (node_filesystem_size_bytes{fstype!~"tmpfs|fuse.lxcfs|squashfs"} - 
   node_filesystem_free_bytes{fstype!~"tmpfs|fuse.lxcfs|squashfs"}) / 
  node_filesystem_size_bytes{fstype!~"tmpfs|fuse.lxcfs|squashfs"}
) * 100

6.4 HTTP请求监控

# 请求成功率
sum(rate(http_requests_total{status=~"2.."}[5m])) / 
sum(rate(http_requests_total[5m])) * 100

# 错误率
sum(rate(http_requests_total{status=~"4..|5.."}[5m])) / 
sum(rate(http_requests_total[5m])) * 100

# 平均响应时间
sum(rate(http_request_duration_seconds_sum[5m])) / 
sum(rate(http_request_duration_seconds_count[5m]))

# P95响应时间
histogram_quantile(0.95, 
  sum(rate(http_request_duration_seconds_bucket[5m])) by (le))

6.5 告警规则示例

groups:
- name: example-rules
  rules:
  - alert: HighRequestLatency
    expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 1
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "高请求延迟"
      description: "实例 {{ $labels.instance }} 的P95响应时间超过1秒(当前值:{{ $value }}秒)"

七、最佳实践

7.1 查询优化建议

  1. 使用具体的标签选择器:避免查询所有时间序列,使用标签过滤减少数据量
  2. 选择合适的时间窗口:根据监控需求选择合适的时间范围(如 [5m][1h]
  3. 避免高基数标签聚合:高基数标签会导致查询性能下降
  4. 使用recording rules预计算:对复杂查询使用记录规则,提高查询性能

7.2 监控告警策略

  • CPU使用率:> 80% 警告,> 90% 告警,> 95% 紧急
  • 内存使用率:> 80% 预警,> 90% 告警,> 95% 且 Swap > 50% 严重告警
  • 磁盘空间:使用率 > 85% 告警
  • HTTP错误率:> 1% 警告,> 5% 告警

7.3 性能优化

# 优化前:查询所有实例的CPU使用率
rate(node_cpu_seconds_total[5m])

# 优化后:只查询特定实例
rate(node_cpu_seconds_total{instance="web-server-1"}[5m])

# 优化后:使用更小的时间窗口
rate(node_cpu_seconds_total{instance="web-server-1"}[1m])

八、总结

PromQL 是 Prometheus 监控体系的核心,掌握其语法和函数对于构建高效的监控系统至关重要。通过本教程,您应该已经掌握了:

  1. 基础语法:时间序列选择器、标签匹配、范围查询
  2. 操作符:算术、比较、逻辑、聚合运算符
  3. 内置函数:速率计算、时间窗口、预测、分位数计算
  4. 向量匹配:一对一、多对一、一对多匹配模式
  5. 实战案例:CPU、内存、磁盘、HTTP请求监控
  6. 最佳实践:查询优化、告警策略、性能调优

建议在实际环境中多练习,从简单查询开始逐步增加复杂度,建立自己的查询模板库,将技术指标与业务指标关联,设计有意义的告警规则。

作者:严锋  创建时间:2025-12-21 19:48
最后编辑:严锋  更新时间:2025-12-25 10:39