3. 事件触发值班机器人架构:事件源、决策引擎、通知渠道
事件触发值班机器人的核心架构围绕“感知-决策-执行”闭环设计,由三个逻辑层组成:事件源负责接收外部信号,决策引擎负责判断谁该处理、如何处理,通知渠道负责将决策结果送达目标人。三层之间通过标准化事件总线解耦,便于接入 OpenTelemetry 进行全链路诊断。
架构要点:每一层都应当输出可观测的 Span 和 Metrics,以便在值班机器人出现“漏通知、错通知、延迟通知”时,快速定位是事件丢失、决策超时还是渠道投递失败。
3.1 整体架构分层
下图展示了值班机器人的三层架构及典型组件,箭头表示事件流转方向。
3.2 事件源层详解
事件源是值班机器人的“输入边界”。不同事件源具有不同的触发特征和负载模式,决策引擎需要根据这些特征做差异化处理。
| 事件源类型 | 触发方式 | 典型协议/格式 | 负载特征 | 可观测关注点 |
|---|---|---|---|---|
| 告警 | 监控系统推送(Prometheus Alertmanager、Zabbix) | JSON / Alertmanager Webhook | 突发性高,可能产生告警风暴 | 告警到达率、去重率、延迟 |
| Webhook | 外部系统回调(GitLab CI、Jenkins、自定义服务) | HTTP POST / JSON | 请求频率不稳定,可能被重放 | 签名校验失败率、重复请求率 |
| 定时任务 | Cron 表达式触发(每日巡检、健康检查) | 内部调度器事件 | 周期性、可预测 | 调度延迟、执行超时 |
| 消息队列 | Kafka / Redis Pub-Sub 订阅 | Avro / Protobuf / JSON | 高吞吐、持续流 | 消费偏移量、积压量 |
OpenTelemetry 接入点:在事件源入口处创建 Span,记录
event.type、event.source、event.id 等属性。对于告警源,额外记录 alert.severity 和 alert.count,用于后续诊断告警风暴场景。
3.3 决策引擎层
决策引擎是值班机器人的“大脑”,负责将原始事件转化为“谁、用什么方式、在什么时间内处理”的指令。核心子模块包括:
- 事件去重与聚合:相同告警在短时间内重复到达时,只触发一次通知,避免轰炸。通常使用滑动窗口 + 事件指纹(如 MD5 摘要)实现。
- 值班表匹配:根据事件的时间戳、业务标签、优先级,查询当前值班人员列表。支持主备、轮岗、自定义排班规则。
- 升级策略:如果第一责任人未确认,按时间阶梯升级到第二人、值班经理、SRE 负责人。升级间隔可配置(如 5 分钟、15 分钟、30 分钟)。
- 限流与降级:当事件速率超过阈值时,自动丢弃低优先级事件或合并通知,保护下游通知渠道不被冲垮。
常见陷阱:决策引擎的“升级策略”如果未设置全局超时控制,在告警风暴时可能产生指数级通知爆炸。建议在决策引擎中增加
max_escalation_depth 和 cooldown_period 两个硬限制。
3.4 通知渠道层
通知渠道负责将决策结果投递给目标人。不同渠道的可靠性、延迟、成本差异显著,通常采用“多渠道并行”或“主备切换”策略。
| 渠道 | 可靠性 | 典型延迟 | 成本 | 适用场景 |
|---|---|---|---|---|
| 企业微信 / 钉钉 | 中(依赖网络) | 1-5 秒 | 低 | 日常告警、非紧急通知 |
| 短信 | 高 | 5-30 秒 | 中 | P1/P2 紧急告警 |
| 电话(语音) | 极高 | 10-60 秒 | 高 | P0 灾难性故障 |
| 邮件 | 中 | 1-10 分钟 | 极低 | 日报、非实时通知 |
| PagerDuty / OpsGenie | 极高 | 秒级 | 高 | 国际化团队、SLA 严格场景 |
3.5 事件流转与可观测埋点
为了在 OpenTelemetry 中实现端到端诊断,需要在三层之间传递统一的 Trace Context。下图展示了事件从产生到通知完成的关键埋点位置。
3.6 架构设计原则
- 无状态化:决策引擎不持有值班表状态,通过外部缓存(Redis)或配置中心获取,便于水平扩展。
- 幂等性:相同事件重复投递时,通知结果一致。决策引擎通过事件 ID 去重,通知渠道通过消息 ID 去重。
- 可观测性优先:每一层都输出 Metrics(事件速率、处理延迟、成功率)和 Traces(完整调用链),避免“黑盒”运维。
- 优雅降级:当通知渠道不可用时,事件应进入死信队列(DLQ)并触发告警,而不是直接丢弃。
课后思考:如果值班机器人在凌晨 3 点收到 1000 条相同告警,你的架构如何保证“只通知一次”且“升级策略不爆炸”?尝试在决策引擎中设计一个基于滑动窗口的去重计数器,并思考如何用 OpenTelemetry 的 Span 属性记录去重命中率。