今天来给大家分享一下我分别作为一线研发同学和一线Leader的两个角色,亲身经历了哪些线上故障、我是怎么样应对故障以及我对故障的思考是什么。

故障定义

先上一个标准的定义,互联网公司的故障定义如下:

互联网公司故障一般指在运营过程中出现的技术或服务异常,导致网站或应用程序无法正常运行或提供服务的问题。这些故障可能来自于硬件或软件故障、网络中断、安全漏洞、数据丢失、人为操作失误等因素。一旦出现故障,将会对公司的业务和用户体验产生严重的影响。因此,互联网公司通常会采取多种手段来预防故障的发生,并及时解决已经发生的故障。


通俗点来说。故障就是造成了线上客户可用性问题或者给客户带来资金损失。其中资损是更为严重的一种故障,这个我们后面再详细细说。一般来说公司对于较大影响的故障会有明确的内部定级用来标识故障等级,方便内部故障追责和方便给客户赔偿。比如腾讯的故障定级有如下标准:

一位阿里Leader故障方法论_链路

一般来说,大流量系统往往可以直接从系统监控里判断故障等级,而对于一下长尾的业务由于客户访问量比较小、成功率抖动本身也比较大,不好直接用成功率来衡量故障,诸如面对客户的公司比如飞书、钉钉,一般会采用客户投诉的数量来作为定级的一个准则。

我的第一个资损故障

实际上从一个相同故障里面来看的话,可能有不同的视角。首先说说我的经历,我大概去了淘宝一年左右的时间就亲手触发了一个定级故障。那个时候是作为毕业的应届生,跟着师兄一起做一些比较大的中后台项目,由于一个老的商品配置后台已经年久失修,我们做的项目就是对老的商品配置后台的翻新。系统主要的功能是配置商品的详情属性以及规格的详情属性,还有价格优惠等等。

其实从现在看来的话,这个项目是一个WEB的后台portal,并且只是给我们内部的员工配置商品使用的,相对来说技术含量并不是很高,但是会比较有非常多的前后端工作量,我们相当于是全栈既要写前端页面,也要写后台的逻辑。

在这个门户系统上线之后,大概三个月,我又被指派到支持一个产品同学配置一个淘宝旺铺的商品的上线,这个商商品我记得是名称叫淘宝旺铺,主要是给淘宝卖家购买后用于装修店铺的。产品要负责给这个商品配置一个限时优惠,这个优惠的话就是首次购买打9折。当时是没有测试人员,产品在配置完商品以后,并且那个时候由于商品还是要付费的,所以产品申请一张优惠券,使用优惠券下单以后产品粗略看了一眼就反馈没问题了。我作为这个优惠系统能力的负责人,也没有仔细检查订单,也就直接给与通过了。

这个促销活动上线定的时间是凌晨,我们给优惠配置了自动生效时间,到了指定时间后就生效,商品在客户首次购买的时候就会打9折。

到了那个上线的凌晨,我记得我刚刚准备睡觉的时候,突然接到了一个同事给我打来的电话,是我的一个运营同事,她说她在线上巡查商品的时候,发现了这个商品的价格是为0的。并且可以直接下单购买。那个时候我就有点慌了,因为一个1000块钱一年的直接变成了0元,并且可能会有大量的客户下单薅羊毛,这里面产生的损失要了亲命了,而且如果放任它扩大到第二天,甚至所有的淘宝客户都会来买这个免费的商品。这个资损金额可能是天价。

由于我们的运营还是非常负责的,在凌晨上线之后还做了一下巡检,在第十分钟的时候就发现了这个问题,运营紧急的帮商品给下架了并电话给我们。我记得我当天晚上知道这个消息之后和师兄粗略的统计了一下,约大概有几十万万的资损金额。

那天晚上我的情绪是很焦虑和不安的,我因此已经完全无法再睡觉了,一直拖到了凌晨3点多钟才开始睡觉,准备第二天的排查问题和接受故障处罚。

当然这个故事里面也告诉了我一个非常深刻的一个商业道理,也就是当有一个免费或者存在漏洞又可以被薅羊毛的时候,所有人都会不顾一切的往上冲的。我们这个活动上线的时间是0点,而理论上并没有这么多的客户会在0点的时候登录到系统购物,而事实上他们发现了这个漏洞的情况之后,就有很多人帮这个漏洞的链接转到了各个群里以及他的一些朋友。就导致了这个自损的金额快速的放大,我当时庆幸是十分钟以后就被巡查发现了,如果一旦这个故障没有人发现的时候,让第二天上午自然上班的时候才发现,我想可能这个结果是非常恐怖的,有可能是我无法承担,甚至是会给集团造成损失的,我现在想想还是后怕。

