监控系统会死在哪里
这篇文章来自一次真实事故的复盘,记录的是生产组织在最需要可见性的时候为什么反而看不见。
那次凌晨两点的事故
现场
凌晨 02:17,客户支持群冒出第一条消息:某大客户请求大量超时。
02:19,Oncall 被拉醒。
02:21,打开 Grafana,一片绿色。CPU 正常,Memory 正常,Error rate 接近 0。系统看上去啥事没有。
02:25,更多客户报告超时,业务负责人进会议开始问:影响多少客户?范围多大?要不要回滚?多久能恢复?没人能答上来。监控系统在那里,但它没给出任何能拿来做决策的信息。那一刻我意识到,监控没坏,但已经失效了。
四层崩塌
第一层:监控看到的和用户感知到的不是一回事
02:30,初步排查。Infra dashboard 显示 CPU < 40%,Memory 正常,Network 正常,Pod 数量正常,没有明显 error spike。但用户那边:请求超时,页面卡死,API latency 超过 20 秒。
第二层:最关键的问题答不上来
管理层问了五个问题:影响面多大?是某个 region 吗?是单个客户吗?要不要 rollback?要不要对外公告?一个都答不了。
监控存在,但没有决策能力。
第三层:信任开始崩塌
02:40,工程师开始 SSH 进机器,手动翻日志,临时加 debug,打印内部状态。逐渐没人看 dashboard 了。
监控一旦被绕过,它就失去了控制权。
第四层:监控系统自己也要撑不住了
02:50,Prometheus 查询变慢,高 cardinality 查询直接 OOM,有些 dashboard 加载超过 40 秒。
那时候真正的恐惧出现了:如果 Prometheus 挂了,我们就彻底瞎了。
最终定位
03:12,手动排查发现某核心依赖服务连接池耗尽,导致级联超时。但 infra metrics 没触发 alert,没有 dependency latency SLO,没有 per-client SLO,没有 request saturation 指标。监控没有错,只是没有监控到真正的风险。
事后来看,这不是监控缺失的事故,是监控系统设计暴露的事故。Dashboard 在,Alert 在,但系统处于"盲飞"状态:我们有可观测性,但没有控制能力。于是我开始想一个问题,如果一个监控系统会死,它会死在哪里?
监控到底在测什么
02:25,管理层问"有多少用户受影响",仪表盘答不了:它显示的是 CPU、内存、网络,基础设施工程师关心的一切,却回答不了真正重要的问题。多数监控系统测的东西就是错的:测的是基础设施,测不出组织的行动能力。监控的价值说到底是能不能改变行为或决策,其他都是次要的。
CPU 90% 不一定是风险
CPU 90% 有没有风险?看情况:没有用户影响,可能没事;用户超时,就是问题;流量高峰时在预期内;低流量时反而可疑。原始指标告诉你状态,不告诉你风险,风险需要解释。那次事故里 CPU 正常,用户却宕了,指标没错,只是没测对东西。
信号和噪音
那次事故里,基础设施指标太多是噪音,用户影响信号太少,信噪比是倒的。收集一切、对一切告警,最终没人看,解法不是更多数据,是更少噪音:主动过滤、分组、提高置信度阈值、移除低价值指标。
决策延迟
衡量行动能力的核心指标是决策延迟,从信号到行动决策的时间。那次事故里这个数字接近无穷大:信号有(CPU、内存),但做不了决策,回滚还是扩容还是再等,谁都说不出来。好的监控系统要把决策延迟压到分钟级,关键事故要在 5 分钟内走完信号检测、解释、决策三步(各约 1-2 分钟),我们那次卡死在解释这一步,不知道信号对用户意味着什么。多数监控系统回答的问题本身就错了,它们回答"系统状态是什么",该回答的是"我们该做什么"。
风险检测和决策支持
02:25,我们答不了"安全吗?要回滚吗?"监控系统本该是安全系统,目的是风险检测和决策支持。
飞机驾驶舱的思路
飞机驾驶舱不给你看原始高度、燃料、速度,显示的是"距离危险阈值"“燃料够不够到目的地”“接近失速速度”。原始指标不如处理后的洞察有价值,驾驶舱不是为了显示高度,是为了保证你不会坠毁,监控也是同一个道理。那次事故里我们只有原始指标(CPU、内存),没有安全信号,用户安全吗、风险在扩大吗,都答不上来。
控制循环
监控是反馈控制系统,得靠闭环运转:现实 → 信号 → 解释 → 风险框架 → 决策 → 行动 → 系统变化 → 新现实,任何一环断了就退化成观察噪音。
那次事故里,循环在多个点断裂:信号只反映基础设施,不反映用户体验;解释做不了;没有 SLO 和错误预算做风险评估;做不了决策;没触发行动。循环从未闭合过。
控制理论视角
振荡是告警风暴:告警触发行动,行动导致更多告警,反馈放大,一旦开始很难停,那晚没遇到但以前见过。噪音是误报:工程师静音久了,真告警也跟着被静音,那晚情况正好相反,基础设施正常但用户宕了,噪音掩盖了信号。延迟是数据滞后:那晚数据是新鲜的,新鲜的却是错的信号,CPU 新鲜,用户影响缺失,正确信号的延迟才致命。
监控系统必须能回答:安全吗?在变糟吗?需要行动吗?什么行动?答不了这些,它就只是一个数据显示器,算不上安全系统。
让监控系统比生产更稳定
02:50,Prometheus 查询 OOM,高基数查询崩溃,仪表盘加载 40 秒以上,再挂一下我们就彻底瞎了。跟生产一起死的监控系统没有用:监控系统是关键基础设施,必须比它监控的东西更稳定,因为最需要它的时候恰恰是生产出问题的时候。
生存能力层级
| 层级 | 架构特征 | 应用崩溃时 | AZ失败时 | 区域失败时 | 适用场景 |
|---|---|---|---|---|---|
| 0 | 与应用共享基础设施 | 监控崩溃 | 监控崩溃 | 监控崩溃 | 开发环境 |
| 1 | 独立VM/存储 | 监控存活 | 监控失败 | 监控失败 | 小型生产 |
| 2 | 独立故障域(不同AZ) | 监控存活 | 监控存活 | 监控失败 | 关键生产 |
| 3 | 跨区域冗余+缓冲 | 监控存活 | 监控存活 | 监控存活 | 关键业务 |
那次事故里我们大概在层级 0 到 1 之间,生产出问题时监控也跟着晃,Prometheus 挣扎、查询变慢,距离彻底失明只差一次崩溃。事故之后组织才投资做了独立部署。
基数问题
OOM 的原因是基数爆炸:service x region x instance x endpoint x status 这类标签一相乘就是数百万时间序列,稳态下能跑的查询,事故期间就崩了。解法是标签治理,限制标签维度、用记录规则、早期聚合;换一个"更好的数据库"解决不了基数问题。
元监控
监控系统也需要被监控,但元监控必须比主监控更简单,否则就是递归。要盯的是监控系统可用性、数据收集成功率、查询性能、存储健康。那次事故里 Prometheus 开始挣扎的时候我们并不知道,直到查询失败才发现,元监控本可以提前检测到这种退化。
Prometheus 为什么会在事故里 OOM
02:50 Prometheus 查询 OOM、仪表盘加载 40 秒以上,根源是可观测性存储是个数据平台问题,可视化只是表层。多数人以为监控等于 Grafana 仪表盘,其实 Grafana 只是可视化层,核心是数据库:查询挂了仪表盘就挂了,数据库一挣扎,一切都跟着挣扎。可观测性存储是高频时间序列数据仓库,写重、读重、高基数、压缩、保留、成本压力,这不是 OLTP 数据库的问题。
基数爆炸的解法前面说过了。存储分层也重要:热事故需要热数据、快速查询,不该在热事故期间去查冷数据。那次事故我们没做冷热分离,也没做预计算和缓存,所有查询都实时算,事故期间先变慢,再失败,再 OOM。
从 CPU 到收入:监控该看哪一层
CPU 正常,客户宕了:看不到用户影响,是因为监控在错误的层级。监控有层级,业务风险/价值 → 模型/逻辑 → 管道 → 服务 → 基础设施,越接近业务越接近真相,越接近基础设施越接近噪音。那次事故里我们卡在基础设施层级,CPU、内存都正常,看起来没事,但用户已经宕了,真相在业务层级,我们看不到。问题不在缺数据,在数据待在错误的层级。
基础设施指标不是没用,但没有上下文化就是噪音:CPU 90% 不代表风险,CPU 90% 加上用户影响才是风险。
认知栈
从原始信号到行动有一条完整链条:原始信号 → 处理后的信号 → 风险解释 → 决策接口 → 行动。
| 层级 | 02:25 事故状态 | 缺失后果 |
|---|---|---|
| 原始信号(CPU、内存) | 存在 | - |
| 处理后的信号(聚合、趋势) | 存在 | - |
| 风险解释(SLO、错误预算) | 缺失 | 不知道信号对用户意味着什么 |
| 决策接口(回答关键问题) | 缺失 | 答不了"影响多大?要回滚吗?" |
| 行动(告警、自动化响应) | 缺失 | 触发不了回滚、扩容 |
栈在风险解释处断了,后面全跟着断。
管理层问"是单个客户吗?“答不了,因为没有每客户 SLO。有的话就能看到"客户 X 宕了,其他正常"或者"所有客户都受影响”。
要监控的是价值流(用户请求 → 服务 → 依赖 → 响应 → 用户体验),基础设施指标(CPU、内存、网络、Pod)只能算配角。那次事故,价值流断在连接池耗尽那里,我们看不到。
仪表盘要回答的四个问题
如果 02:25 有一个支持决策的仪表盘,它会显示的是用户影响、风险级别、推荐行动,跟 CPU、内存、错误率是两回事。
仪表盘必须能回答四个问题:系统安全吗?在变糟吗?需要行动吗?什么行动?回答不了就没有价值。
监控分两种:战术监控实时、绑定行动、聚焦决策,比如 Oncall 仪表盘、告警系统、SLO 监控器;探索监控是历史、分析、洞察,比如容量规划、趋势分析、事后分析工具。核心监控必须是战术的,那次事故里我们需要的是战术监控,手上有的是探索型的,类型错了。
仪表盘价值的衡量标准还是决策延迟。02:25 那次,决策延迟接近无穷大:打开了仪表盘,看到了指标,却什么都决定不了。如果当时有用户影响数据,能决定回滚还是等;有风险级别,能评估紧迫性;有推荐行动,能直接行动。仪表盘要为事故条件设计,事故时需要快速决策、清晰行动、风险评估,容量规划、趋势分析这类稳定状态的需求是次要的。
为什么工程师绕过仪表盘
02:40,工程师开始 SSH 进机器,彻底绕过仪表盘,因为仪表盘帮不上忙:看到指标,支撑不了决策,只好自己找路。
信任崩塌
监控系统本质上也是信任系统,崩塌的症状是误报太频繁、出过漏报、数据延迟、仪表盘和真实体验对不上、事故时数据缺失。那次事故里好几条都中了:仪表盘绿色但用户宕了、没有用户影响数据、错过了真正的问题。信任一旦崩塌,工程师就绕过监控自己 SSH、翻日志,监控变成摆设。
信任要靠工程手段维护
信任预算给每个信任组件分配错误预算(误报、漏报、延迟);信任透明显示数据新鲜度、置信度分数、错误率;信任恢复要承认误报、修根本原因、沟通改进;信任监控要盯静音率、绕过率。那次事故里这些都没有,信任无声地崩塌了。
所有权
没有所有者等于不存在:仪表盘在那里,但没人拥有,所以没人维护、没人信任,自然衰败。所有权模型可以是单一所有者、轮换、共享,甚至社区维护,但必须明确结构,不能模糊。工程师绕过监控通常出于四种原因:不帮忙、不可靠、太慢、门槛太高,那次事故里四条都中了。
从风险出发设计监控
如果按风险设计,我们会监控连接池饱和度,但我们没有:监控的是 CPU、内存、错误率,因为这些容易测,连接池饱和度要先想清楚风险是什么,更麻烦。
正确的思路是先识别什么可能出错(连接池耗尽、依赖超时、请求饱和),再确定什么信号能表征这些风险(连接池利用率、依赖延迟、请求队列深度),按影响和概率排优先级(连接池耗尽导致级联超时,高影响高概率,利用率超 80% 告警),最后验证能不能检测到、告警会不会触发正确行动。我们跳过了这些,监控容易的,没监控重要的:如果当时从风险出发设计,本可以在用户注意到之前就发现问题。监控必须能回答:在赚钱吗?在伤害用户吗?失控了吗?在变慢吗?快出问题了吗?答不了这些就没有存在价值。
六种死法
| 死亡模式 | 症状 | 根本原因 | 事故中是否出现 |
|---|---|---|---|
| 存在但不被信任 | 工程师绕过、SSH 手动排查 | 信任崩塌、无所有权 | 是 |
| 告警噪音崩塌 | 告警风暴、误报过多、被静音 | 无信号过滤、无分组节流 | 否 |
| 系统脆弱 | Prometheus OOM、查询变慢 | 与应用耦合、无元监控 | 是 |
| 答不了决策问题 | 有指标但做不了决策 | 只有原始指标、无风险框架 | 是 |
| 跟生产一起死 | 生产崩溃时监控也崩溃 | 共享基础设施 | 接近 |
| 监控和现实对不上 | 绿色但用户宕了 | 快乐路径偏见、错误 SLO | 是 |
那次事故里,多种死亡模式同时出现。但追溯到根上都是同一个问题:监控没有为"不确定性下的组织决策能力"设计过。
它会死在哪里
回到最初的问题:现实 → 原始信号 → 聚合信号 → 风险解释 → 决策层 → 行动 → 系统变化 → 反馈,链条任何一环断了,监控就失效。那次事故里,链条在多处断裂:风险解释缺失、决策层缺失、行动缺失,有信号有聚合,但没有解释、没有决策、没有行动。信任崩塌让工程师绕过监控,生存能力不足让监控跟着生产一起摇晃,风险驱动设计缺失让监控盯错了东西,决策能力缺失让什么都决定不了,控制循环断裂让系统没有反馈也没法纠正。一环断,环环断。
监控系统真正的目的,是在不确定性中维持组织的行动能力。
我现在做监控设计的时候,第一个问题永远是"这个信号能帮谁做什么决策"。能回答的留下,回答不了的砍掉。从那次事故之后,再也没让仪表盘骗过我。