PromQL高级查询 #

一、高级查询技巧 #

1.1 子查询 #

promql
# 子查询语法
<表达式>[<范围>:<分辨率>]

# 查询过去1小时内每分钟的最大值
max_over_time(http_requests_total[1h:1m])

# 查询过去1小时内每分钟的最小值
min_over_time(http_requests_total[1h:1m])

# 查询过去1小时内每分钟的平均值
avg_over_time(http_requests_total[1h:1m])

# 计算过去1小时内速率的最大值
max_over_time(rate(http_requests_total[5m])[1h:])

# 计算过去1小时内P99延迟的最大值
max_over_time(
  histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))[1h:]
)

1.2 @修饰符高级用法 #

promql
# 查询特定时间点的数据
http_requests_total @ 1700000000

# 查询特定时间点的范围数据
http_requests_total[5m] @ 1700000000

# 使用start()和end()
http_requests_total @ start()
http_requests_total @ end()

# 子查询中使用@
rate(http_requests_total[5m])[1h:] @ start()

# 计算同比
http_requests_total 
/ 
(http_requests_total @ (time() - 86400))

1.3 复杂标签匹配 #

promql
# 多条件正则匹配
http_requests_total{
    method=~"GET|POST",
    status=~"2..|3..",
    endpoint!~"/health|/metrics"
}

# 使用标签名正则匹配
{__name__=~"http_.*", job="api-server"}

# 排除多个标签值
http_requests_total{status!~"4..|5.."}

# 复杂组合
http_requests_total{
    method="GET",
    status=~"2.."
} or http_requests_total{
    method="POST",
    status="201"
}

二、复杂场景应用 #

2.1 服务可用性计算 #

promql
# 服务可用性(SLA)
# 定义:成功请求 / 总请求 * 100

sum(rate(http_requests_total{status!~"5.."}[5m])) 
/ 
sum(rate(http_requests_total[5m])) * 100

# 按服务分组计算可用性
sum by (service) (rate(http_requests_total{status!~"5.."}[5m])) 
/ 
sum by (service) (rate(http_requests_total[5m])) * 100

# 计算过去30天的可用性
avg_over_time(
  sum(rate(http_requests_total{status!~"5.."}[5m])) 
  / 
  sum(rate(http_requests_total[5m])) * 100
[30d:5m])

2.2 错误预算计算 #

promql
# 错误预算
# 定义:允许的错误请求数 = 总请求 * (1 - SLA目标)

# 假设SLA目标为99.9%
sum(increase(http_requests_total[30d])) * (1 - 0.999)

# 已消耗的错误预算
sum(increase(http_requests_total{status=~"5.."}[30d]))

# 剩余错误预算
(
  sum(increase(http_requests_total[30d])) * (1 - 0.999) 
  - 
  sum(increase(http_requests_total{status=~"5.."}[30d]))
)

# 错误预算消耗率
sum(increase(http_requests_total{status=~"5.."}[30d])) 
/ 
(sum(increase(http_requests_total[30d])) * (1 - 0.999)) * 100

2.3 容量规划 #

promql
# 预测磁盘何时满
predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[1h], 3600 * 24 * 7)

# 预测内存何时耗尽
predict_linear(node_memory_MemAvailable_bytes[1h], 3600 * 24)

# 计算存储增长速率
deriv(node_filesystem_size_bytes{mountpoint="/"}[1d])

# 预测请求增长
predict_linear(http_requests_total[1h], 3600 * 24 * 30)

2.4 异常检测 #

promql
# 基于标准差的异常检测
# 超过平均值+3倍标准差视为异常

http_requests_total 
> 
(
  avg_over_time(http_requests_total[1h]) 
  + 
  3 * stddev_over_time(http_requests_total[1h])
)

# 基于历史数据对比
# 当前值超过历史平均值2倍
rate(http_requests_total[5m]) 
> 
2 * avg_over_time(rate(http_requests_total[5m])[1d:5m])

# 检测突增
(
  rate(http_requests_total[5m]) 
  - 
  rate(http_requests_total[5m] offset 1h)
) 
/ 
rate(http_requests_total[5m] offset 1h) > 0.5

三、性能优化 #

3.1 查询优化原则 #

text
查询优化原则:

┌─────────────────────────────────────────────┐
│ 1. 减少时间序列数量                        │
├─────────────────────────────────────────────┤
│ • 使用标签过滤                              │
│ • 避免高基数标签                            │
│ • 使用聚合减少序列数                        │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ 2. 减少数据量                              │
├─────────────────────────────────────────────┤
│ • 缩短查询时间范围                          │
│ • 使用合理的step值                          │
│ • 避免不必要的范围查询                      │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ 3. 使用高效函数                            │
├─────────────────────────────────────────────┤
│ • rate()比increase()更高效                 │
│ • 避免嵌套复杂函数                          │
│ • 使用内置函数代替复杂计算                  │
└─────────────────────────────────────────────┘

3.2 优化示例 #

promql
# 不推荐:查询所有指标再过滤
sum(rate(http_requests_total[5m])) by (method)

# 推荐:先过滤再聚合
sum by (method) (rate(http_requests_total{job="api-server"}[5m]))

# 不推荐:大范围查询
rate(http_requests_total[30d])

# 推荐:合理范围
rate(http_requests_total[5m])

# 不推荐:嵌套复杂函数
histogram_quantile(0.99, 
  sum by (le) (
    rate(http_request_duration_seconds_bucket[5m])
  )
)

