反馈体系漫谈(五):通知策略设计——什么时候通知谁

前面四篇分别讲了邮件、短信、即时通讯三个通道的技术细节和集成方式。有了“术”之后,最后要聊的是“道”——怎么把这些通道组合起来,设计一套真正好用的通知体系。

通知体系设计的核心问题只有一个:在正确的时间,把正确的信息,通过正确的通道,送到正确的人手里。

一、通知分级:不是所有失败都值得发短信

DevOps 中的事件千差万别。一条日志警告和线上数据库宕机,性质完全不同。如果所有通知都走同一个通道、发同一批人,结果必然是告警疲劳——大家把通知当背景噪音,真正重要的事也被忽略了。

通知分级的基础框架:

级别 含义 通知通道 通知对象 响应要求
P0 - 紧急 线上服务不可用、核心功能中断 短信 + 电话 + IM On-Call + 负责人 立即响应(5分钟内)
P1 - 严重 服务异常但未完全中断 短信(单条) + IM On-Call 尽快响应(30分钟内)
P2 - 一般 非核心功能异常、需要关注 IM 通知 相关开发 工作时间内处理
P3 - 提示 信息通报、常规报告 邮件 / IM 静默 全体成员 无需响应

分级的判断维度

怎么判断一个事件该定哪个级别?三个维度:

  1. 影响范围:影响了多少用户?是不是核心功能?
  2. 持续时间:已经持续多长时间?预计还要多久?
  3. 可恢复性:能不能自动恢复?回滚行不行?

示例判断:

场景:用户服务 API 错误率从 0.01% 升到 5%,持续 3 分钟
→ 影响范围:中等(API 仍然可用,但部分请求失败)
→ 持续时间:不长,但趋势不好
→ 可恢复性:不确定
→ 定级:P1(严重)
→ 操作:短信通知 On-Call + IM 群通知

二、通知对象:不是所有人都需要知道一切

通知对象应该按角色划分,而不是“有通知就发给所有人”:

Pipeline 事件
    ├── 构建失败 → 触发者 + 相关模块负责人
    ├── 部署到测试环境 → 测试团队
    ├── 部署到生产环境 → 运维 + 全员公告
    └── 安全漏洞扫描 → 安全团队

线上告警
    ├── P0 → On-Call(主) + 团队负责人(升级)
    ├── P1 → On-Call + 服务负责人
    └── P2 → 服务负责人(工作日)

On-Call 轮值设计

On-Call 不能是“谁在就谁接”,必须有明确的排班:

第1周: 张三(主) + 李四(备)
第2周: 王五(主) + 赵六(备)
第3周: 张三(主) + 李四(备)
...

升级规则: 主 On-Call 5分钟未确认 → 通知备 On-Call → 仍无响应 → 通知团队负责人

实践建议:

  • 一周一轮:太短切换频繁,太长负担重
  • 必须有备份:主 On-Call 可能在洗澡、在开车
  • 做 Handoff:交接时说明上周发生了什么、有什么遗留问题

三、告警聚合与防抖

单个故障可能触发十几个告警——DB 连不上导致 API 报错,API 报错导致上游报错,一个根因裂变成几十条通知。

不做聚合的结果就是告警风暴

21:30 - [P1] 数据库连接超时
21:30 - [P1] 用户服务 API 错误率上升
21:30 - [P1] 订单服务调用超时
21:30 - [P1] 支付服务异常
21:30 - [P1] 网关 502
21:30 - [P1] 前端页面不可用
21:31 - [P1] 数据库连接超时
21:31 - [P1] 用户服务 API 错误率上升
...

应该聚合为:

21:30 - [P0] 核心服务大面积故障
  根因: 数据库主库连接超时
  影响: 用户服务、订单服务、支付服务、网关
  已自动触发主备切换,正在恢复中...

聚合策略:

  • 时间窗口:同一时间窗口内相关告警聚合(如 2 分钟内)
  • 依赖拓扑:根据服务依赖关系,下游告警归到上游根因
  • 去重:同一告警不重复发送
# 简单的告警聚合逻辑
def process_alert(alert):
    key = f"{alert.service}:{alert.type}"  # 聚合键
    
    # 2分钟内的同类告警聚合
    if redis.exists(f"alert:flood:{key}"):
        redis.hincrby(f"alert:flood:{key}", "count", 1)
        return None  # 不发通知
    
    # 新告警
    redis.setex(f"alert:flood:{key}", 120, '1')
    return send_notification(alert)

四、通知的内容设计

通知内容应该遵循金字塔原则——最重要的事最先说:

[级别] [状态] [标题]                     ← 最核心,一眼看完
─────────────────────
基础信息:项目、环境、触发者、时间       ← 快速定位
关键信息:错误摘要、影响范围、建议操作   ← 帮助决策
详细信息:日志链接、监控大盘、相关记录   ← 需要时展开

好的通知示例:

🔴 [P1] 用户服务 API 错误率异常
──────────────────────────────
环境: 生产环境
服务: user-api
指标: 错误率 5.2%(正常 < 0.1%)
持续: 3 分钟
操作: 查看监控 → 检查日志 → 必要时回滚
──────────────────────────────
📊 Grafana | 📋 日志 | 🔄 回滚

五、避免告警疲劳的实践

告警疲劳(Alert Fatigue)是通知体系最大的敌人。几个核心原则:

  1. 通知必须是可操作的:收到通知后知道做什么,否则就是噪音
    • CPU 使用率 85%(然后呢?)
    • CPU 使用率 85%,是否加扩容?[一键扩容]
  2. 静默期有意义:非工作时间 P2 以下不发,维护窗口期不发

    # Prometheus AlertManager 静默规则
    mute_time_intervals:
      - name: outside-business-hours
        time_intervals:
          - weekdays: ['monday':'friday']
            times:
              - start_time: '18:00'
                end_time: '09:00'
    
  3. 定期清理无用告警:每月回顾哪些告警从未被响应,要么移除、要么降级

  4. 保持通道纯净:IM 通知群只发 DevOps 通知,不要掺杂日常聊天

六、完整的通知体系架构

把前四篇串起来,一个通知体系的完整架构:

事件源层
  ├── CI/CD Pipeline(Jenkins/GitLab CI)
  ├── 监控告警(Prometheus/Grafana)
  ├── 日志分析(ELK/Loki)
  └── 安全扫描(SonarQube/Trivy)
         │
         ▼
路由层(通知中心)
  ├── 分级判断(P0/P1/P2/P3)
  ├── 聚合去重(防抖 + 依赖拓扑)
  ├── 静默规则(维护窗口/工作时间)
  └── 通道选择(短信/IM/邮件)
         │
         ▼
通道层
  ├── 邮件(SMTP/SendGrid)
  ├── 短信(阿里云/Twilio)
  └── IM(飞书/企业微信 Webhook)
         │
         ▼
接收层
  └── 按角色 + 级别分发到正确的人

小结

通知体系设计不是选哪个工具的问题,而是一个决策框架

  • 分什么级:P0 到 P3,根据影响/持续/可恢复性
  • 通知谁:按角色和 On-Call 排班,不打扰无关的人
  • 怎么聚:同一根因合并,同一时间窗口去重
  • 说什么:金字塔结构,最重要的事放最前面
  • 怎么防疲劳:可操作、有静默、定期清理

从第一篇文章讲邮件 SMTP,到这里聊完通知体系设计,这个系列告一段落。反馈是 DevOps 循环从 Monitor 回到 Plan 的关键一环。好的反馈体系,让人能从“不知道”变成“第一个知道”,从“被动响应”变成“主动行动”。

每天前进一小步,就是一个新的高度!