所以那时候一方面我还是特别的羞愧苦恼以及内心特别的焦虑不安的同时,也比较庆幸这个运营真的救了我一命。

事后我就开始做了多轮的复盘,对于事故原因特别神奇的是,刚好这个优惠系统是我自己做的。然后我在协助配置优惠的时候就命中了这个优惠系统的bug会导致总价变成了零,最终导致了商品变成了免费并且所有人都可以免费下单。

所以我觉得很多时候自己种的因才会导致自己种的果,自己当初在商品配置系统上线的时候没有做过非常细致的测试,才导致了后面的一个粗心,把问题直接放大。

所以我们在实际的线上生产系统中,很多的故障都不是由于一个单一的问题引起的,而往往是由于一连串的链路上面都有问题,叠加起来才放大了故障。这让我想到了屡次的空难原因,有著名的空难原因法则:

空难原因法则指的是“瑞士奶酪模型”(Swiss Cheese Model),也称为“多层次防御模型”(Multiple Layers of Defense Model)。该模型描述了空难事故通常由多个因素和故障组成的复杂系统,这些因素和故障相互作用,导致事故的发生。该模型主要由四个层次组成,包括人员、机械、环境和组织。每个层次都有自己的防御措施,但是这些措施都有缺陷,并且有可能发生故障。当多个缺陷和故障同时发生时,它们的影响会相互叠加,并最终导致事故的发生。

因此,空难原因法则强调了空难事故通常是由多个因素和故障组成的,而不是单一原因所导致的。飞行员、机械设备、环境因素和组织管理等各方面的因素都有可能对空难事故产生影响。因此,为了避免空难事故的发生,需要在每个层次上采取多层次的防御措施,以确保安全。


这个故障最终定级的是一个比较小的P4故障,并且我们通过订正的手段追回了损失。但这个故障对我的影响其实非常的巨大,也让我对线上的任何操作开始有了非常强大的敬畏之心。在我心里,虽然是软件系统,但实际上和车间里面的工程作业已经没有任何区别,在车间里面可能由于你的不慎,会导致工人或者你自己丧失了生命。而在软件系统里面也是一样,由于你的不慎会导致客户公司或者合作伙伴导致巨大的损失。而且由于线下的生产过程中受到物理方面的限制影响面是可控的,但是我们到了互联网上,由于互联网的规模和海量的用户可能出现的故障导致的损失可能是数万,数百万甚至是数亿用户计的。

在这故障里面我学到了非常深刻的一课,就是真正要敬畏线上,日常的故障分享是来自于生产系统里面每一次血淋淋的案例。所以我们很多刚刚毕业的同学,我们跟他灌输了再多的敬畏系统,精卫线上客户的案例,他们可能都没有体感,当他们自己碰到一次这样非常痛苦和深刻教训的时候,他们就会形成一种非常沉浸的认知。

所以就为什么我们要在培训的时候要大量的去分享一些深刻的实际故障案例,一些安全案例能够让同学们保持一颗敬畏之心,对自己写的代码、发布线上流程、线上测试验证会有一个更加谨慎的态度。


一个跨越边界的故障

这里再说一下第二个案例,第二个案例是比较特殊的,它不是一个由于线上各种变更或者配置引起的故障,而是我的同部门的技术同学错误的操作,导致了线上大量的客户投诉。

事情缘由是这样的,我们部门负责的是整个商品的配置系统,那么有大量的ISV(卖家)过来上架商品到我们的平台,客户可以下单购买。有一天有一个服务商要求我们这边的业务运营同学上架一个商品,但是由于特别情特殊,没有能找到这位运营的同学,而时间刚好又恰巧在周末,所以ISV刚好就通过我们的一些合作群找到了这位技术同学。

这位技术同学本着向前一步的方式在寻找了这位业务同学无果之后,就替这位业务同学做了支持的工作。把商品配置并在当天发布上线了。然而在我们下一周一上班的时候,就接到了某一个外部客户的大量投诉,他投诉说大量的客户都打电话到了他的这个企业里面,我们开始觉得会很奇怪,理论上客户打电话咨询的应该是这个服务商,怎么会咨询到某一个正常的其他公司里面呢?

后面我们一查发现我们这位技术同学在帮这位ISV配置联系电话的时候,由于配置的号码有误,被系统截短了一位,导致变成了另外一个公司的电话号码。所以在商品发布上线以后,大量的客户咨询全部打到了这个电话里面,而这个电话又是这个公司的付费电话,所以消耗了公司的大量资源,于是公司的负责人勃然大怒,投诉到了我们的公司。

