3. 录制规则核心概念:recording rule 的定义、rule_group 结构、record 字段与 expr 字段详解、labels 字段的作用

录制规则(Recording Rule)是 PromQL 水位治理中最核心的工程化手段。它允许你将一个频繁使用或计算昂贵的 PromQL 表达式预先计算并存储为一条新的时间序列,从而降低查询延迟、减少计算压力,并为水位监控提供稳定的指标基座。本节将系统拆解录制规则的四个关键维度:定义、分组结构、核心字段语义以及标签控制。

3.1 什么是 Recording Rule

Recording Rule 本质上是一个“预计算 + 存储”的声明式配置。当 Prometheus 服务器加载规则文件后,会按照指定的评估周期(evaluation_interval)反复执行 expr 中的 PromQL 表达式,并将结果写入一个新的时间序列,该序列的名称由 record 字段指定。

核心价值:将复杂聚合(如 99 分位、多维度比率、跨实例求和)从查询时计算转移到写入时计算,使 Grafana 面板和告警规则能够直接引用预计算指标,响应速度提升 10-100 倍。

3.2 rule_group 结构:规则的容器与调度单元

所有录制规则必须归属于一个 rule_group。一个规则文件可以包含多个 rule_group,每个 rule_group 拥有独立的评估间隔和规则列表。这种分组机制为不同重要等级或不同计算频率的规则提供了隔离能力。

字段 类型 说明 示例
name string 组名称,必须唯一,用于日志和调试 node_exporter_high_cardinality
interval duration 该组内所有规则的评估周期,覆盖全局默认值 30s
rules array 录制规则或告警规则的列表 见下方代码块
groups:
  - name: node_cpu_water_level
    interval: 30s
    rules:
      - record: node:node_cpu_utilization:ratio_avg5m
        expr: avg by (instance) (rate(node_cpu_seconds_total{mode!="idle"}[5m]))
        labels:
          level: "watermark"
      - record: node:node_cpu_utilization:ratio_avg30m
        expr: avg by (instance) (rate(node_cpu_seconds_total{mode!="idle"}[30m]))
        labels:
          level: "watermark"
工程注意:同一 rule_group 内的规则按顺序评估。如果规则 A 依赖规则 B 的输出,必须将规则 B 放在规则 A 之前,否则评估周期内可能读到空数据。

3.3 record 字段与 expr 字段详解

record 和 expr 是录制规则的两个必填字段,它们共同定义了“存储什么”和“如何计算”。

record 字段:输出指标的名称

  • 命名规范:推荐使用 namespace:metric_name:suffix 的三段式命名法,例如 node:node_cpu_utilization:ratio_avg5m。命名空间(如 node)避免跨团队冲突,后缀(如 ratio_avg5m)明确聚合类型与窗口。
  • 唯一性:同一 Prometheus 实例内,record 名称不能与已有的指标名称或其它录制规则名称重复,否则会导致数据覆盖或查询歧义。
  • 标签继承:新生成的时间序列会保留 expr 结果中的所有标签,除非在 labels 字段中显式覆盖或添加。

expr 字段:PromQL 表达式

  • 表达式限制:必须返回一个瞬时向量(instant vector),不能是标量、字符串或范围向量。如果表达式返回范围向量,需要使用 avg、max、quantile 等聚合函数或子查询将其转换为瞬时向量。
  • 性能考量:避免在 expr 中使用 offset 过大的时间偏移或未经聚合的高基数标签(如 pod、device),否则录制规则本身会成为性能瓶颈。
  • 水位场景典型表达式:
# 水位场景:计算每个实例的 CPU 利用率 5 分钟平均比率
expr: avg by (instance) (rate(node_cpu_seconds_total{mode!="idle"}[5m]))

# 水位场景:计算集群级别的内存使用率 99 分位
expr: quantile by (cluster) (0.99, (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes))

# 水位场景:计算请求错误率(5 分钟滑动窗口)
expr: sum by (service) (rate(http_requests_total{status=~"5.."}[5m])) / sum by (service) (rate(http_requests_total[5m]))

3.4 labels 字段的作用:标签控制与覆盖

labels 字段是一个可选的映射表,用于在录制规则输出时添加、修改或删除标签。它不会影响原始指标,只作用于新生成的时间序列。

操作类型 语法 示例 效果
添加标签 key: value source: "recording_rule" 为所有输出序列增加 source="recording_rule" 标签
覆盖标签 key: value instance: "aggregated" 将 expr 结果中的 instance 标签值统一改为 aggregated
删除标签 无法直接删除,需通过覆盖为空字符串 device: "" 将 device 标签置空,Prometheus 存储时会自动移除空标签
水位场景最佳实践:在录制水位指标时,建议通过 labels 添加 level: "watermark" 或 type: "sli" 等分类标签,便于在 Grafana 中通过标签选择器快速过滤所有水位指标,而无需依赖指标命名前缀。

3.5 录制规则核心概念关系图

下图展示了录制规则从配置加载到时间序列写入的完整数据流,以及 rule_group、record、expr、labels 四个核心要素之间的协作关系。

录制规则核心概念关系图 录制规则核心概念关系图 规则文件 (YAML) rule_group name: "node_cpu_water_level" interval: 30s rules: [...] rules 列表 规则 1 record: node:util:ratio_avg5m expr: avg by(instance) (rate(...)) 规则 2 record: node:util:ratio_avg30m expr: avg by(instance) (rate(...)) labels 字段处理 添加/覆盖/删除标签 新时间序列写入 TSDB 评估周期由 rule_group.interval 或全局 evaluation_interval 控制

3.6 核心字段对比总结

下表从字段属性、必填性、数据类型、典型用途四个维度对四个核心概念进行横向对比,便于快速查阅。

概念/字段 所属层级 必填 数据类型 典型用途
rule_group 组容器 是 结构体 定义评估间隔、组织规则、控制评估顺序
record 规则内部 是 string 指定输出时间序列的名称,遵循三段式命名
expr 规则内部 是 string (PromQL) 定义预计算逻辑,必须返回瞬时向量
labels 规则内部 否 map[string]string 添加分类标签、覆盖高基数标签、删除无用标签

3.7 常见陷阱与避坑指南

陷阱 1:expr 返回范围向量导致规则失败。
如果 expr 中使用了 rate(...[5m]) 但没有配合聚合函数(如 avg by(...)),则返回的是范围向量,录制规则会报错。必须确保最外层是聚合函数或子查询。
陷阱 2:labels 覆盖导致标签丢失。
当使用 labels 覆盖某个标签时,该标签在 expr 结果中的原始值会被完全替换。如果只想添加而不覆盖,请确保 labels 中的键名不与 expr 结果中的标签键名冲突。
推荐做法:在开发录制规则时,先在 Prometheus 的 Graph 页面中验证 expr 是否返回正确的瞬时向量和标签集,确认无误后再写入规则文件。这可以避免因表达式错误导致的规则评估失败或数据异常。