3. 告警规则编写:Prometheus告警规则语法、告警表达式、标签与注解

告警规则是 Prometheus 监控体系的核心“触发器”。一条精准的告警规则,能够在系统出现异常时第一时间通知 SRE 团队,并携带足够的上下文信息用于快速定位。本章将深入剖析告警规则的语法结构、表达式编写技巧以及标签与注解的最佳实践。

3.1 告警规则文件结构与语法

Prometheus 告警规则采用 YAML 格式定义,通常保存在独立的规则文件中(如 alerts.yml),并在 Prometheus 主配置中通过 rule_files 字段加载。

核心语法结构:
groups:
  - name: <group_name>          # 规则组名称,必须唯一
    interval: <duration>         # 规则评估间隔(可选,默认继承全局配置)
    rules:
      - alert: <alert_name>      # 告警名称,必须唯一
        expr: <promql_expression> # PromQL 表达式,触发条件
        for: <duration>          # 持续时间,满足条件持续多久才触发
        labels:                   # 附加标签(可选)
          <key>: <value>
        annotations:              # 注解(可选),用于传递上下文信息
          <key>: <value>
字段 必填 说明 示例
groups[].name 是 规则组名称,用于逻辑分组 node_alerts
groups[].interval 否 该组规则的评估频率 30s
rules[].alert 是 告警名称,在告警通知中作为标题 HighCPUUsage
rules[].expr 是 PromQL 表达式,返回非零值即触发 node_cpu_seconds_total > 0.9
rules[].for 否 表达式持续满足该时长后才触发告警,用于防止抖动 5m
rules[].labels 否 附加标签,会覆盖原始指标标签,常用于路由告警 severity: critical
rules[].annotations 否 注解,用于携带描述、链接、Runbook 等上下文 summary: "CPU usage is high"
最佳实践:规则组名称应反映其监控对象(如 kubernetes_nodes、database_instances),便于管理和排错。评估间隔建议与数据采集间隔保持一致或为其整数倍。

3.2 告警表达式编写核心原则

告警表达式是 PromQL 查询语句,其返回值决定了告警是否触发。编写高质量表达式需要遵循以下原则:

  • 返回非零值即触发:Prometheus 将表达式结果中所有非零(且非 NaN)的样本视为触发状态。因此,常用比较运算符(>、<、==)生成 0 或 1 的结果。
  • 避免空结果:如果表达式返回空向量,则不会触发告警。对于“无数据”场景,应使用 absent() 函数。
  • 使用 for 消除抖动:设置合理的持续时间,避免瞬时峰值导致误告警。
  • 聚合与分组:使用 by 或 without 子句控制告警的粒度,避免为每个实例生成过多告警。
常见表达式模式:
# 1. 阈值比较(CPU 使用率 > 80%)
100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80

# 2. 速率异常(5分钟内错误率超过 5%)
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) > 0.05

# 3. 无数据检测(实例离线)
absent(node_cpu_seconds_total{instance="192.168.1.1:9100"}) == 1

# 4. 预测趋势(磁盘 6 小时内会满)
predict_linear(node_filesystem_free_bytes{mountpoint="/"}[6h], 6 * 3600) < 0

3.3 标签与注解:告警的“元数据”

标签(labels)和注解(annotations)是告警规则中传递上下文的关键字段,直接影响告警的路由、去重和可读性。

3.3.1 标签(Labels)

标签用于标识告警的属性和路由策略。Prometheus 会将原始指标标签与规则中定义的标签合并,形成告警的唯一标识。常用标签包括:

  • severity:严重级别(critical、warning、info),用于告警分级。
  • team:负责团队,用于路由到正确的通知渠道。
  • env:环境标识(prod、staging),便于区分。

3.3.2 注解(Annotations)

注解用于提供人类可读的描述和操作指引,不会影响告警的路由。推荐包含以下信息:

  • summary:简短摘要,概括告警内容。
  • description:详细描述,包含当前值、阈值、实例等动态信息。
  • runbook_url:指向 Runbook 文档的链接,便于快速响应。
  • dashboard_url:指向相关监控面板的链接。
完整告警规则示例:
groups:
  - name: node_alerts
    interval: 30s
    rules:
      - alert: HighCPUUsage
        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 90
        for: 5m
        labels:
          severity: critical
          team: platform
        annotations:
          summary: "Instance {{ $labels.instance }} CPU usage is high"
          description: "CPU usage has been above 90% for more than 5 minutes. Current value: {{ $value }}%"
          runbook_url: "https://runbook.example.com/high-cpu-usage"
          dashboard_url: "https://grafana.example.com/d/node-cpu"

3.4 告警规则生命周期与状态机

理解告警的状态转换有助于排查告警未触发或重复告警的问题。下图展示了告警从评估到恢复的完整流程:

告警规则状态机 告警规则状态机 正常 (OK) 待触发 (Pending) 触发 (Firing) 恢复 (Resolved) 条件满足 持续 > for 条件恢复 条件恢复 自动关闭 说明:Pending 状态用于等待 for 持续时间,防止瞬时波动导致误告警;Resolved 状态表示告警已恢复。

3.5 告警规则编写避坑指南

常见陷阱与解决方案:
  • 陷阱:表达式返回多个时间序列,导致告警爆炸。
    解决:使用 by 子句聚合,或设置 alert_relabel_configs 进行标签降维。
  • 陷阱:for 时间设置过短,频繁误告警。
    解决:根据指标波动特性设置 for,通常建议 3-5 分钟。
  • 陷阱:注解中未使用模板变量,告警信息千篇一律。
    解决:使用 {{ $labels.xxx }} 和 {{ $value }} 动态填充实例名称和当前值。
  • 陷阱:规则文件语法错误导致 Prometheus 无法加载。
    解决:使用 promtool check rules 命令进行本地校验。

3.6 告警规则与 CI/CD 联动设计

在自动化运维体系中,告警规则不应是静态的。通过 CI/CD 管道管理规则文件,可以实现版本控制、自动化测试和灰度发布。下图展示了告警规则在 CI/CD 中的流转过程:

告警规则 CI/CD 联动流程 告警规则 CI/CD 联动流程 Git 仓库 CI 校验 测试环境 生产环境 提交 通过 验证通过 失败回退 说明:CI 阶段使用 promtool 校验语法,测试环境验证告警触发逻辑,生产环境通过灰度发布逐步生效。
CI/CD 集成要点:
  • 在 CI 阶段执行 promtool check rules alerts.yml 进行语法校验。
  • 使用 promtool test rules test.yml 进行单元测试,验证表达式在给定输入下的输出。
  • 通过配置管理工具(如 Ansible、Helm)将规则文件分发到 Prometheus 服务器,并触发热加载(POST /-/reload)。
  • 在测试环境中使用模拟指标数据验证告警触发与恢复逻辑。

3.7 本章小结