针对这个故障我的当时的主管非常的生气,并且搞了大概三到四个内部团队循环复盘问题。我们的主管认为这是一个特别越界的行为,一个技术同学去越界做了本来该业务同学操作的事情。

这个案例所以告诫我们要在向前一步和把握自己的本质工作里面要做一个非常好的划分。在这个案例里面,我其实也学到了很多东西,我们所有公司的文化教导我们是要向前一步的去主动补位,解决客户的问题,但是我们也要清晰知道我们的界限在哪里。

所以这里面我觉得作为一个技术的同学,本职工作一定是把自己代码研发相关的工作做好,在此之外也要积极的去补位自己的上下游角色,但这个补位是相关角色缺席的情况下主动的去补上这个缺,并且补上这个缺是有条件的,是做一些周知,而不是替代性的决策工作。所以本质上补位是帮助整个产品或者客户变得更好,同时又不能逾越他原来的界限。

举一个简单的例子,当我们客户发现了投诉的时候,又没有办法找到相关的负责人,那么作为技术的接口人,可以作为产品和系统的一种客服的接口人,把问题带回来,想办法找到负责的业务同学,并催促业务同学来帮助客户解决问题。而绝不对不是替代了业务同学擅自做决策,以自己的方式帮客户解决问题。因为一个公司里面的业务非常复杂,规则非常复杂,权限也非常复杂,技术同学往往没办法能够周全的考虑到业务权限和业务判断问题。所以技术同学是不能够直接做业务操作的,而对于向前一步里面是应该更多地走近客户,走到不同的角色,站在他们的角度去考虑问题,去思考问题,但并不是替代他们去做决策。

所以当时这个同学内心确实是很受打击的,可能后续再有跟他技术不直接相关的事情,他都会再三思考先,积极性肯定是大不如前,但我相信做事本来就是这样的,我们中国有一句古话叫过犹不及,放在所有地方都非常的有用。这个案例也告诫了我们在做事情的时候一定要取得平衡。有些价值导向是明确的,但是怎么样做还是需要智慧的,更需要有原则的。

团队协作故障案例

再说一下第三个案例,第三个案例是我们团队最近刚刚发生的一个案例。我们依赖的一个中间件技术系统有一个新功能全量的发布。但是这个系统全量的发布以后就导致了我们这边的某一个客户一直会超时。这个客户是一个平台客户,导致客户里面有很多的用户都发生了异常情况。在我们接到第一例投诉的时候,我们就联系了这个中间的同学,但中间件的同学没有正确的评估出来风险是由他们引起的,并没有第一时间回滚系统,所以我团队的同学就自行评估(评估的方式不正确)可以通过上层订正止血,于是就开始走了订正流程。

由于订正方案不是最佳的,一通订正以后,反而由于对系统不熟悉,订正错了把原来少部分用户受影响订成了全部用户受影响。并且由于不熟悉系统,超过了一天的时间才把问题全部止住。从结果上来看,原来可能只有几个用户在投诉,订正出错后放大以后成了几百个个用户都受到非常大的影响。

并且在这个过程中,我们处理问题的一线同学也没有把整个故障的影响面上升到主管层面,对方的中间件同学也没有感知到这个问题的严重性。所以缺乏团队间应急流程和止血方案评估失误综合而来,导致形成了这个P4故障。

刚开始的时候,中间件的主管认为故障主责应该定成我这边,因为我们团队这边放大了故障。但我认为是由于中间件同学的不负责任,评估不到系统发布的风险,同时没有评估到及时回滚,而且期间多次联系不上,才导致了故障的出现,因此最后经过一阵争议,最终把主要责任定在了中间件,次责定在了我这边的团队。

第三个故事对我来说也非常有感知力,虽然我已经成为了主管,不再直接处理具体故障的排查和止血问题。由于到了技术主管,一般也很少写代码,所以也不会直接引起代码。但是作为技术主管则需要对整体的稳定性负了更高维度的责任,所以我在这里面就在反思从一个研发同学的视角怎么样看待故障升级到了怎么样作为一个团队管理者的角度来看待故障。


我对于故障的思考

我认为对于客户的角度,其实不管是一线开发者还是主管,甚至是总监,甚至是公司的CTO对于整个故障的态度应该是一致的,也是坚决的。那就是敬畏线上,敬畏客户,给客户带来哪怕一分钱的损失,一分钟的不可用,都要持愧疚自省的态度。因为我们提供的产品,我们是要保证产品的可用性,实在做不到100%的,也要有一个事前清晰的SLA标准。我就听到某总裁讲过,由于云服务的故障,导致某个传统大公司的核心服务不可用,为此传统公司的CTO都引咎辞职。

