阅读本文你将收获:
1、从研发效能的视角谈“故障复盘”
2、系统故障复盘的具体步骤与最佳实践
3、故障复盘的常见误区与应对策略
作者简介
茹炳晟,腾讯Tech Lead,腾讯研究院特约研究员,业界知名实战派研发效能和软件质量双领域专家。中国计算机学会CCF TF研发效能SIG主席,腾讯云、阿里云、华为云最具价值专家,年度 IT 图书最具影响力作者,畅销书《测试工程师全栈技术进阶与实践》、《软件研发效能提升之美》、《软件研发效能提升实践》和《高效自动化测试平台:设计与开发实战》作者,极客时间《软件测试 52 讲—从小工到专家的实战心法》作者。
本文来源:转载茹炳晟老师的公众号内容:《从研发效能的视角谈“故障复盘”》;
从研发效能的视角谈“故障复盘”
首先我们必须接受这样一个事实:系统正常,只是该系统无数异常情况下的一种特例。听起来有点悲观,但这就是现实。故障会是系统,尤其是复杂系统的常态,业务体量越大,系统架构越复杂,潜在的问题和故障就越多,这个是必然的。
复杂系统的高网络密度和强耦合性是造成这一必然性的罪魁祸首。复杂系统都是非线性的网状结构,而且网络密度随着系统本质复杂性的提升而增大,系统的各个部分会以隐藏的、意想不到的方式相互作用,故障的来源非常隐蔽,故障的传播路径更是难以琢磨,我们既不可能预测出所有可能会出错的地方,也无法准确预测出系统中某处小故障可能导致什么后果,更不可能遍历所有可能的路径。系统各个部分之间的强耦合性会使问题进一步恶化,故障会在系统中以意想不到的路径快速蔓延并不断放大,最终造成严重后果。
图:复杂系统的高网络密度和强耦合性
由此可见,目前的技术想要对故障进行有效的事前预测还是很困难的,因为故障的本质是复杂系统运行到临界状态之后的叠加结果。
所以面对故障的正确姿势应该是,事前尽可能控制,但是由于事前无法完全预测和消除,所以系统设计必须考虑“为失效而设计(Design for Failure)”,并在此基础上切实推行有效的复盘机制,才能最终提升复杂系统的鲁棒性。
故障是表象,背后技术管理上的问题才是根因
如果我们把主要关注点都放在故障本身上面,就会忽略故障背后更深层次的东西。海恩法则告诉我们,每一起严重事故的背后,必然有29次轻微事故和300起未遂先兆以及1000起事故隐患。那问题是这么多的先兆为什么都会被忽略,没有引起团队的重视呢?
我认为根本原因是技术管理本身出了问题,技术管理上的问题在积累到一定量之后,会通过故障的形式爆发出来,而故障本身只是表面现象。
任何一个故障的具体原因都可以归结到某些具体的技术点上,但是技术管理不应该只是“头痛医头脚痛医脚”的角色,而应该是站在更高的全局视角看问题。比如你应该这样来思考问题:
- 故障无法快速定位是不是系统的可观测性设计出了问题
- 故障发现不及时是不是监控覆盖度不够
- 容量故障是不是限流、降级、熔断等保障手段缺失
- 局部小问题的牵一发而动全身是不是故障隔离没有考虑
- 故障预案在遇到问题时失效,是不是故障预案停留在纸上谈兵,没有实际演练
- 某些流程经常出错,是不是人工操作步骤太多,或者流程本身需要改善
- 生产环境的人因故障是不是缺乏对生产环境的敬畏之心
- ...
我们要的不仅是单点问题的解决,更需要的是系统化问题的解决,这才是治标又治本的正确方法,这也是技术管理应该发挥的价值。
当出问题的时候,技术管理者要先自我反省看问题出在哪儿,不能一味的揪着具体问题和员工不放,具体问题可能只是表面现象,而员工更多的是整个体系中的执行者,做得不到位,一定是体系设计上还存在不完善的地方或漏洞。这个点上,技术管理者应该重点反思才对。
最后,再想说一点,如果不发生故障,可能很多技术管理者压根都没有关注过员工在做的事情,比如设计是否合理,测试是否充分,发布过程是否规范,是否需要支持等等,这本身也是技术管理者的失责,为潜在的故障留下了滋生的土壤。
可以包容失败,但是不允许犯错
这个点是我老板教我的,失败可以接受,但是犯错零容忍。对于一些本身就极具挑战性的技术或解决方案,由于团队,甚至是业界可能都没有可供直接借鉴的经验,结果在落地的过程中踩到了一些坑而没能成功,这种失败是可以接受的。愿意承担这样责任的员工一般都是积极性和责任心很强的人,事情没做好,他们内心都不知道反思了多少遍了,作为管理者应该要鼓励和支持他,这样更能达到“知耻而后勇”的激励效果。如果他的做事积极性被打击了,变得畏首畏尾起来,那么他的创新能力就很难发挥,更不用说技术突破了。
所以,团队内部一定要营造出鼓励做事向前冲的氛围,而不是制造担心失败被处罚的恐慌氛围。而犯错往往是指那些已经明确知道不能做的事情依然在做,同样的或者类似的错误不断重复发生,这就无法被接受,必须通过处罚等手段来提升责任心和敬畏意识。例如,在工作中需要遵守所谓的“成人法则”,员工不是“巨婴”,犯过的错误应该通过各种手段防止再犯,比如遵守规范,流程,增加检查清单等研发纪律。总而言之,我们最终的目的是鼓励做事,而不是处罚失败。
个体的失误反而是一件好事
不要惧怕个体失误,从团队的角度来看,面对风险,个体的失误反而是一件好事,因为个体的失误为整个团队提供了可以借鉴的经验和教训,团队吸收这个经验教训的过程中,逐渐培养起了整个团队的反脆弱性。反脆弱性的存在,给系统向更完善的阶段进化提供了一种可能。在这种思考模型下,不“浪费(忽视)”任何一个失误反而变得更为重要。
故障复盘的步骤与最佳实践
故障复盘的实施步骤通常包含以下步骤:
- 理解故障的技术背景
- 梳理故障的整体情况
- 识别故障的直接/间接影响
- 梳理故障时间线
- 识别和分析故障触发条件和关键环节
- 层层下钻故障根因
- 分析解决方案
- 归纳推演出后续的跟进措施
- 总结经验教训
上述步骤相信大家都已经非常熟悉,而且在不同团队中的实践也是大同小异,所以整个故障复盘的过程我就不展开了。这里只谈四个我认为比较关键的点。
故障根因分析
理解一个系统如何运作并不能使你成为专家,只有当系统不工作的时候能够快速定位根因并及时修复才能使你成为专家。而且故障根因分析要层层递进,不能停留于表面的浅层原因。
举个丰田的例子,工厂车间地上漏了一大片油,常规的处理方式就是先清理地上的油,然后检查机器哪个部位漏油,换掉有问题的零件就好了。但是按照丰田的思路,会引导工程师继续追问:为什么地上会有油?因为机器漏油了。为什么机器会漏油?因为一个零件老化,磨损严重,导致漏油。为什么零件会磨损严重?因为质量不好。为什么要用质量不好的零件?因为采购成本低。为什么要控制采购成本?因为节省短期成本,是采购部门的绩效考核标准。你看,问了一系列的“为什么”,漏油的根本原因才找到了。
所以对漏油事件的根本解决方案,其实是改变对采购部门的绩效考核标准,除了关注成本还要加强质量因素的比重,这样才能防止以后发生类似问题。这种连续问“为什么”的能力是一种理性思考的推理能力,不仅要求你有全面系统的技术背景知识(俗话叫“懂行”),还要你有努力求知不懈怠的态度(俗话叫“用心”)。
这种理性思考的推理能力可以借助于一些工具或者思考模型来实现,比如鱼骨图和帕累托方法等。当你花费比别人更多花时间去思考,最终你就可以拥有几倍于别人的成功。
改进措施的闭环
故障复盘的时候讨论热火朝天,看似总结出来了很多改进项,但最终都停留在纸面上,没有落地到具体的行动计划当中。请牢记:只有行动才能真正带来改变,所以不论你的故障复盘做得多么深刻,只有把识别出的改进措施付诸行动才能算是有效的复盘。因此。对于每次复盘后得到的改进措施必须做到闭环管理,有始有终,方能进步。常用的闭环管理工具有PDCA循环和RACI矩阵等。
演习的必要性
之前看了部电影《萨利机长》,讲的是全美航空1549航班飞机起飞两分钟后遭到飞鸟攻击,两架发动机全部熄火后,萨利机长成功在哈德逊河上迫降,155人全数生还的真实故事。我就特别感慨,为什么有些人遇见紧急情况还能淡定从容,有些人却很容易慌了手脚呢?原因很可能不是在性格上,而是在见识和准备程度上。萨利机长的故事让我感受到,处事不慌是可以刻意练习的,同样,故障的处置也同样需要刻意练习,这样这种面对故障我们才能做到从容不迫。目前主流的刻意练习方法是事前演练和混沌工程,混沌工程在实施过程中还会和压力测试的场景相结合,这样的演习会更具真实性。
复盘过程本身的质量
故障复盘是相关干系人共同参与的过程,所有干系人都应对复盘过程和结果质量负责,过程质量决定产出质量,而产出质量又反映过程质量。为了最大化复盘的产出和价值,需要建立一套标准、可量化的复盘有效性保障方法,这套方法会对复盘过程进行监督、纠正和持续改进,如实透明的展示复盘过程中各个流转状态的处理时长、数据准确度、调查轮次等评判指标数据,通过多维度的数据对复盘过程的质量进行评定,给到团队优秀的复盘案例,促进团队成长。
故障复盘的常见误区与应对策略
图:故障复盘的常见误区与应对策略
以唯一根因为导向来复盘
雪崩的时候没有一片雪花是无辜的。如果我们还是以唯一根因为导向来盯着做复盘,就很容易陷入到无限的纠结中去,原因是根因往往不是一个,而是一个系统。为了便于你的理解,这里举个例子:由于服务器宕机造成数据库MySQL服务挂了,进而影响上层服务,整个过程花了20分钟才修复,最终被定级成故障。在这个例子中,你觉得故障的根因是什么?有人说服务器是根因,有人说MySQL是根因,有人说上层服务不支持功能降级,所以架构设计是根因。这么一个简单直白的问题,不同的人就会有不同的理解。
如果我们把问题再复杂化一下,比如MySQL设计了主从切换,但是宕机时没切换成功,而且当时DBA还联系不上,后来联系上之后由于VPN链接不稳定又耽误了处理,那么这种情况下,你觉得故障的根因又怎么算?有人说是DBA不在岗是根因,有人说是VPN的稳定性是根因,有人说主从切换失败是根因。显然每个都像是根因,而每个又都不是根因。所以我们应该系统化地看待根因,同时把找根因的目标放在改进上去,就能走出迷局,试看下面的分析:
- VPN连接问题,和运营商网络有关,所以需要给运维人员配备两个以上运营商的上网卡。
- 值班机制问题,关键运维岗位需要有备份机制,必须确保至少有一人可以快速响应。
- MySQL主从切换不生效为什么一直没有发现,原因是缺乏定期的切换演练。
- 业务没做降级保护,所以要添加鲁棒性设计,并且需要对降级保护进行混沌工程试验。
试想一下,上面只要有其中一个环节能够做到位,都会大大降低故障的影响度,哪个是根因其实已经没那么重要了。
将故障和处罚直接挂钩
故障的事后处理一定要分清楚定责和处罚的关系:定责不等于处罚。如果这个关系没能处理好,无尽的甩锅推诿就开始了。故障需要与定责挂钩,但是定责和处罚不是强绑定关系。定责的原则是对事不对人,这件事情一定要有人承担责任,这里承担责任的意思是说负责后续改进措施的执行与落地,其目的是改进。而处罚的目的是避免主观意识薄弱造成的低级且重复的错误,进而有效降低再犯的概率。同时处罚也能提升人的敬畏意识,激活其责任心,巩固其基本的职业素养和操守。
将处罚和绩效强绑定
很多人会把“处罚我”和“否定我”画上等号,此时员工的注意力就会从“怎么改进”这个点上转移到“为什么要处罚我”这个点上来了,在这种消极情绪和氛围中再去沟通什么改进措施,效果就大打折扣了。
我的经验,处罚如果和绩效强绑定,团队就陷入这种质疑、挑战以致最终相互不信任的局面。所以这里建议采用曲线救国的方式,首先取消处罚与绩效的直接挂钩,对于出现的故障有专门的系统记录,然后把故障按季度或者半年度来统计,通过统计周期内的综合情况进行判断,如果员工整体的表现都是不错的,甚至是突出的,说明员工已经改正或者故障确实是偶尔的失误导致,这种情况下员工仍然会有好的绩效。但是如果是频繁失误、频繁出问题,这种情况下也就没什么特别好说的了,用数据说话就好了。
把故障归因于外部客观原因
开会迟到,客观原因是堵车,主观原因是没有充分预估交通状况,其实早点出发就不会堵车,或者即使堵车也不会迟到,为什么我们要这么区分呢?任何一个问题都有主观原因和客观原因,但是我们犯错的时候会下意识的忽略主观原因,推卸自己的责任,而去强调客观原因。在做故障复盘的时候,这是我们要尽量避免的。当发生故障时,我们不应该把问题归因于不受我们控制的外部客观原因,而是应该研究我们到底没做什么,因为这就意味着面对故障我们需要占据主动,面向失败来做设计。这样的认知升级是非常重要。
故障缓解措施依赖于管理手段而非技术
技术手段暂时无法满足的,可以靠管理手段来辅助,但是这只能作为辅助手段,一定不能是常态,必须尽快将这些人为动作转化到技术平台中去,靠技术和工具来系统性地解决问题。否则效果很难被量化评估,同时还增加了管理成本。举个简单的例子,接口变更,变更方要通知到对应的依赖方,如果未通知,变更方承担责任,如果已通知,依赖方未及时做出调整,依赖方承担责任,通知形式以公告和邮件为准,这就是典型的靠管理手段在解决问题,如果使用技术手段,我们就应该建立接口设计的契约管理系统,所有的契约变更都有系统来完成通知和同步,这样就不会再有契约信息不同步的问题了。