微服务告警总炸群?试试依赖链感知的降噪设计
上周三凌晨,支付网关报了 47 个 P2 告警。DBA、中间件、业务开发全被拉进战情室。查到底,只是缓存集群一次主从切换。这就是典型的依赖链噪音扩散。下游服务不知道上游只是抖了一下,只会按固定阈值疯狂发信。
告警不是监控大屏的副产品,它是“需要人工介入”的工单。跨服务降噪的核心就一条:让告警沿着服务依赖图反向收敛,而不是顺着调用链正向广播。
先看根因路由。别在监控系统里对每个 service 写死规则。先把调用拓扑导出来。用 eBPF 或 Sidecar 抓包生成实时依赖图。当 A->B->C 的调用失败率同时飙升时,只告警 C。A 和 B 的规则直接标记为 suppressed。Alertmanager 的 inhibit_rules 能做这事,但前提是你得把 source_matchers 和 target_matchers 绑在同一个 trace_id 或 service_topo_tag 上。
状态机比瞬时值靠谱。CPU 90% 不代表要报警,连续三个采集周期超过 85% 且伴随错误率上升才是真问题。把告警条件写成状态转移。比如 pending -> firing -> resolved。级联静默用时间窗控制。底层数据库慢查询触发后,自动给上层所有依赖该 DB 的服务发一个 silence 令牌,有效期设成故障平均恢复时间(MTTR)的 1.2 倍。上层服务在这期间只记日志,不发告警。
依赖权重必须分级。核心交易链路和内部报表服务不能共用一套阈值。核心链路走动态基线,按过去 14 天同时间段的 QPS 和延迟分布算分位数。偏离 3σ 才触发。边缘服务直接卡死阈值,超了就降级。权重标签打在 deployment 注解里,告警路由层按 sla_tier 字段分发。
落地时别自己造轮子。用 OpenTelemetry 统一埋点。Trace 和 Metric 必须能互查。告警触发时,自动附带最近 5 分钟的 Top 3 错误调用链。运维不用猜是哪一跳断了。配置参考:
# Alertmanager inhibit 示例逻辑
- source_match:
severity: critical
alertname: DatabaseConnectionExhausted
target_match:
severity: warning
dependency_root: "db-cluster-01"
equal: [cluster]
别把抑制规则写得太死。留一个 force_escape 通道。当静默服务同时触发核心 SLO 跌破 99.9%,或者连续 5 分钟无恢复迹象,直接打穿静默,升级给值班长。
上线前按这份清单走一遍:
- 绘制当前版本依赖图,标记单点故障域。
- 为每个节点设置 inhibit 来源,确保根节点优先级最高。
- 压测模拟底层抖动,观察告警风暴是否被压到原始量的 1/3 以下。
- 核对 Runbook,每条 firing 告警必须有对应的处置动作或自动化脚本入口。
- 定期清理过期 match_re 标签,防止规则膨胀拖慢路由引擎。
每季度做一次断网演练。把某中间件进程直接 kill,看告警风暴有没有被压住。记录误报率和漏报率。告警规则不是写完就放那的,它得跟着架构迭代一起变。
降噪的终点不是零告警,是每条告警都能对应一个明确的 Action Item。能自动扩容的别发人,能查日志定位的别拉群。把人的注意力留给真正需要判断的异常。