但是回到整个团队的主管视角,我觉得和一线同学观感的问题应该是不一样的。

  • 首先在团队里面要树立起一个正确的处理故障的机制和意识。这个非常重要,因为作为一个单点的研发同学来看的话,会用孤立的视角来看待问题,比如说团队故障是不是我引起的,如果不是我引起的是不是我就可以忽略了?比如说这个故障是外部调用异常,我应该找哪个同具体同学去处理?当自己评估的不准确,或者没办法及时联系到对方的负责人,那么会导致故障处理滞后?当系统故障要放大的时候,对于系统不熟悉,又非常想解决客户的问题,匆忙操作止血方案反而引起二次故障?所以到了主管这个层面上面就不仅仅是一个单点问题,而是一个全局性的问题,所以要依赖团队主管建立一个非常完备的故障应急制度。
  • 比如说在发生故障以后,第一处理人是谁?
  • 在故障发生以后,怎么样判断是否是日常的常规性问题?还是有可能进一步扩大的风险?
  • 如何快速成立故障应急小组?故障升级到什么样的维度?
  • 故障的第一操作人是谁?有没有止血的方案?如果没有止血的方案,怎么样才能够快速形成一个?有并且这个方案的副作用是什么,能否确认该方案是生效的?如果有副作用它的影响面是什么?
  • 有多个止血方案的话,用哪个止血方案最快?
  • 该止血方案有副作用,该找谁来确认这个决策?
  • 没有止血方案的话,采用什么临时措施来尽可能的降低影响面?限流?限流多少?对哪些客户限流?

这些都依赖于整个团队主管在整个团队内长期的宣导。我们回归普通同学的心理,很多一线同学在写代码的时候,往往可能由于一些非常细小的问题,没有注意到自己代码产生的副作用,当然发布上线形成用户投诉的时候往往非常焦急,一方面又想快速的把问题给止住,另外一方面又怕问题放大,导致主管或者其他团队同学对自己形成一个不良的口碑,所以都希望自己快速能把问题解决。

这是一个很自然的心理现象,但往往由于团队一线写代码的同学层级不够高,处理故障的经验不多,可能会导致误判,从而进一步把原来可能很小的问题放大到成了故障,甚至放大成了整个公司层面的故障。所以就很有必要依赖于主管对于日常应急故障处理机制的一个宣导。

  • 第一,我们要坦率的告诉同学,承认出了问题是正常的,不会因为某一个问题就对同学万分苛责,而且写得代码越多,引起故障的概率就更大。一些小问题问题是允许出现的,这样才能让同学们愿意创新、试错和成长。
  • 第二,要形成一个正确的故障处理机制,当出现了问题的时候,同学们应该在第一时间里面有一个较为准确的判断,如果在判断不清楚的时候,要马上上升,成立应急小组,找到资深的同学一起来处理问题。
  • 第三,要在团队形成一种共识,如果当原来一个小的问题出现后,但是经过应急小组处理之后,对客户造成的影响变小,或者甚至是没有影响,应该对这位同学进行一个嘉奖。

我在团队形成应急故障的同时,主管更要宣导怎么样让同学能够处理好团队之间的协作,我们发现其实大部分的故障的扩大或者踢皮球往往是多跨多个团队,在协同处理故障的时候则权不清晰。或者相互沟通存在一定的障碍。所以就非常有必要去形成这种跨团队的故障的约定,系统边界的约定及责任人的约定。只有在这样才能够破除一线同学不好意思去找对方的leader的情况。


  • 其次作为一个团队的主管,要形成在团队里面的危机管理意识,一定要时刻宣导团队的同学们,要非常非常敬畏线上,敬畏客户的心理。要在团队内经常有技术方案review,预案,回滚等等,在系统设计的时候都就应该形成的一系列的方案。没有一个review的方案,没有预案、回滚策略、监控体系、未经测试的变更是不允许上线的。这一定要在团队内反复要求,直至成为同学们心理都接受的红线。

在应对故障里,预案是非常必要的。从经验上来看,不管实先代码写得有多好,不管测试有多周全,总会有一定的概率无法覆盖的全面。就算代码没有BUG、测试全面,也保不齐流量过大、网络抖动导致的系统性故障风险。而且在实际出现线上告警或者客户投诉不可用的时候,往往我们没有办法快速定位到问题,从而可能就在焦急中寻找方案。所以预案的作用就显得无比的大了。古话说,凡事预则立不预则废。只有事前针对每个核心的链路都有准备预案,才能在出现故障的时候能够快速执行预案,给客户降低影响,给自己排查和定位赢得宝贵的时间。

