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