报警降噪与去重

告警噪音是 SRE 团队最头疼的问题之一。当告警数量达到一定规模,工程师会产生「告警疲劳」——要么忽略告警,要么直接关闭告警通知。这两种做法都会导致真正的故障被忽视。本篇介绍系统性的降噪策略。

告警噪音的来源

在开始降噪之前,需要理解噪音的来源:

抖动告警:指标在阈值附近反复波动,导致告警频繁触发和恢复。这种告警即使有效,也会因为数量太多而被忽视。

重复告警:相同问题触发多个相似告警。例如,某个服务的多个实例同时触发 HighCPU 告警,每个实例各发一条。

无价值告警:指标异常但不影响业务,或者异常程度不足以需要人工介入。

传播告警:根本原因已经发送,但衍生问题仍在继续告警。

去重策略

Alertmanager 的 group_waitgroup_interval 本身就是去重机制。但对于更精细的去重,需要在报警规则层面处理。

标签归一化

将动态变化的标签从分组键中移除,保留静态标签:

# 原始:每个实例触发一条
group_by: ['alertname', 'instance']

# 优化:按服务聚合
group_by: ['alertname', 'service']

数值抽象化

具体数值不应该成为分组键。将数值信息移到 Annotations 中:

# 错误:数值成为分组键,每个不同值都是新告警
labels:
  alertname: "HighLatency"
  latency_ms: "{{ $value }}"  # 500, 600, 700 各一条

# 正确:数值放在 description
labels:
  alertname: "HighLatency"
annotations:
  description: "延迟达到 {{ $value }}ms"

告警合并策略

跨服务合并

当某个基础设施故障影响多个服务时,合并这些服务的告警:

route:
  routes:
    - match:
        infrastructure: database
      receiver: "infra-alerts"
      # 不再按服务分组,而是按基础设施聚合
      group_by: ['alertname', 'infrastructure']

时间窗口合并

使用更长的 group_wait 窗口,让更多相关告警在发送前被收集:

route:
  group_wait: 2m   # 等待 2 分钟收集相关告警
  group_interval: 10m  # 10 分钟内最多发一次

阈值优化

告警阈值设置不当是噪音的重要来源。阈值应该基于历史基线和业务影响确定,而非拍脑袋决定。

基线分析:分析过去 30 天的指标分布,取 P95 或 P99 作为参考基线。

业务影响:阈值应当与业务影响直接关联。例如,当转化率下降 5% 时报警,而非当某个内部队列长度达到某个值时报警。

分级阈值:区分 Warning 和 Critical 两个级别,给运维人员留出响应空间。

# Warning:需要关注,但不需要立即处理
- alert: HighErrorRate
  expr: error_rate > 0.01
  labels:
    severity: warning

# Critical:必须立即处理
- alert: HighErrorRate
  expr: error_rate > 0.05
  labels:
    severity: critical

持续优化

降噪不是一次性工作,而是持续改进的过程。建议建立以下机制:

每周告警回顾:每周检查告警数量趋势,分析新增噪音来源。

无效告警清理:对于持续触发但无人响应的告警,要么优化阈值,要么删除。

阈值动态调整:基于季节性或业务周期,动态调整告警阈值。