PromQL recording rules:让贵的 query 提前算 + cache

起因

Grafana dashboard 30+ panel,每 panel 一个 PromQL query。
打开一次 dashboard:Prometheus 跑 30 query → CPU 飙 → 慢。

某些复杂 query:

histogram_quantile(0.95,
    sum by (le, service) (rate(http_request_duration_seconds_bucket[5m])))

每次跑要扫几百万 sample 再算 percentile。慢且重复。

Recording rules:把贵 query 周期性提前算 → 存为新 metric → dashboard
查这新 metric → 快。

配 recording rule

/etc/prometheus/rules/api.yml

groups:
  - name: api_recording
    interval: 30s
    rules:
      - record: api:http_request_duration_seconds:p95
        expr: |
          histogram_quantile(0.95,
              sum by (le, service) (rate(http_request_duration_seconds_bucket[5m])))

      - record: api:http_requests:rate5m
        expr: |
          sum by (service, status) (rate(http_requests_total[5m]))
# prometheus.yml
rule_files:
  - 'rules/*.yml'

reload prometheus → 每 30 秒算一次 → 结果存为 metric api:http_request_duration_seconds:p95

dashboard query 改成:

api:http_request_duration_seconds:p95

立刻返回(已算好)。

命名规范

<level>:<metric>:<aggregation>

例:

  • api:http_requests:rate5m
  • node:cpu:usage_pct
  • cluster:pod_count

避免跟原 metric 冲突 + 一眼知道是 recording rule。

何时用 recording rule

适合:

  • 复杂 query(histogram_quantile / 多 join)
  • dashboard 频繁查
  • alert 用同 query 多次
  • 跨 metric 计算(A + B / C 等)

不适合:

  • 简单查询(ratio / count)
  • 一次性临时 query
  • high cardinality(recording 后存空间炸)

alerting rule

类似语法:

- alert: HighErrorRate
  expr: api:http_requests:rate5m{status=~"5.."} > 10
  for: 5m
  labels: { severity: warning }
  annotations:
    summary: "High 5xx rate on {{ $labels.service }}"

expr 用 recording rule 结果 → alert evaluation 也快。

性能数据

我们一个 cluster 100 node / 50 service:

dashboard 打开(30 panel):

latency Prometheus CPU
无 recording rule 8s 80%
全 recording rule 0.5s 20%

dashboard 数据可能稍滞后(recording interval 30s)。
trade-off:实时性 vs 性能。

external_labels

# prometheus.yml
global:
  external_labels:
    cluster: prod
    region: us-east

recording rule 结果自动带 cluster / region label → 多集群 federation。

federation (多集群汇总)

多个 prometheus 互相拉:

scrape_configs:
  - job_name: 'federate'
    metrics_path: '/federate'
    params:
      match[]:
        - '{__name__=~"job:.+"}'         # 只拉 recording rule
    static_configs:
      - targets:
          - 'prom-us-east:9090'
          - 'prom-eu-west:9090'

中央 prom 拉所有 region recording rule → 全局 dashboard。
只拉 recording rule(不是 raw metric)→ 数据量小 + 标准化。

与 Mimir / VictoriaMetrics 对比

老 prometheus 单机:

  • 数据存本地,几亿 sample 内存
  • recording rule 提速但仍单机瓶颈

Grafana Mimir / VictoriaMetrics 是 prometheus 兼容的分布式 TSDB:

  • 多节点存储 + 查询
  • 长期保留(年级别)
  • 内置 recording rule 跑

大 scale 必上。中小 scale prom 单机 + recording rule 够。

真实 case:dashboard 优化

某客户 SRE dashboard:

  • 10 个 service × 4 SLI(latency p50/p95/p99 + error rate)= 40 panel
  • 打开慢 15 秒
  • prom CPU 周期 spike

优化:

  1. 建 recording rule 算每 SLI metric
  2. dashboard query 改用 recording rule
  3. recording rule interval 跟 dashboard auto-refresh 对齐(30s)

效果:

  • dashboard 打开 1 秒
  • prom CPU 平均 -50%
  • alert evaluation 同样加速

与 cortex / thanos 对比

self-host prom Mimir Thanos VictoriaMetrics
部署 简单 复杂 复杂
长期存储 S3 S3 本地/S3
多集群 federation native native native
性能 单机 横向扩展 横向扩展

中小项目 self-host prom + recording rule + 远程 write 备份。

几亿 series → Mimir / VictoriaMetrics。

subquery (PromQL 4)

max_over_time(rate(http_requests_total[5m])[1h:1m])

[1h:1m] = 1h 窗口里每 1m 取 sample → over rate → max。

复杂但强大。recording rule 提前算更友好。

debug 不出数

# 看原 metric
http_request_duration_seconds_bucket

# 看 recording rule 结果
api:http_request_duration_seconds:p95

Grafana Explore 直接查。
/api/v1/rules 看 rule 状态:

curl http://prom:9090/api/v1/rules

health: ok / err / unknown 显示 rule 是否在跑。

踩过的坑

  1. rule cycle:rule A 依赖 rule B 依赖 rule A → 报错 + 数据空。
    严格 layer:raw → level 1 → level 2,单向。

  2. label cardinality 爆:recording rule 加 high cardinality
    label → 新 metric 几百万 series → TSDB OOM。sum without 合并。

  3. interval 太短:1s interval rule 比 raw scrape 还频繁 → 反而
    增负载。30s-1m 合理。

  4. alert 旧数据:recording rule 跑得慢 → alert 用旧值 → 错过
    真实 spike。监控 prometheus_rule_evaluation_duration_seconds

  5. federation 漏 label:federation 默认不带 external_label → 多
    region 看不出来源。honor_labels: true

精确评价 共 0 人评价
可复现性
可复现 · 0 不可复现 · 0
文风
文风流畅 · 0 文风晦涩 · 0
立场
支持 · 0 反对 · 0

登录后即可对本帖作出评价。

评论区 0 条 · 所有人可在此交流

登录后参与评论。

还没有评论,来说两句。