干运维这些年,我最大的变化是心态。刚接手线上系统那会儿,每天最大的压力就来自"未知"——你不知道故障什么时候来,也不知道第一个发现故障的究竟是你还是用户。很多时候是用户先炸了,客服那边接了一堆投诉,业务方跑来找你"查一下怎么回事",你才开始登录机器看日志。这种被动救火的日子,我相信不少人都经历过。
后来我花了不少时间把"发现故障"这件事从人肉模式改成系统模式。所谓"第一时间发现线上故障",核心不是采购一套监控平台就完事,而是建立起一套"有指标、有规则、有通知、有定位"的闭环。这篇文章就把我在这条路上沉淀下来的思路、踩过的坑和最终落地的方案完整梳理一遍。内容比较长,但每一步都是可以直接拿去复用的,适合正在搭建或优化故障发现体系的运维、后端和SRE同学参考。
1. 故障发现的本质是抢时间:先搞懂你比用户快多久才算"第一时间"
1.1 三种发现路径,效率天差地别
线上故障被发现的方式,归纳起来无非三种。
第一种是用户投诉。这是最被动也最糟糕的方式。用户不会在系统出问题的第一秒就来找你,他通常会先刷新一次,再等一会儿,再换个网络重试,折腾几轮之后才想到去客服反馈。等到投诉真正到达你手里,故障往往已经持续了十几分钟甚至更久,影响面早就铺开了。更麻烦的是,投诉信息是碎片化的,有人反馈"页面打不开",有人反馈"下单失败",有人反馈"支付转圈",你得从这些模糊的描述里反推真正的故障点,效率极低。
第二种是人工巡检。团队安排值班人员盯大屏、定时看面板,这比等投诉主动一些,但本质还是靠人。人的注意力不可能二十四小时在线,几十个指标在一个屏幕上滚动,某一列数字出现异常波动,肉眼很难第一时间识别出来。即便识别出来了,还要判断"这个波动到底要不要处理",非常考验经验。值班盯屏只能作为辅助,不能作为主力。
第三种是自动化告警。监控系统按照预设规则持续采集指标,一旦异常触发条件,立刻通过电话、短信、群消息等方式通知到具体的人。这种方式最大的优势是"不依赖人的注意力",机器七乘二十四小时都在盯着,理论上可以在秒级到分钟级内发现问题。我们说的"第一时间发现线上故障",指的就是把发现路径从第一、第二种转向第三种,让告警比用户投诉领先一步甚至领先好几步。
1.2 理解"机会窗口",才知道要快到什么程度
这里说一个我常用到的概念——机会窗口。用户对一次故障的容忍时间是有限的,具体多长取决于业务形态和用户心智。
举例来说,一个电商页面加载缓慢,前几秒用户会觉得"可能是网络波动",重试一两次之后开始焦虑,超过一分多钟没有响应,很多人就关掉页面走了,一部分人会去投诉。那对我们来说,合理的发现目标就不是"在用户投诉之前",那太宽松了,而是"在用户大规模感知之前"。监控系统应该在页面开始变慢的几十秒内就捕捉到异常并完成通知,给处理人留出操作缓冲。
理解了这个窗口,你就能理解为什么告警规则不能拍脑袋乱设。阈值设得太松,故障发生了你比谁都后知后觉;设得太紧,天天收到"假警报",人麻了之后真故障也被当垃圾信息忽视。所以后面讲到的所有监控指标和告警设计,都围绕一个核心目标:在机会窗口之内完成发现、通知、响应这三步。
2. 搭监控体系不是装个工具,而是铺四层"雷达"
很多人以为监控就是部署一套开源监控平台,配几个常见的 CPU、内存指标就完事了。我刚开始也这么干过,结果就是:系统经营得死死的,但该出的故障一个没拦住。后来我渐渐明白,监控体系要能"第一时间发现故障",必须从上到下铺四层雷达。每一层覆盖不同的故障类型,缺一层就有盲区。
2.1 第一层:基础设施层,先保证机器和网络不"哑火"
这是最底层也最基础的监控。涵盖 CPU、内存、磁盘、网络流量、负载均衡、数据库连接数等资源指标。这一层解决的问题是:资源耗尽、机器宕机、网络异常这类"物理性故障"。
为什么这一层仍然重要?因为很多应用层故障的根源其实在基础设施。比如某次接口大面积超时,查到最后是磁盘写满导致日志写不进去,应用进程虽然还活着,但性能已经急剧恶化。如果只看应用指标,你会看到响应时间飙升,却不知道病因在底层。把基础设施层的指标管起来,相当于给上层故障排查提供了一个"地基"视角,很多疑难杂症都能从这里找到线索。
基础设施层的采集频率通常设在 15 到 30 秒一次。CPU、内存这类的指标变化很快,动辄按分钟采集会漏掉瞬时尖峰。
2.2 第二层:应用层,盯住黄金四指标
应用层监控是大多数团队最先搭建的,也是最容易做走样的。我看到很多系统的应用监控做了整整一屏指标,看起来琳琅满目,真出了故障却一个都用不上。后来我按行业内常说的黄金四指标来收敛:请求量(Rate)、错误率(Errors)、响应时间(Duration)、饱和度(Saturation)。
请求量反映流量水位,正常情况下有比较规律的昼夜曲线,突增可能是活动流量,突降则可能是入口挂了或服务不可用。错误率无需多解释,HTTP 5xx 比例、异常调用次数都在此列,它是故障最直接的"表情"。响应时间要看分位数,P95、P99 比平均值更有参考价值,因为平均值容易被少数慢请求拉高,掩盖大部分用户的真实体验。饱和度对数据库、缓存这类有容量上限的组件特别关键,连接池用满、队列积压都属于饱和,饱和往往意味着"离宕机只有一步之遥"。
很多团队只盯了请求量和错误率,忽略了饱和度,结果就是故障的前兆信号就在眼前而毫无察觉。
2.3 第三层:业务层,盯住"钱袋子"指标
业务层指标是最能体现"故障影响"的一层,也是最容易被技术团队忽略的一层。说来也有意思,业务方最关心的东西,往往是运维搞监控时最后才想到的。
举个例子,下单接口的请求量、错误率、响应时间全部正常,但支付回调的消费端积累了大量的消息没处理,导致订单一直卡在"待支付"状态,用户在下单之后迟迟收不到确认信息。这种故障从应用层指标看毫无异常,但它实实在在伤害了用户和业务。如果我们没有监控"成功支付的订单量"这类业务指标,就只能等用户投诉才能发现。
所以我在设计监控体系时,一定会和业务方一起梳理出三到五个核心业务指标,比如:每分钟成功支付笔数、单量、注册完成数、订单取消率等。这些指标被业务方看作是"钱袋子",一旦掉下来就说明出了事。
业务指标的变化不能只靠固定阈值判断,因为不同时段、不同活动周期波动很大。这时候就要用同比和环比。比如今天下午三点的单量比昨天同一时段跌了百分之四十,哪怕绝对值看起来还行,也值得立刻排查。
2.4 第四层:用户体验层,从外部视角兜底
前面三层都是从系统内部去看,但用户的实际体验到底如何,内部指标未必骗不了你。有些网络链路问题、地域性运营商问题、公网出口问题,服务端指标一切正常,用户那边却是另一番景象。第四层就是站在用户视角做探测,业内叫主动探测或拨测。
做法其实很简单:从外部节点周期性地发起真实请求,访问你的核心页面或接口,记录可用性和响应时间。这就像是雇了一个"隐形用户",每隔几分钟帮你走一遍核心链路,有问题马上报告。我在某一次故障中的经历很典型:某地域用户的访问大量超时,服务端各项指标都正常,最终是靠拨测数据定位到是该地域某条网络线路的问题,协调网络运营商才解决。如果没有外部视角,这个故障根本发现不了。
四层雷达铺完之后,监控体系才算有了"全面感知"的基础。但感知只是第一步,接下来要解决一个更让人头疼的问题:告警规则怎么定。
3. 告警规则设计:既要比用户快,又不能变成噪音
监控体系铺完之后,最典型的问题就是告警泛滥。我见过一个团队的监控群里,每分钟弹好几条告警,大家从紧张到麻木,最后直接把群折叠了。这比没有监控更可怕——真正的故障被淹没在大量无效告警里,等于回到了"被动救火"的状态。告警规则的设计,本质上是两条线之间找平衡:发现得够快,同时误报率可控。
3.1 静态阈值和动态基线,配合着用
静态阈值是最直觉的做法:CPU 使用率超过百分之九十就告警,接口 P99 响应时间超过五百毫秒就告警,磁盘使用率超过百分之八十就告警。优点是简单直观,缺点是很傻也很僵硬。
比如接口 P99 平时是两百毫秒,某天因为业务高峰期涨到四百毫秒,绝对值没到预设阈值,但性能已经明显劣化了一倍,这时候不告警就错过了。反过来,某些业务接口的 P99 平时就徘徊在八百毫秒左右,你设个五百毫秒的阈值,它一天到晚都在告警,全是无效信息。
更聪明的做法是动态基线。监控系统基于历史数据自动学习每个指标的"正常波动范围",当指标偏离基线超过一定幅度时,就判定为异常。比如系统学到每天上午十点到十一点这个接口的 P99 大致是两百到三百毫秒,某天突然跳到六百毫秒,即便绝对值不高,也会触发告警。动态基线尤其适合业务有明显周期波动的场景,能很大程度减少误报。
我的经验是两者结合:核心硬性指标用静态阈值保底,防止基线算法抽风的时候漏报;周期性强的业务指标用动态基线识别偏离,减少琐碎告警。不要指望一种方案包打天下。
3.2 持续时间窗口:别被瞬时抖动骗了
新搭建监控的团队最容易犯的毛病,就是把阈值触发当成立即告警。指标刚碰了一下线,告警就弹出来了,结果两秒钟之后指标自己恢复了,留下一堆没有价值的告警记录。
正确做法是设置持续时间窗口。比如"CPU 使用率超过百分之九十持续五分钟"才触发告警,或者"错误率超过百分之五持续三分钟"才触发。这个窗口的作用是过滤瞬时抖动和偶发毛刺,让告警只留给"持续存在"的异常。
具体窗口设多长,取决于业务特征。对核心支付链路,五到十秒级别的快速告警都是合理的,因为这类故障多持续一秒钟就多放大影响;对非核心的报表系统,五分钟甚至十分钟的窗口都可以接受,晚一点发现不影响大局。做这个决策的核心原则是:窗口时长应小于等于故障影响用户的机会窗口。
3.3 告警分级:想清楚什么级别该打扰人
如果你把所有异常都当成必须马上响应的级别,处理人很快就会崩溃。告警分级是治理告警疲劳的基础操作。
我一般把告警分成三个等级。最高等级是 P0,代表核心业务不可用或即将不可用,例如支付服务大面积报错、登录服务全线超时、核心数据库连接池耗尽。P0 必须通过电话、短信、PagerDuty 这类强打扰渠道通知,并且是二十四小时不间断值班的人来响应。中间等级是 P1,代表某模块或某地域出现异常,影响可控但有扩散风险,通过群消息和电话通知处理人,要求在一定时间内确认并处理。最低等级是 P2,代表资源水位告警、非核心模块异常,只需要在群里通知相关人员,工作日处理即可。
很多人会问,P0 和 P1 的边界怎么定?我的判断标准是:如果这个故障持续半小时不处理,会不会造成用户投诉或收入损失。会,就是 P0;不会,但可能恶化,就是 P1;基本没影响,就是 P2。带着这个标准去评审告警规则,比凭空分类容易得多。
3.4 通知渠道分场景,别全靠一种方式
通知渠道的设计也很有讲究。群消息适合 P1、P2 这类需要留痕、大家都能看见的告警;电话和短信适合 P0 这类需要立刻把人叫醒的告警。我见过有团队把所有的告警都发到同一个群里,P0 和 P2 混在一起,结果真正需要立刻处理的被刷掉了。
推荐的落地方式是一张表明确对应关系:P0 告警走电话加短信加群消息三重轰炸;P1 走群消息加短信;P2 只走群消息。这样处理顺序一目了然,值班人员不用在群里翻半天找哪条是真正要紧的。
4. 从"发现"到"定位":日志、链路和一套标准动作
监控告警解决了"系统出问题了"这一步,但真正让人头疼的是下一步:"问题到底出在哪个环节?"。如果没有一套配合手段,你人是从睡梦中被叫醒了,但面对着告警信息还是一脸茫然。所以完整的故障发现体系,必须包含快速定位的能力。
4.1 日志:不要全量收集,要结构化采集
日志是定位问题的基础素材,但日志收集这件事我强烈建议做一次"减法"再考虑"加法"。
最反感的做法是把所有系统输出的日志全部收集起来,不管有没有用。结果就是日志平台被海量噪音塞满,真正要查的时候,检索慢得像在淘金。我后来定的规范是:日志按级别和用途分流,业务日志、错误日志、访问日志分开存储;必须包含结构化字段,比如请求 ID、用户 ID、接口名、耗时、状态码、错误信息、时间戳,尽量用统一的格式输出。这样的日志既能被快速检索,也能被后续的链路系统关联。
这里有个容易被忽视的细节:应用在异常分支里千万不要"吞异常"。打日志却只写一句"operation failed"是不够的,至少要把关键上下文打印出来,包括入参摘要、异常堆栈、依赖服务的地址和响应状态。每一个"吞掉的异常"都意味着故障定位时你少了一条重要线索。
4.2 链路追踪:一次请求的全景视图
当业务拆成多个服务之后,一次请求可能经过网关、认证服务、订单服务、库存服务、支付服务等七八个节点。如果只有零散日志,每个服务各记各的,你很难把一次完整请求串起来看全貌。
链路追踪的作用就是给每次请求发一个全局唯一标识,让它经过的每个服务都把这个标识记录在日志或追踪数据里。排查问题时,拿到一个请求 ID,就能把这次请求从入口到出口经过的所有节点、每个节点的耗时、是否报错完整地拉出来,一眼看清楚"时间到底花在了哪个环节"。
做链路追踪不一定非要上重型的分布式追踪系统,在小团队里,很多场景靠"请求 ID 贯穿日志"就能解决大部分问题。核心路径上的每个应用都要求把上游传入的请求 ID 透传给下游,并在日志中保留。先做到这一步,再考虑引入更完整的追踪系统,这是我认为更务实的路径。
4.3 定位问题的标准动作:隔离、对比、回放
我在故障定位上给自己定的标准动作是三步:隔离、对比、回放。
隔离,就是先判断故障面。告警来了先看影响范围:是个别用户、某个地域、某种机型,还是全部流量?通过告警信息和监控面板快速切分故障边界,能缩小排查范围。比如只影响某个地域,那就优先查该地域的网络链路和就近接入节点;全部流量都中招,问题大概率出在公共组件或核心服务上。
对比,就是拿当前数据跟正常数据比。对比时间维度可以做同比和环比,看看指标是什么时候开始变坏的;对比空间维度可以做单实例和集群的差异对比,看看是个别机器异常还是整个集群异常。很多问题一对比就暴露了:比如新上的一个版本在部分节点上存在内存泄漏,对比新旧版本节点的指标曲线就能快速锁定。
回放,就是用真实流量或模拟请求去复现链路。准备几台测试机器,构造和用户相同或相似的请求,逐步复现故障路径。不需要百分之百复现,哪怕复现出七成的相似路径,也能帮你缩小根因范围。
这三步走下来,大多数故障都能在十五分钟以内有一个明确的定位方向。配合上前面说的日志和链路数据,这套组合拳在实战中给我的体感非常稳。
5. 告警疲劳与告警风暴:监控越做越多,反而什么都看不见
告警疲劳是故障发现体系最大的隐形杀手。我聊过的不少团队都出现过这种状况:为了追求"不留盲区",把能监控的都监控了,结果每天平台弹出几百上千条告警,值班同学从上到下都麻木了。等到真正的 P0 级故障发生,一条告警混在几百条无关信息里,没有人注意到。这是典型的"劣币驱逐良币"。
5.1 告警风暴是怎么发生的
告警风暴的成因通常有几个。
第一个是告警规则之间缺少依赖关系。最典型的就是"级联风暴":数据库连接池告警之后,依赖数据库的所有服务的连接失败告警、接口超时告警、错误率告警跟着一起弹出来。本质上是同一个根因,却刷了几十条不同表现形式的告警。
第二个是阈值设计不合理,大量边缘性告警。比如磁盘使用率超过百分之八十就告警,而磁盘增长很慢,这条告警可能连续触发一周,每天都弹,处理人看习惯之后就麻木了。
第三个是规则没有定期复盘。系统扩容了、流量结构变了、业务上线了新功能,过去合理的阈值现在可能已经完全不合适,但规则还在机械地跑。
5.2 治理告警的五个手段
针对这些成因,我的治理手段可以概括为五条。
第一条,告警聚合。把同根因的告警合并成一条。具体的做法可以按依赖关系设置抑制规则,比如"数据库告警时,禁止触发数据库连接失败类服务告警";也可以按时间窗口做聚合,比如五分钟内同一服务的多条告警合并为一条。
第二条,告警分级降噪。把那些不需要半夜响应的告警降级为 P2,工作日处理。降级的原则是:这条告警在半小时内不处理,会不会造成用户投诉,不会就降级。
第三条,告警预案。每一条 P0 告警必须有对应的处置预案,至少写明"接到这条告警之后第一个动作是什么、在哪个面板看哪些指标、由哪个团队负责"。有了预案,告警才称得上有操作性。没有预案的告警,本质上只是"噪音的正式通知"。
第四条,定期复盘和调优。我养成了一个习惯,每隔一段时间拉出所有告警记录,逐个过一遍,统计每条告警的触发次数、被确认的次数、以及最终是否关联上真实故障。触发很多但从未关联到故障的告警规则,要么调阈值,要么直接删掉。
第五条,告警去重。同一实例同一指标在持续告警期间不要重复通知,只在状态从正常切换到异常时发一次,恢复时再发一次。这看着是小事,但能大幅削减无效消息量。
5.3 故障演练:验证体系的唯一标准
告警规则定得好不好,监控覆盖全不全,不能靠嘴上说,要靠演练来验证。我强烈建议每季度至少做一次故障演练。
做法不算复杂:挑一个非核心时段,人为在预发或灰度环境里制造一个故障,比如给某个核心接口注入延迟、停掉一个下游依赖、填满一块磁盘,然后观察监控系统能不能在预期时间内触发告警,值班同学能不能通过现有的工具和笔记在合理时间内定位到原因。演练结束之后认真复盘,把暴露出来的问题记录进改进清单。
我有一次演练发现,某个核心服务的告警规则虽然存在,但通知的接收人已经离开了团队,等于一条"无主告警"。这种问题在真实故障前根本发现不了,只有演练能把这些死角挖出来。故障演练不是走形式,它就是检验整个发现体系有没有真正闭环的试金石。
6. 我踩过的坑,和最后的落地心得
6.1 三个亏吃出来的教训
第一个坑是过度相信监控平台的默认配置。开源监控平台带了一堆预置的监控项和告警规则,看着很周全,但那些规则跟你的业务场景完全不匹配。我早期直接启用默认告警,结果一个晚上收到几百条无效告警,被折腾到怀疑人生。现在我的做法是:默认配置只作为采集参考,所有告警规则必须逐条按业务场景重新设定。
第二个坑是只关注技术指标,不关注业务指标。某次线上事故让我印象特别深,系统各项技术指标全部正常,技术人员视角里一切安好,但用户就是下单不成功。后来发现是某个业务状态流转的逻辑在特定场景下出了 bug,这类故障从技术指标层面根本感应不到。从那之后,我每次都坚持跟业务方一起梳理核心业务指标,把"用户能不能顺利完成关键操作"纳入监控范围。
第三个坑是告警发出去了,但没有落到具体的人。曾经有一条 P0 告警发到了一个多人群里,大家都看到了,但每个人都觉得"别人会处理",结果半小时过去了,没有任何人来响应。现在我在设计通知体系时,每条 P0 告警必须明确标注唯一责任人,值班轮值表挂在显眼位置,确保"告警有主,响应有人"。
6.2 给正在搭这套体系的同学几句掏心窝的话
如果你现在正处在从零搭建或优化故障发现体系的阶段,我有几个建议供参考。
第一,不要追求一步到位。先覆盖核心链路、核心服务、核心业务指标,跑通"监控采集—告警通知—人肉响应—事后复盘"的完整闭环,再逐步扩充覆盖面。一次铺得太宽的代价就是告警质量失控,管不过来。
第二,把告警规则当成代码来维护。规则变更要有记录、要有评审、要有版本,放在统一的配置管理里,不要散落在"谁临时改的,没人记得"的状态。告警规则本身就是要持续迭代的资产。
第三,人永远比工具重要。再完善的监控体系,也需要一个知道"看到告警后该做什么"的人。定期做培训、做演练、做复盘,让每一个值班的人真正熟悉自己负责的系统,这套体系才能发挥它应有的价值。
最后再分享一个小技巧:我会专门维护一张"故障发现速度"记录表,把历次故障的发现途径、发现耗时、用户影响时长记下来。每隔一段时间回看这张表,你会发现体系优化的效果是看得见摸得着的——发现耗时从最初的十几分钟,逐步压缩到几分钟甚至几十秒,那种感觉,确实很有成就感。