起因
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:rate5mnode:cpu:usage_pctcluster: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
优化:
- 建 recording rule 算每 SLI metric
- dashboard query 改用 recording rule
- 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 是否在跑。
踩过的坑
-
rule cycle:rule A 依赖 rule B 依赖 rule A → 报错 + 数据空。
严格 layer:raw → level 1 → level 2,单向。 -
label cardinality 爆:recording rule 加 high cardinality
label → 新 metric 几百万 series → TSDB OOM。sum without合并。 -
interval 太短:1s interval rule 比 raw scrape 还频繁 → 反而
增负载。30s-1m 合理。 -
alert 旧数据:recording rule 跑得慢 → alert 用旧值 → 错过
真实 spike。监控prometheus_rule_evaluation_duration_seconds。 -
federation 漏 label:federation 默认不带 external_label → 多
region 看不出来源。honor_labels: true。
登录后参与评论。