在复杂的软件系统和互联网基础设施中,系统故障不可避免。真正重要的不是故障是否发生,而是团队能否在紧急情况下快速响应、有效协作,并通过事后复盘持续改进。本文将围绕应急响应、事件响应流程、系统故障处理、主动测试和故障复盘,介绍大型技术团队在真实故障场景中的实践经验。
东西总会坏,这就是现实。
无论事件影响有多大,也无论组织规模如何,真正关系到一个组织长期健康发展、并使其与众不同的,往往是相关人员在紧急情况下的应对方式。很少有人天生就能在危急时刻做出高效反应。妥善的应急响应离不开事前准备,也离不开定期、贴近实际的演练与培训。建立并维护完善的培训和测试流程,不仅需要员工认真投入,也需要管理层和决策层的支持。只有这些条件齐备,团队才有可能投入资金、时间和精力,必要时甚至牺牲一部分系统可用性,以确保系统、流程和人员能够在紧急情况下高效运转。

在研发团队中,应急响应并不只是某一次故障处理,而应贯穿目标制定、需求评审、开发测试、发布上线、知识沉淀和复盘改进的全过程。企业可以借助 PingCode 这类智能化研发管理工具,将研发流程、项目进度、测试发布、知识库和外部工具连接起来,让事件响应过程中的信息、数据和经验能够更顺畅地流转与沉淀。
需要说明的是,关于“事后复盘文化”的章节已经详细讨论了如何撰写事后复盘报告,以确保需要应急响应的事件也能转化为学习机会(参见“事后复盘文化:从失败中学习”)。本章将通过更多具体案例,进一步说明应急响应在真实场景中的运作方式。
系统故障发生时该怎么办
首先,不要惊慌。你不是孤身一人,天也没有塌下来。你是专业人士,接受过相关训练,能够处理这种情况。通常,并没有人身安全受到威胁——受影响的只是那些可怜的电子。最糟糕的情况,也不过是半个互联网暂时瘫痪。所以,先深呼吸,然后继续处理问题。
如果你觉得人手不足,就请求更多人加入。必要时,甚至可以通知整个公司。如果你的公司已经建立了事件响应流程(参见“事件管理”),请务必熟悉并遵循该流程。
由实验引发的紧急情况
海外某些大型互联网公司会主动开展灾难和紧急情况测试(参见 [Kri12])。站点可靠性工程师会有意破坏系统,观察故障如何发生,并据此做出改进,以提高系统可靠性,防止同类故障再次出现。大多数情况下,这些受控故障测试都会按计划进行,目标系统及其依赖系统的表现也大体符合预期。测试过程中,团队通常会发现一些薄弱环节或隐藏依赖,并记录后续行动项,用于修复发现的问题。然而,有时团队的假设与实际结果会相去甚远。
下面这个测试案例,就暴露了一些出乎意料的依赖关系。
细节
团队希望找出大型分布式 MySQL 数据库中某个测试数据库的隐藏依赖关系。计划很简单:在一百个数据库中封锁其中一个,禁止所有访问。然而,谁也没有预料到接下来会发生什么。
响应
测试开始后的几分钟内,多个依赖服务报告称,外部用户和内部用户都无法访问关键系统。部分系统只能间歇访问,或只能访问其中一部分功能。
站点可靠性工程师判断,问题很可能出在这次测试上,于是立即中止测试。团队尝试回滚权限变更,但没有成功。不过,大家并没有陷入慌乱,而是立刻集思广益,寻找恢复正常访问权限的方法。随后,团队采用一种已经测试过的方法,恢复了副本和故障转移所需的权限。与此同时,团队联系了关键开发人员,请他们修复数据库应用层库中的缺陷。
在做出最初决策后一小时内,所有访问权限均已完全恢复,所有服务也重新建立连接。此次测试造成的广泛影响促使团队迅速、彻底地修复了相关库文件,并制定了定期复测计划,以防止此类重大缺陷再次发生。
发现
哪些方面进展顺利
受此次事件影响的依赖服务很快就在公司内部上报了问题。团队也正确判断出,原本受控的实验已经失控,并立即中止了测试。
在收到第一份报告后不到一小时,团队就完全恢复了权限,系统随即恢复正常运行。部分团队还采取了不同方法,重新配置系统以避开测试数据库。这些并行工作帮助服务尽快恢复。
后续行动项也得到了快速、彻底的落实,以避免类似故障再次发生。与此同时,团队建立了定期测试机制,确保类似缺陷不会卷土重来。
我们学到了什么
虽然这项测试经过了充分审查,并被认为覆盖范围很广,但事实证明,团队对依赖系统之间这种特定交互方式的理解仍然不足。
团队没有遵循事件响应流程。该流程当时才制定几周,尚未得到充分宣传。事实上,这一流程本可以确保所有服务团队和客户都能及时了解此次中断情况。为避免未来再次出现类似问题,站点可靠性工程团队将持续改进和测试事件响应工具与流程,并确保事件管理程序的更新能够清晰传达给所有相关方。
由于团队没有在测试环境中验证回滚流程,回滚流程本身存在缺陷,最终延长了停机时间。现在,团队要求在开展此类大规模测试之前,必须先对回滚流程进行全面、彻底的测试。
由配置变更引发的系统故障
可以想见,海外某些大型互联网公司拥有海量配置,而且这些配置极其复杂。与此同时,团队还会不断对这些配置进行变更。为了防止系统发生灾难性故障,团队会对配置变更进行大量测试,确保它们不会引发意外行为或不符合预期的结果。然而,这类基础设施的规模和复杂性决定了,工程团队不可能预见每一个依赖关系或交互方式。有时,配置变更并不会完全按计划发展。
下面是一个例子。
细节
某个周五,团队向全球推送了一项基础设施配置变更。该基础设施用于保护服务免遭滥用,几乎会与所有面向外部的系统发生交互。此次变更触发了其中一个系统中的崩溃循环漏洞,导致整个系统几乎同时开始反复崩溃。由于内部基础设施也依赖自身服务,许多内部应用程序也突然变得不可用。
响应
几秒钟内,监控告警开始响起,显示部分站点已经宕机。一些值班工程师同时遇到了他们认为是公司网络故障的情况,于是转移到配备生产环境备用访问能力的专用安全房间,也就是紧急避难室。其他无法正常访问公司网络的工程师也加入了他们。
在首次配置推送后的五分钟内,负责推送的工程师已经意识到公司内部系统出现故障。尽管当时他还不了解故障的整体范围,但他又推送了一次配置变更,回滚了第一次变更。此后,服务开始恢复。
在首次推送后的十分钟内,值班工程师宣布发生故障,并开始按照内部事件响应流程处理。他们开始向公司其他部门通报情况。推送工程师也告知值班工程师,此次故障很可能与刚刚推送并回滚的变更有关。然而,由于最初事件还触发了其他无关错误或配置问题,部分服务在长达一个小时的时间里仍未完全恢复。
发现
哪些方面进展顺利
有几个因素阻止了此次事件演变成大规模内部系统的长期瘫痪。
首先,监控系统几乎立刻检测到问题并发出告警。不过也必须指出,在这种情况下,监控并不理想:告警反复、持续触发,使值班人员应接不暇,常规通信渠道和紧急通信渠道都被大量信息淹没。
问题被发现后,事件管理总体上运转顺利,更新信息也能及时、清晰地传达。即使部分复杂软件栈不可用,带外通信系统仍确保所有相关人员保持联系。这次经历再次提醒团队,为什么站点可靠性工程需要保留高可靠性、低开销的备用系统,也说明了为什么这些系统需要经常使用和验证。
除了带外通信系统之外,团队还准备了命令行工具和备用访问方式。即使其他接口无法访问,工程师仍然可以执行更新和回滚变更。这些工具和访问方式在系统中断期间表现良好,但也暴露出一个问题:工程师需要更熟悉这些工具,并更频繁地对其进行测试。
基础设施还提供了另一层保护:受影响系统限制了向新客户端提供完整更新的速度。这一机制可能减缓了崩溃循环,避免系统完全宕机,使任务能够在两次崩溃之间保持运行足够长的时间,从而处理一部分请求。
最后,也不应忽视运气的作用。此次事件之所以能迅速解决,很大程度上是因为推送工程师恰好在实时通信渠道上密切关注情况。而这种额外谨慎并不是发布流程中的常规环节。推送工程师注意到推送后立即出现大量关于企业访问权限的投诉,于是几乎立刻回滚了变更。如果没有这次迅速回滚,中断时间可能会更长,故障排查也会困难得多。
我们学到了什么
此前推送新功能时,虽然进行了完整的金丝雀测试,但并未触发同样的漏洞。原因在于,当时并没有将一个极其罕见且特定的配置关键字与新功能结合使用。触发此次漏洞的具体变更被认为风险较低,因此采用了较为宽松的金丝雀测试流程。当该变更被全局推送时,一个未经测试的关键字与功能组合触发了故障。
颇具讽刺意味的是,改进金丝雀测试和自动化原本已经计划在下一季度成为重点工作。此次事件立即提高了这些工作的优先级,并凸显出一个事实:无论风险等级如何,都有必要进行全面的金丝雀测试。
不出所料,由于所有站点基本上都离线了几分钟,此次事件引发了大范围告警。这不仅干扰了值班工程师的实际处置工作,也让事件相关人员之间的沟通变得更加困难。
团队依赖自己的工具。用于故障排查和沟通的大部分软件栈,都依赖那些已经陷入崩溃循环的作业。如果这次故障持续更长时间,调试工作将受到严重阻碍。
由自动化流程引发的紧急情况
一些海外大型技术团队投入了大量时间和精力来开发自动化系统,用于管理所有机器设备。令人惊叹的是,只需极少的操作,就能在整个设备组中启动、停止或重新配置许多作业。有时,当事情没有完全按计划发展时,自动化系统的高效率也会带来意想不到的后果。
下面这个案例说明,行动过快并不总是一件好事。
细节
作为一次例行自动化测试的一部分,团队连续提交了两份针对同一批即将退役服务器部署的停机请求。在第二次停机请求中,自动化流程里的一个细微漏洞导致这些部署中的所有机器在全球范围内都被送入 Diskerase 队列,硬盘即将被擦除。更多详情请参阅“自动化:大规模故障测试”。
响应
第二次请求关闭后不久,值班工程师收到通知:第一台小型服务器已经离线,等待退役。调查后,他们发现这些机器已被移入磁盘擦除队列。按照正常流程,值班工程师立即切断了该位置的流量。由于该位置的机器已经被擦除,无法响应请求,为避免请求直接失败,值班工程师将流量从该位置转移出去,重定向到仍能正常处理请求的位置。
不久之后,世界各地所有此类服务器的值班告警都响了起来。面对这种情况,值班工程师立即禁用了团队的所有自动化程序,以防止损失进一步扩大。随后,他们又停止或冻结了其他自动化程序和生产维护工作。
不到一小时,所有流量都被分流到其他位置。虽然用户可能会感受到延迟增加,但他们的请求仍然得到了处理。此次故障正式结束。
然而,真正的挑战才刚刚开始:恢复。一些网络链路报告严重拥塞,网络工程师发现瓶颈后立即采取了缓解措施。其中一个瓶颈位置的服务器被选为众多待重建服务器中的第一批重建对象。在最初中断发生后三小时内,几位工程师坚持不懈地推动重建,该服务器得以恢复上线,并再次开始正常接收用户请求。
随后,一个地区的团队将工作移交给另一个地区的团队。站点可靠性工程团队制定了一项计划,采用精简但人工参与的流程,优先进行系统重装。团队被分成三个小组,每个小组负责人工重装流程中的一个步骤。三天内,绝大部分容量恢复上线,剩余容量则将在接下来一两个月内陆续恢复。
发现
哪些方面进展顺利
大型服务器部署中的反向代理与小型部署中的反向代理采用了截然不同的管理方式,因此大型部署未受影响。值班工程师能够迅速将流量从小型部署迁移到大型部署。大型部署的设计足以轻松承受满负荷运行。不过,部分网络链路出现拥塞,因此需要网络工程师制定变通方案。为了减少对终端用户的影响,值班工程师将拥塞网络作为首要问题处理。
小型设备的关闭流程高效而顺利。从开始到结束,不到一小时就有大量此类设备被成功关闭并安全擦除。
尽管退役自动化程序迅速破坏了小型部署的监控设置,值班工程师仍然及时恢复了这些监控。这有助于他们评估损失范围。
工程师们迅速遵循了事件响应流程。自本章所述第一起故障发生以来,这些流程已经日趋完善。公司内部以及各团队之间的沟通与协作堪称出色,充分体现了事件管理计划和培训的有效性。各团队成员都积极参与,并充分发挥了各自的经验。
我们学到了什么
根本原因在于,退役自动化服务器没有对其发送的命令进行适当的完整性检查。当服务器在第一次退役失败后再次运行时,它收到了一个关于机架的空响应。服务器没有过滤该响应,而是将空过滤条件传递给机器数据库,相当于指示机器数据库对所有相关机器执行磁盘擦除。没错,有时“空”确实意味着“全部”。机器数据库执行了这一操作,于是退役工作流开始以最快速度处理所有机器。
机器重装速度缓慢且不稳定。这主要是因为远程位置使用了网络服务质量(QoS)最低的简单文件传输协议(TFTP)。系统中每台机器的 BIOS 对这些故障的处理能力都很差。根据所使用的网卡不同,BIOS 要么停止运行,要么陷入持续重启循环。每次重启都无法成功传输启动文件,进一步加重了安装程序的负担。最终,值班工程师通过略微提高安装流量的优先级,并使用自动化程序重启所有卡住的机器,解决了这些重装问题。
机器重装基础设施也无法同时处理数千台机器的安装请求。部分原因是一个回归问题导致每台工作机器最多只能运行两个安装任务。此外,该回归问题还使用了不合适的 QoS 设置来传输文件,并且超时时间配置不当。它还会强制重装内核,即便某些机器的内核版本仍然正确,且磁盘尚未被擦除。为解决这一问题,值班工程师将问题上报给负责该基础设施的相关人员,后者迅速调整了基础设施,使其能够承受这种异常负载。
所有问题都有解决办法
时间和经验表明,系统不仅会崩溃,而且常常会以出人意料的方式崩溃。海外某些大型技术团队学到的一条重要经验是:解决办法总是存在的,哪怕它一开始并不明显,尤其是对那个刚刚被呼叫器叫醒的人来说更是如此。如果你想不出解决办法,就扩大搜索范围。让更多团队成员参与进来,请求帮助,尽一切可能寻找答案,但一定要迅速行动。首要任务是尽快解决眼前的问题。很多时候,掌握最多信息的人,正是触发事件的那个人。一定要充分利用这个人所掌握的信息。
还有一点非常重要:一旦紧急情况得到控制,请务必留出时间进行清理、撰写事件报告,以及……
从历史中吸取教训,不要重蹈覆辙
保留故障历史记录
学习的最佳方式之一,就是记录过去发生的问题。所谓历史,就是从所有人的错误中学习。记录时要全面、诚实,最重要的是要敢于提出尖锐问题。寻找能够防止同类故障再次发生的具体措施,不仅要考虑战术层面的修补,也要考虑战略层面的改进。通过发布和整理事后复盘报告,确保公司里的每个人都能了解你们学到了什么。
要督促自己和他人落实事后复盘报告中列出的具体行动项。这样做可以避免未来再次发生与已记录故障几乎相同、触发因素也几乎相同的问题。对于跨部门协作较多的团队,也可以借助 Worktile 这类通用项目协作系统,将复盘后的任务、文档、日程、审批和责任人统一管理,确保行动项真正被跟进和闭环。当你们已经可靠地从过往故障中吸取经验后,就可以进一步思考如何预防未来的故障。
提出那些重大甚至看似不太可能的问题:如果……会怎样?
没有什么比现实更能检验系统。问自己一些开放式的大问题:如果大楼停电了怎么办?如果网络设备机架被水淹了怎么办?如果主数据中心突然断电了怎么办?如果有人入侵了你的网络服务器怎么办?你会怎么做?你会联系谁?谁来承担费用?你是否有应对计划?你知道该如何应对吗?你知道系统会如何反应吗?如果现在就发生这种情况,你能把影响降到最低吗?坐在你旁边的人能做到吗?
鼓励主动测试
谈到故障,理论和现实往往截然不同。除非系统真的发生过故障,否则你无法真正了解该系统、它所依赖的系统,以及用户会如何反应。不要依赖假设,也不要依赖那些无法测试或尚未测试过的东西。你更希望故障发生在什么时候?是周六凌晨两点、公司大部分员工还在外地参加团队建设活动的时候?还是你最优秀、最聪明的团队成员都在现场,监控着他们前几周精心审查过的测试时?
结论:用应急响应机制持续提升系统可靠性
本章回顾了三起系统部分故障案例。尽管这三起紧急情况的触发原因各不相同——一起由主动测试引发,一起由配置变更引发,另一起由系统退役自动化引发——但它们的应对方式有许多共同点。响应人员没有惊慌失措,而是在必要时寻求更多人员协助。他们认真研究并吸取了以往故障中的经验教训,并据此改进系统,使其能够更好地应对此类故障。每当出现新的故障模式,响应人员都会将其记录下来。这些后续记录有助于其他团队更好地排查问题,并强化系统,以应对类似故障。响应人员还会主动测试系统,确保变更能够解决根本问题,并在其他薄弱环节演变成实际故障之前发现它们。
随着系统不断演进,这一循环也会不断持续。每一次故障或测试,都会推动流程和系统逐步改进。虽然本章的案例研究来自海外大型技术组织,但这种应急响应方法经过时间检验后,可以应用于任何规模的组织。
文章包含AI辅助创作:应急响应指南:系统故障、事件响应与事后复盘实践,发布者:cai,转载请注明出处:https://worktile.com/kb/p/3980885
微信扫一扫
支付宝扫一扫