当你的服务商宕机时
最后更新:
服务商状态页是云、托管、代码或支付服务商为宣示自身健康状况而维护的公开仪表盘:一个总体指示值、一份组件清单,以及一条由服务商本人在事件进行中亲手写下的事件时间线。读懂它是一种运维技能,因为标题只是摘要,真相住在它下面——哪个组件受影响、在哪个地区、宣布的影响有多大、事件在服务商自己的流程中已经走到了哪一步。本文就教你这种读法,并以你所依赖的服务商出事时最初十分钟该做什么收尾。从服务商状态看板开始,它把主要服务商的页面汇集成一份快照,并始终记住是它宕机了,还是只有你?这个问题:这两个工具回答的是同一份疑虑的相反两半。
两件不同的事:指示值与事件状态
每个成熟的状态页都带有读者不断混淆的两个独立信号。第一个是总体指示值:整个服务的一个汇总状态,在页面背后的机器可读馈送中通常是 none、minor、major、critical 或 maintenance 之一——这个模型记录在 Statuspage 开发者文档中,大多数大型服务商要么直接使用它,要么紧密地模仿它。指示值刻意粗糙。它的存在是为了让忙碌的读者——或者像我们的状态看板这样的机器——能在一秒内回答“那边有什么不对吗?”,它由受影响最严重的组件、服务商自己的判断,或两者共同计算得出。
第二个信号是事件本身,它有指示值抹平了的自身生命周期。一起事件以名称、宣布的影响和一个取自流程的状态开启:调查中(我们看到了症状,还不知道原因)、已定位(我们知道原因并正在处理)、监控中(修复已上线,我们正在观察它是否站得住)和已解决(我们相信它结束了,以复盘为准)。这些状态携带指示值无法携带的信息。一起已在监控中停留两小时的危急事件通常正在结束;一起四分钟前刚进入调查中的 minor 事件则可能变成任何样子。
按这个顺序把两者都读完,并读它们之间的更新。事件下方的简短更新时间线,是服务商告诉你标题永远不会说的事情的地方:哪个子系统坏了、有什么变通办法、受影响的是数据还是仅仅可用性,以及下一次更新承诺在二十分钟还是两小时后。一场更新停止到来的事件本身就是一种信号——要么团队已经不堪重负,这与更长的故障相关,要么这起事件已悄悄被并入一场更大的事件。只截屏标题就停下阅读的运维者,例行地按照页面上信息量最少的那句话行事。
为什么“所有系统运行正常”仍可能意味着你宕机了
指示值总结的是整个服务,而现代服务不是一个东西。一个服务商可以全球诚实地全绿,同时你部署的地区、你调用的那一个产品界面、你被钉住的遗留 API 版本,或者你部署所需的控制平面,正在对每个碰到它的客户失效。组件清单正是为此而存在:像 GitHub 的状态页这样的页面把服务分解为 Git 操作、API 请求、Actions、Pages 等等,其中任何一个都可以在总体横幅保持安慰人心的同时降级——反之亦然,横幅为一个你从未用过的组件变红。
还有三个更安静的缺口。第一,宣布滞后:服务商在确认一起事件后才宣布它,而不是在第一个错误发生时,因此许多故障的最初几分钟里,看到的是一张绿色的页面和一条燃烧的社交馈送;页面没有撒谎,它只是落后了。第二,阈值:服务商可能把某一层级上百分之二的错误率当作正常背景而从不宣布任何事,而这百分之二恰恰集中在你的流量模式上。第三,范围:状态页描述的是电线在服务商那一侧的情况。你的用户与一个健康的服务商之间的 DNS 故障、路由问题或被阻断的路径,会在绿色指示值之下为你制造一场全盘故障——这正是为什么那个伴随的问题“是它宕机了,还是只有你”必须从独立的观察点回答,而不是从服务商自己的页面回答。
工作规则是把绿色当作“没有宣布的事件”,永远不要当作“已证明健康”。当你自己的监控说用户在失败、而服务商说运行正常时,就你的用户而言相信你的监控,并把状态页用于另一件工作:检查之后是否出现一份宣布——它会追溯地确认原因——以及你依赖的组件是否有与你正在经历的这场形状相同的事件历史。
订阅到组件,而不是页面
大多数运维者订阅状态页的方式和订阅简报一样:一个订阅、每起事件、永远如此——然后可想而知地开始忽略这些邮件,因为一个大型服务商的全球馈送会稳定地滴下他们不用的组件、他们不服务的地区的事件。告警疲劳不是性格缺陷;它是对信号范围划错的正确反应。修复是机械的,几乎每个成熟的状态页都有:在组件级别订阅。定义这些指示值的同一个 Statuspage 模型也允许订阅者按组件过滤,而运行自己系统的服务商,如 Cloudflare 的状态页,也通过自己的订阅流程提供同样的选择。
把每个订阅的范围划到在凌晨三点确实会改变你行为的东西上。你的生产流量调用的组件属于响亮的渠道——那个会呼叫、发消息或至少标记你几分钟内会看到的东西的渠道。你只用于构建、分析或内部工具的组件属于一个你在工作时间审阅的安静渠道。你根本不用的组件不属于任何地方:你正确地忽略的每一条通知,都让下一条更容易被忽略,包括那条重要的。技术栈变化时重新审视这份清单,因为订阅会向两个方向腐烂——没人订阅的新依赖,和还在呼叫一个没人看的渠道的死依赖。
尽可能偏好机器可读的馈送。电子邮件是状态页提供的最慢、最容易忽略的渠道;而 webhook 和馈送可以驱动你自己的仪表盘、打开一张内部工单,或在第一条用户投诉到来之前翻起你支持团队准备好的占位页。即使是轻量版也有回报:我们的服务商状态看板上的快照正是从这些公开馈送构建的,这证明这些数据就在那里,可供程序化地消费,而不是被供在一个你得记得打开的浏览器标签页里欣赏。
建立你自己的依赖清单
没有一份清单,上述建议都行不通,而大多数团队都是在故障中才发现自己没有。一份依赖清单只是一个听起来简单其实不然的问题的书面答案:哪些外部服务,如果今晚停了,会让我们停下——哪些只会让我们难堪?在天气平静时建它。逐个界面走过你的架构——托管、DNS、代码托管与 CI、数据库与存储服务商、支付处理商、邮件与短信发送方、身份服务商、错误追踪器、分析标签、你的页面从别人 CDN 加载的字体与脚本——并为每一个写下:服务商、你实际消费的组件、它的状态页在哪里,以及它失败时你的用户会经历什么。
按每个条目失败的形状而不是你多喜欢这个供应商来给它排名。有些依赖是硬的:它们停,你就停,唯一可做的工作是沟通和等待。有些是软的:没有它们网站也能运行,只是降级——没有分析、没有聊天小部件、没有个性化——对这些,清单应写明谁有权把它们关掉、如何关。还有些是隐藏的:你没有选择的传递性依赖,比如你的 SaaS 数据库本身运行其上的云地区的状态,或一切之下的证书与 DNS 基础设施。隐藏依赖正是制造“一切都宕机了、而我们付费的东西一个都没被列出”那种故障的那些,你通过向每个供应商问一次他们依赖什么来找到它们。
把清单放在一场事件能够到它的地方:在运行手册里、升级名单旁边,而不是在一个当身份服务商正是宕机的那个东西时没人能打开的 wiki 页面里。一页就够了。它在故障中的工作是把“出了点问题”变成一份清单——对每个硬依赖,三十秒内,上或下——它之后的工作是被纠正,因为每一场真实事件都会教你一个你排错了的依赖。一份从未被纠正的清单是一份历史文件,不是运维文件。
服务商故障的最初十分钟
第零到二分钟:确认并定位。检查你自己的监控,确信这场失败是真实的、且归你宣布,然后打开状态看板和可疑服务商的页面。你在回答一个问题:有没有一份宣布的事件与你使用的东西重叠——组件、地区、产品?如果有,你就有了原因和第一条消息。如果没有,把检查范围扩大:你清单中的另一个服务商、你自己最近的一次部署、你的 DNS。大多数虚假的戏剧死在这两分钟里,大多数真实的事件也在这里成形。
第二到五分钟:沟通,直白且尽早。在你的用户真正在读的渠道里告诉他们:一家被点名的上游服务商正在发生事件,这在实际层面意味着什么——什么不能用、什么还能用、他们的数据是否安全——以及你下一次更新的时间。在第四分钟发出的一条诚实占位消息,胜过在第四十分钟发出的一份精确解释,因为沉默正是用户用他们最坏的猜测和你竞争对手的名字来填充的东西。在内部,开一条事件线,指定一个人发言,并给一切打上时间戳;你在复盘时会感谢自己,服务商的支持团队在你需要他们时也会。
第五到十分钟:停止让它变糟,并准备软着陆。冻结部署——在一场活跃的上游事件中做出的变更无法评估,甚至可能无法回滚。关掉对失败服务商猛烈重试的激进重试和非必要任务;当一万个客户端步调一致地重试时,恢复可测量地变慢,而且有些服务商会把你限流到第二场自找的故障里。关掉或降级你的清单标记为可舍弃的软依赖,有占位页就贴出占位页,然后沉下心来进入事件决定的节奏:监控服务商的更新、无论有没有新闻都在承诺的时间更新你的用户,并且除非事实变化否则不再改变任何东西。故障会在服务商的日程上结束,不在你的上面;你的十分钟决定的是,你的用户会把这件事记作他们服务商的倒霉日,还是你的。