Recording rule本质是预计算而非缓存,需显式查询新指标名(如http_requests_rate_5m)才能生效;record字段仅支持合法指标名,expr中写标签或聚合;高基数指标须先降维再记录,否则加剧性能问题;rule修改后需重载配置且确保语法、路径、label值正确。

Recording rule 本质是预计算,不是缓存
它把高频、复杂查询的结果提前算好并存成新指标,后续查这个新指标就快得多。Prometheus 不会自动帮你“加速原查询”,而是用新指标替代原查询——这点很多人误以为开了 recording rule 就能加速任意 rate(http_request_total[5m]) 这类表达式,其实不行,必须显式改查 http_requests_rate_5m 这样的预计算结果。
常见错误现象:query_range 延迟没降,甚至更高;Grafana 面板还是慢;prometheus_engine_queries 计数没变少。
- 根本原因:查询语句没切换到 recording rule 生成的指标名
- 必须在 Grafana 查询编辑器、
curl请求、alert.rules中,全部替换成新指标名,比如http_requests_rate_5m - 检查是否生效:查
prometheus_rule_evaluations_total{rule_group="xxx"}看是否持续增加;再查http_requests_rate_5m是否有数据
rule 文件里写错 record 和 expr 就白定义
record 是最终存进 TSDB 的指标名,必须合法(只能含字母、数字、下划线),且不能和已有指标冲突;expr 是实际执行的 PromQL 表达式,它运行时上下文和普通 query 一致,但不支持子查询或某些函数(如 absent() 在旧版中受限)。
典型翻车点:
-
record: http_requests_total{job="api"}—— 错!record字段只接受纯指标名,标签得写在expr里或用labels覆盖 -
expr: rate(http_requests_total[5m]) by (job, instance)—— 对,但若原始指标没有job标签,这里会返回空 - 参数差异:
[5m]的区间必须匹配你真实查询习惯;用太短(如[1m])会导致抖动,太长(如[30m])则丢失细节
高基数指标 + recording rule = 更快崩掉
如果原始指标本身带大量 label 组合(比如 http_request_total{path="/user/:id", user_id="123456", ...}),直接对它做 rate(...[5m]) 并记录,会产生海量时间序列——比原指标还多,因为 recording rule 每次 eval 都新建 series(尤其当 label 动态变化时)。
性能影响比想象中更直接:
- TSDB 写放大:一条原始指标可能膨胀成几百条 recording 结果
- 内存占用飙升:
prometheus_tsdb_head_series指标会明显上涨 - 规避方法:先用
sum by(job, handler)或count by(status_code)聚合降维,再 recording;或加label_replace()归一化动态 label - 别录
http_request_duration_seconds_bucket这种直方图原始桶——应该录rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m])
rule 加载后不生效?先看 prometheus_config_last_reload_successful
Prometheus 不会热重载 recording rules:改了 rules.yml 必须触发 reload(SIGHUP 或 curl -X POST http://localhost:9090/-/reload),否则新 rule 完全不跑。
容易被忽略的坑:
- 配置文件路径没加进
prometheus.yml的rule_files列表,比如漏写了- "rules/*.yml" - rule 文件语法错误(YAML 缩进错、冒号后少空格),reload 失败但日志可能刷得快,
prometheus_config_last_reload_successful为 0 就是铁证 - rule group 名重复或包含非法字符(如空格、点号),会导致整个 group 跳过加载
- 查
prometheus_rule_group_last_evaluation_samples可确认每个 group 实际处理了多少样本,为 0 就说明没跑起来
最麻烦的其实是 label 一致性——比如你在 expr 里用了 job="api",但 target 实际上报的是 job="apiserver",那这条 rule 就永远安静如鸡。得对着 target 页面逐个核对 label 值。


