# 推荐:简化查询
histogram_quantile(0.99, 
  sum by (le) (rate(http_request_duration_seconds_bucket[5m]))
)

# 不推荐:多次查询同一指标
sum(rate(http_requests_total[5m])) + 
sum(rate(http_requests_total[5m])) * 2

# 推荐:使用变量
sum(rate(http_requests_total[5m])) * 3

3.3 使用Recording Rules #

yaml
# recording_rules.yml

groups:
  - name: http_requests
    interval: 30s
    rules:
      # 预计算QPS
      - record: job:http_requests:rate5m
        expr: sum by (job) (rate(http_requests_total[5m]))
      
      # 预计算错误率
      - record: job:http_errors:rate5m
        expr: sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
      
      # 预计算可用性
      - record: job:availability:ratio5m
        expr: |
          sum by (job) (rate(http_requests_total{status!~"5.."}[5m]))
          /
          sum by (job) (rate(http_requests_total[5m]))
      
      # 预计算P99延迟
      - record: job:http_request_duration:p99_5m
        expr: |
          histogram_quantile(0.99, 
            sum by (job, le) (rate(http_request_duration_seconds_bucket[5m]))
          )

四、常见查询模式 #

4.1 趋势分析 #

promql
# 7天趋势
rate(http_requests_total[5m]) 
/ 
rate(http_requests_total[5m] offset 7d)

# 环比增长
(
  sum(increase(http_requests_total[1d])) 
  - 
  sum(increase(http_requests_total[1d] offset 1d))
) 
/ 
sum(increase(http_requests_total[1d] offset 1d)) * 100

# 同比增长
(
  sum(increase(http_requests_total[1d])) 
  - 
  sum(increase(http_requests_total[1d] offset 7d]))
) 
/ 
sum(increase(http_requests_total[1d] offset 7d])) * 100

# 移动平均
avg_over_time(rate(http_requests_total[5m])[1h:])

4.2 容量分析 #

promql
# CPU容量
# 已使用CPU核心数
sum(rate(node_cpu_seconds_total{mode!="idle"}[5m])) by (instance)

# 总CPU核心数
count(node_cpu_seconds_total{mode="idle"}) by (instance)

# CPU使用率
sum(rate(node_cpu_seconds_total{mode!="idle"}[5m])) by (instance) 
/ 
count(node_cpu_seconds_total{mode="idle"}) by (instance) * 100

# 内存容量
# 已使用内存
sum(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) by (instance)

# 总内存
sum(node_memory_MemTotal_bytes) by (instance)

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

4.3 性能分析 #

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

# P50响应时间
histogram_quantile(0.5, rate(http_request_duration_seconds_bucket[5m]))

# P90响应时间
histogram_quantile(0.9, rate(http_request_duration_seconds_bucket[5m]))

# P99响应时间
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

# 响应时间分布
sum by (le) (rate(http_request_duration_seconds_bucket[5m]))

4.4 错误分析 #

promql
# 错误率分析
# 总错误率
sum(rate(http_requests_total{status=~"5.."}[5m])) 
/ 
sum(rate(http_requests_total[5m])) * 100

# 按状态码分组
sum by (status) (rate(http_requests_total{status=~"5.."}[5m]))

# 按服务分组
sum by (service) (rate(http_requests_total{status=~"5.."}[5m])) 
/ 
sum by (service) (rate(http_requests_total[5m])) * 100

# 错误趋势
sum(rate(http_requests_total{status=~"5.."}[5m])) 
/ 
sum(rate(http_requests_total[5m] offset 1h)) * 100

五、Grafana集成 #

5.1 变量使用 #

text
Grafana变量语法:

# 简单变量
$variable_name

# 标签值变量
label_values(http_requests_total, method)

# 查询变量
query_result(sum by (service) (rate(http_requests_total[5m])))

# 使用变量过滤
http_requests_total{method="$method"}
http_requests_total{service=~"$service"}

5.2 常用Grafana查询 #

promql
# 单值面板
sum(rate(http_requests_total[5m]))

# 时间序列面板
rate(http_requests_total[5m])

# 饼图
sum by (status) (rate(http_requests_total[5m]))

# 表格
sum by (instance, method) (rate(http_requests_total[5m]))

# 热力图
sum by (le) (rate(http_request_duration_seconds_bucket[5m]))

# 状态面板
up{job="node-exporter"}

六、最佳实践 #

6.1 查询命名规范 #

promql
# 使用有意义的变量名
# 不推荐
a = rate(http_requests_total[5m])

# 推荐
request_rate = rate(http_requests_total[5m])

# 使用注释说明复杂查询
# 计算过去5分钟的HTTP请求错误率
sum(rate(http_requests_total{status=~"5.."}[5m])) 
/ 
sum(rate(http_requests_total[5m])) * 100

6.2 查询模板 #

promql
# CPU使用率模板
100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# 内存使用率模板
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100

# 磁盘使用率模板
(1 - (node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"})) * 100

# 网络流量模板
irate(node_network_receive_bytes_total{device!~"lo|veth.*"}[5m])
irate(node_network_transmit_bytes_total{device!~"lo|veth.*"}[5m])

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

七、总结 #

高级查询技巧:

技巧 说明
子查询 计算范围内的聚合值
@修饰符 查询特定时间点
复杂匹配 多条件组合过滤
Recording Rules 预计算复杂查询

最佳实践:

原则 说明
减少序列数 使用标签过滤
缩小范围 合理时间范围
使用变量 提高可读性
预计算 使用Recording Rules

下一步,让我们学习导出器!

最后更新:2026-03-27