一些常见的预案有如下几种方式:

  • 接口限流,当明确发现系统负载变高,流量过大,系统要雪崩的时候,可以采用接口限流的预案,紧急削峰保护系统,避免问题扩大的全局不可用。
  • 缓存方案,我们很多大系统在高峰期流量是极高的,而保障系统稳定性一个


  • 还有就是要日常的监控、值班、演练和压测。
  • 监控

监控是处理系统故障的第一步。连稳定性监控都没有,等于整个系统就是个瞎子,不知道会不会出问题,也不知道什么时候出问题,除了问题之后也不知道原因。所以在系统设计的时候,有一个必选项就是稳定性监控。一般的业务功能至少要求具备调用总量、成功率、失败率、同比环比等监控大盘。另外还有必要的就是对于底层中间件和操作系统的监控,比如数据库的调用情况、内存的访问情况等等。只有一个综合的监控系统,才能保证第一时间感知到系统故障,研发同学可以及时介入处理,而不是等待客户上报。往往等客户上报的时候已经晚了,因此监控系统和良好的应急机制,可以“把故障扼杀在摇篮”。

这让我想到了扁鹊对于三兄弟医术的一个评价故事

一位阿里Leader故障方法论_压测_02

即对于故障来说,事前预防的效用远大于事后修补故障的成本。

  • 值班

我记得我最早去淘宝天猫的时候,是没有早值班的,到了钉钉之后一开始也没有早值班,但是故障频发于是在CTO的推行下就有了每天的早值班。至有了早值班后整体故障率就大幅度下降。相对淘宝天猫来说,大部分客户都是中午或者下午甚至是晚上才会访问,而这个时间点工程师几乎都上班了,所以线上出现第一例问题,工程师就很容易感知到。但是对于钉钉这样的软件,很多客户都是传统的制造业,他们严格按照早8晚6的时间上下班,所以依赖钉钉的打卡服务也有明显的早高峰和晚高峰的特点,因此安排早值班是非常必要的,可以方便工程师整体没有上班之前,有早值班的同学能够尽早的发现系统问题并上报。

  • 压测演练

日常的演练应该是梳理出来核心的链路,并对每一个链路都做过充分的演练,降级和预案的情况。在我上面那个故障里面就由于它是一个系统型的一个主链路,这个链路变化的非常少,所以我们团队把大部分的日常演练都放在了其他的系统上,而忽略了对这个链路的演练,进而导致了对于这种大客户的异常情况没有及时的降级的策略。一般的公司都有自研或者采用开源的压测和演练工具,可以按照月的维度进行压测,压测可以提前暴漏系统问题以便研发同学日常就投入瓶颈的治理。

github上有很多热门的压测工具,诸如Apache JMeter,基于Java开发的功能强大的负载测试工具,支持多种协议和测试类型,可扩展性强。


  • 最后是故障复盘。

作为研发的同学,我亲手触发了故障,作为团队的管理者,我经历了故障,因此我对于整个故障的经历是非常的丰富的,我其实非常明白那种引发了故障的心理上的那种不安的活动和焦虑感。有些时候我甚至认为在我不小心引发了故障之后,我是不是就应该直接跑路了?是不是主管对我的印象就会极为不好?但最终还是坚持了下来,我其实在回顾这一段历程来看的话,虽然当时可能阶段性因为不慎引起的故障,导致当时主管给了我很差的绩效,但对于我长期来说是一个非常大的帮助,也是我人生中里面应对故障,应对风险的一个宝贵的财富。这种对于故障的经历才真真切切的让我体会到如何去敬畏线上,如何写好代码,如何设计每一个系统都需要有降级和回滚的能力。


写在最后

谁都不愿意背故障,但是已经引起故障并不可怕,因为既然已经发生的事情无人能改变。更可怕的是没有从故障中成长。就像短视频“二舅”说过的,苦难不是财富,但是从苦难里面学到的经验和教训才是真正的财富。放在这里我觉得也同样适用,我们带来的故障并不是我们直接的财富,因为故障确实对客户,对公司都造成了不良的影响,但是从故障里面吸取到的教训和经验才是我们真正的财富,因为这些财富伴随我们成长,使我们能够更好的避免下一个故障,能够更好的为其他客户创造更大的价值。所以借助故障来复盘,是给自己团队和给自己个人一个良好成长的方式。

欢迎跟我交流,共同成长,我的公众号:ali老蒋。或访问网站:http://www.javaer.com.cn/