1. 这个项目为什么叫hindsight:复盘大会最缺的,是一面不带滤镜的后视镜
我在无数次事故复盘会之后,得出一个挺扎心的结论:只要由人来复盘,就逃不掉一种叫 hindsight bias 的认知偏差。说白了就是事后诸葛——事情已经出结果了,你拿着完整答案去反推当时的选择,然后觉得"当时怎么就那么蠢,明明看一眼就知道"。
但你真回到那个事故发生的深夜,值班同学面对的是几十条告警同时亮起,群里消息每秒钟刷新一屏,监控面板开一个红一个。他的每一个动作都在不确定里做出来的,而复盘会上所有人的每一句话都在确定性里说出来的。这两者之间的信息差,就是 hindsight 这个项目最想解决的问题。
我给项目起名 hindsight,并不是想强调"事后看问题看得清",反而是想警告自己和团队:后视镜会骗人。它只能帮你看到走过的路,却会让人误以为这条路一开始就该被看清楚。这个项目也不是什么高大上的平台,就是我在团队内部从零搭出来的一整套复盘机制:一份会议流程、一套文档模板、几个采集证据的小脚本、一堆用血泪换来的注意事项,外加一个让教训能反复被检索的复盘仓库。它的核心目标只有一个——让团队在事故后能诚实地回答"当时究竟发生了什么""为什么会做那个决策",然后把这些转化为系统级改进。
如果你正在做SRE、研发质量、技术管理,或者你已经烦透了"复盘会等于甩锅会"的现状,这篇内容里有很多可以直接抄走的东西。
1.1 一个词,两个方向:hindsight 到底是工具还是诅咒
先掰开"hindsight"这个词。它直译叫后见之明,但在事故复盘里有两种完全相反的用法。
积极方向是:把后见之明当成调查能力。我们已经知道火是哪里烧起来的,就沿着证据链往回走,找哪根电线是第一个断的。这是复盘该有的样子——有结果,不慌,回看是为了拆解因果。
消极方向是:把后见之明变成道德审判。用考完试的答案,去要求一个还在打仗的人立刻写满分卷。典型句式我几乎每次复盘都能听见:"当时为什么不先看配置文件?""日志里明明有异常,你怎么不点开?"这些话对阻止下次事故毫无帮助,只会让当事人在复盘时开启防御模式,下意识地美化自己的记忆。
所以我在项目启动时定的第一条规矩是:复盘室里所有的讨论必须指向系统、流程、工具和协作机制,而不是指向某个人"当时不够聪明"。这不是出于政治正确,单纯是效率问题。被审判的人会说谎、会说一半藏一半,只有知道这场会议不是针对他,你才能拿回完整的现场信息。
1.2 复盘失效的三个信号:结论先行、责任找人、行动项空转
我观察过很多团队的复盘会,失效模式几乎一模一样,翻来覆去就是三个信号。
第一个是结论先行。有人还没开始看时间线,就抛出"我觉得是配置问题"。接下来的会议就成了帮他完成论证的过程——所有人都在找支持这个预设结论的证据,其他线索一律视而不见。这种行为看似高效,实则把复盘变成了庭审,证据是提前挑好的半场证据。
第二个是责任找人。会议开到后半程,大家开始回忆"当时是谁拍板不打灰度""当时是谁没盯告警群"。找到"责任人"之后,行动项就变成了"某某下次注意"。一个系统性问题,最后落在一个人的自觉性上,这是复盘里最昂贵的偷懒。
第三个是行动项空转。会议结束前,记录员写出了万能清单:加强监控、加强沟通、加强意识。三条金句写完,所有人都觉得有交代了,但谁也不知道怎么验收。三个月后再翻出来,一条都没执行,也没有任何机制提醒你有东西没执行。
这三个信号就像三根刺:说明团队没有把"事实"和"解释"分开记录。hindsight 的整套设计,本质上就是在做这两件事的切割。
1.3 第一条纪律:把"当时知道的"和"事后知道的"分开
我用的复盘模板第一页永远是两栏:当时已知 / 事后已知。
当时已知,填的是告警标题、监控面板上的数值、日志里的报错、群里同事说的话、正在执行的操作。事后已知,填的是根因分析结论、代码 diff、配置变更记录、压测报告。
为什么要这么分?因为人的记忆是会被重写的。一个深夜亲历事故的工程师,到第二天开会时,已经完全把根因"融入"了自己的记忆,他真心觉得"早上我就怀疑是配置的问题"。但真相是,他是在看到根因之后才重构了这段记忆。这两栏一旦物理上分开,就是在跟大脑作对,逼着大家标清信息的时间点。
用大白话说就是:后视镜不能帮你预测弯道,它只负责帮你搞清楚刚才这个弯是怎么过的。
2. 六步复盘流程:从事故发生时到行动项关闭的完整链路
流程不是一个团队的负担,它是防止遗忘的护栏。我试验过很多套路之后,固定下来一套六步法。每走一步都有明确产出,不空谈、不绕圈,从事故发生的瞬间到行动项关闭的三个月后,全链路都有东西可查。
2.1 第一步:事故还没结束时,先冻结现场证据
很多团队的习惯是:服务恢复后,立刻口头总结。等真要写复盘报告时,监控面板已经刷过去、日志被轮转覆盖、当时的操作记录被后续变更淹没,只能靠几个人的"印象"来拼现场。而记忆,是全世界最不可靠的证据载体。
所以我定了一条很土但特别有效的规矩:事件发生后,立刻指定一个不参与救火的"记录员"。他的任务不是修系统,而是打开录屏软件,把告警通知、监控面板、变更单、聊天记录全部截图存档,同时在一个纯文本文件里,以分钟为单位记下现场每个关键动作。他可能一边记一边被催着"别截了赶紧来帮忙",但他必须扛住。
有一次线上事故,群里吵成一锅粥,我们最后恢复用了40分钟。第二天复盘时,全靠这个记录员留下的操作时间轴,把每个节点的真实顺序理清了。如果靠大家回忆,几个人讲出来的版本能差出三条线。冻结证据不等于停下救援,它只是给复盘留了一条活路。
2.2 第二步:先建时间线,再上讨论桌
复盘会一开场,我禁止任何人讲"我认为问题出在……"。必须先干一件事:把时间线投到大屏幕上。
时间线表格至少包含四列:时间、对象、动作、观察到的事实与证据来源。我随手写一个例子:
| 时间 | 对象 | 动作 | 观察到的事实 | 证据来源 |
|---|---|---|---|---|
| 10:02:14 | 缓存集群 | 突发错误率上升 | 缓存命中率从99%跌到87% | 监控面板截图 |
| 10:02:30 | 值班同学A | 查看告警群 | 群里连续出现P0告警,开始定位 | 聊天记录 |
| 10:04:11 | 值班同学A | 执行缓存重启 | 判断为缓存集群抖动 | 操作记录 |
| 10:07:05 | 配置中心 | 发现异常变更 | 黑白名单被批处理任务改写 | 审计日志 |
| 10:09:20 | 值班同学B | 回滚配置 | 错误率开始回落 | 发布系统记录 |
写时间线有一条硬规矩:只写证据带得动的事实,不写推测和形容词。把"感觉业务受损严重"改成"下单失败率从0.2%升到9%"。把"定位了很久"改成"10:04到10:07三次尝试定位,未果"。证据来源必须具体到可回查:监控面板名称、日志路径、工单号、截图编号。
时间线拉完,不需要主持人总结,每个人基本能看清楚哪一环断裂了、哪一环浪费时间了、哪个关键信号没有到达对应角色。这个时候再进入归因,大家是站在同一堆事实上看问题,而不是站在各自的记忆里吵架。
2.3 第三步:还原"决策时刻",而不是审判"决策人"
时间线记录了动作,但没有解释为什么。要补上这一环,我借鉴了航空事故调查里的决策模型,对时间线上的每一个关键决策问一套固定问题:
- 你当时看到了什么?
- 你当时认为正在发生什么?
- 你当时是基于哪些信息做了这个判断?
- 这些信息有没有缺失、矛盾、或被忽略?
- 如果重来一次,有没有一种系统机制,能让正确决策变成默认动作?
注意,最后一问是重点。我不问"你为什么做错",因为这种问法一出口就带攻击性,对方立刻开始防御,回答的质量直线下降。我问的是"当时看到了什么",对方的回答往往是:"我看到缓存命中率在掉,操作手册第一步就是重启缓存。"好,那问题就清楚了——问题不在他身上,在于手册没有告诉他什么条件下应该先去查配置变更。
这样还原出来的"决策时刻",每一个都对应着一个系统缺口。复盘的全部价值,就是把这些缺口找出来补上。
2.4 第四步:五问挖根因,但要给5Why加上边界
5Why是很便宜好用的工具,但在实战里被大量用坏。用坏的典型画面是:主持人连环发问"为什么、为什么、为什么",团队成员像被审讯,越答越紧张,最后跳到一个"因为大家没有加强意识"的坑里,全员点头,会议结束。
我给5Why加了三条边界,效果立刻不一样:
第一条,每一层的回答都必须有证据托底,不能只靠个人推测。比如你说"因为密钥没通知到位",那就得拿出轮换流程记录、通知邮件、服务配置列表来印证。
第二条,一旦某一层回答指向"某个人不够仔细/不够努力",立刻踩刹车,把问题重新锚定到系统。比如"为什么写错了正则",系统化的问法是"为什么正则没有测试覆盖""为什么测试环境没拦住""为什么线上和测试环境的规则不同步"。
第三条,如果某层超出了当前团队的知识范围,先记录为"待查项",不要硬编一层理由。宁缺毋滥,一个未查实的根因比没有根因更有害。
举个例子,我们有一次支付回调事故,挖出来的完整链条是这样的:
- 为什么支付回调失败了?——签名校验不过。
- 为什么签名校验不过?——密钥轮换后,服务还在用旧密钥。
- 为什么轮换没有通知到所有服务?——轮换流程只通知了配置负责人,没有全局广播。
- 为什么没有全局广播机制?——密钥管理没有注册表,谁依赖哪个密钥没人清楚。
- 为什么没有注册表?——密钥管理当初是临时脚本实现的,一直没产品化。
到第五层,行动项已经很清楚了:建密钥依赖注册表、增加依赖检测、轮换时按注册表通知。这才是有效5Why该有的走向——把一个具体动作的失误,一路问到系统设计的缺位。
2.5 第五步:行动项必须能被验证,否则别写进报告
复盘会的产出只有一个:行动项。行动项做不实,复盘就是一场行为艺术。
我要求每一个行动项同时满足三个条件:第一,影响系统而非影响个人;第二,有明确负责人和截止日期;第三,验收标准可以被验证。我经常拿下面的对照表来纠正团队写法:
| 不合格行动项 | 合格行动项 |
|---|---|
| 加强监控 | 为支付回调新增错误率阈值告警(P95小于X);告警触发后10分钟内自动拉取最近30分钟变更记录到值班群 |
| 加强沟通 | 密钥轮换流程新增"全局广播+依赖服务确认"节点,确认记录归档到工单 |
| 相关同学注意 | 把配置白名单校验逻辑加入CI测试,测试用例覆盖空名单和异常格式 |
写行动项的时候,我总喜欢补一刀魔鬼追问:如果这个行动项没做,系统会用什么方式提醒你?如果没有任何自动提醒,那它对系统的改造就是零。靠自觉执行的事项,默认等于没写。
2.6 第六步:复盘报告不是为了统一口径,是为了锁住记忆
复盘报告的形成我控制在两页以内,不要再多了。结构永远是五块:事实时间线、关键决策时刻、根因链、行动项表格、严重级别和复盘ID。
报告写好的当天就发到固定的频道,同时归档到复盘仓库。我从不压着报告等"所有结论都完美了"再发,因为复盘价值最大的时间是事故后24小时,信息损耗最小。隔了一周再发的完美报告,不如当天发的不完美但有证据链的报告。
写报告还有一条铁律:可以写"我们当时没想清楚",但绝不允许写"这是某人能力不行"。复盘报告是要给未来的人看的,它的使命是帮助下一个值班者做更好的决定,而不是替某个领导出气。
3. 复盘必须过数据关:我用30/60/90天回访检验每条对策的真伪
流程跑通之后,我遇到了新的麻烦:行动项确实写了,但三个月之后再翻,很多要么没执行,要么执行了但什么也没改变。复盘会上的热情,和长期执行之间隔着一道巨大的衰减曲线。后来我彻底想明白了一件事——行动项不是"做完"就完了,而是要验证"生效"。
3.1 给行动项装上可测量的效果指标
我后来强制要求,每个行动项的验收标准,必须是一个可以被数据测量的变化,不能是"已完成上线""已完成开发"这样的过程描述。
比如"提升告警准确率"这个行动项,过程化的写法是"上线告警抑制规则"。可我要求的写法是"日均告警总数从120条降到40条以内"。有了这个数,回访时就非常好办:拉出告警平台的统计页面,达标了就是达标了,没达标就继续迭代,不存在讨论空间。
如果你给一个行动项写不出指标,通常不是指标难找,而是这个行动项本身不够具体。遇到这种情况,正确做法不是绞尽脑汁给"加强沟通"编一个指标,而是干脆换一个行动项,换成一个真正动了系统的项目。
3.2 30/60/90天回访:从"写完了"到"生效了"
我不相信一次复盘的结论能靠人类自觉长期存在。所以我设计了回访机制,每个行动项都有三个时间节点:
第30天:确认行动项是否上线,运行情况如何; 第60天:经历过一次真实事件或演练,验证这个改动在压力下依然有效; 第90天:把它收编进常规巡检,从"专项事件"变为"默认能力"。
三个节点在复盘仓库里的状态分别叫"执行中""已验证""已收编"。没按节点完成的行动项,自动进入下周例会的待办清单,直到有结果为止。这个机制最大的作用,是逼团队区分"做完了"和"生效了"。很多人改完配置就宣布解决,但要等到下一次同类故障发生时,才会知道你的补丁会不会成为另一个坑。第60天的验证节点,就是在这个问题上设置一次强制验收,不给系统悄悄回归的机会。
3.3 复盘仓库:把事故记录变成团队的知识资产
事故本身是坏事,但事故留下的知识资产是好事。我建了一个复盘仓库,结构非常朴素:
/postmortems 2024-07-15-pay-timeout.md 2024-06-02-config-rollout.md每条文件头部放元信息:日期、影响范围、严重级别、关联服务、标签、行动项清单和行动项状态。标签特别关键,我会打上"密钥管理""配置变更""缓存"这类词。下次出现相似事故苗头时,用一条命令就能搜出全部历史,而不是靠某个老员工的脑容量。
这里有个真正能提升效率的玩法:把复盘仓库和发布系统、值班群打通。每次发布前,CI脚本扫一遍本次变更涉及的服务,自动把相关历史复盘链接贴到发布单里。发布人不需要回忆"这个模块以前出过什么坑",系统替他记着。我们做了这个功能之后,团队踩重复坑的概率肉眼可见地下降。
前提是仓库里的文本质量要稳定,所以我严格限制模板结构,不允许自由发挥写长篇叙事,统一用分节表格。机器能解析,人也读得动,两边都舒服。
4. 从hindsight到foresight:复盘的本职是预防下一场事故
如果复盘只对已经发生过的事有用,那它的价值是有限的。这个项目真正让我觉得值得的地方,是积累了足够多的事故证据之后,团队开始获得"预见力"——按下一次发布按钮之前,脑中会自动弹出上次的教训。
4.1 收集near miss:免费的学习样本
重大事故是小概率事件,如果只复盘P0/P1,一年到头复盘次数一只手数得过来,根本养不成习惯。我后来建立了near miss记录制度,也就是"差点出事"清单。比如有人手滑点错了发布按钮但被权限系统拦下;配置改错但灰度比例很小没爆炸;缓存命中率短暂下降但业务扛了过去。
每条near miss只需要填三行:发生了什么、保护机制为什么拦住了(或者为什么没拦住)、需要补什么。不要求开大会,当天记录,当天认领行动项。这个机制的成本极低,但价值非常高——在真正的重武器开火之前,先用小事件反复校准流程。团队对复盘的敏感度也会因此保持在线,不会等哪天出了大事才手忙脚乱。
4.2 上线前的"事前验尸":把hindsight倒着用
复盘是事后,那能不能在事前借用同一套思路?这就是premortem,事前验尸。我在每次高风险变更上线前,会留出15分钟做这个活动:
先想象这个变更三天后引发了严重事故,然后让每个参与者独立写出"我觉得事故会怎么发生",不许交换意见。写完后轮流念,主持人把想法汇总,针对重复出现的假设补防御措施。
这个方法的效果非常惊艳。平时做方案评审,大家客客气气,提风险怕扫兴。事前验尸把"事故已经发生"设定为默认前提,这时候提"死法"就不再是泼冷水,而是在帮团队排雷。我们真靠它捞出来过几个大坑,比如"没考虑老版本客户端还在请求旧接口""回滚脚本会覆盖掉新的数据表结构"。这些问题如果上线后再发现,就是下一次复盘报告的主角。
4.3 把历史复盘沉淀成"已知风险清单"
复盘的结论不应该是一次性消费品。我每季度把过去所有复盘的根因链按主题聚类,产出一份"已知风险清单"。清单上的条目必须特别具体,不能写"注意安全"这种废话。举几个我们的真条目:
- 配置变更未经过灰度时,必须关联密钥依赖清单;
- 所有涉及容量扩容的操作,必须有回滚开关,且回滚开关在上线前要演练过;
- 超过两个服务参与的变更,必须指定一个全局协调人。
这份清单不是摆设,它是新人入职第一天就要读的文档。讲一百遍规范不如让他看半年的复盘仓库,因为里面每一条都是真实流过的血。新人能从中理解团队的红线在哪里,老员工也能用它来对新方案进行自查。
5. 落地hindsight一年后,我踩过的五个坑和对应的改法
流程设计得再好,落地时都会变形。我不打算只分享成功经验,下面五个坑是我真实踩过、也亲手改掉的,写出来能让后来者省点学费。
5.1 报告越写越像论文,最后没人读
有一段时间,我觉得报告写得详细等于专业。结果团队越来越反感复盘,说看报告像啃文献。改法是"字少事硬"。报告砍到两页,只保留时间线、决策时刻、行动项三块,其余讨论全部留在会上完成。报告是证据和结论的容器,不是文采展示台。变短之后,阅读率反而上来了,因为每读一行都有信息量,不掺水。
5.2 高职位在场,复盘会变成"校长训话"
有一阵子复盘会总请大老板列席,结果是会议室里没人敢真正开口。大家说半句留半句,生怕哪句话传出去成了自己的把柄。这跟谁专业不专业无关,是权力结构天然抑制信息流动。
我的改法是:复盘会分两场。第一场是"技术真相场",只有实际参与的人参加,产出时间线和根因,气氛封闭但安全。第二场是"资源汇报场",由主持人向管理层汇报结论和需要的资源,不带当事人接受审判。两层信息完全透明,但取消了"边回忆边看领导脸色"的恐怖场景。
5.3 行动项变成了任务墙上的僵尸
再好的行动项,如果没有后续机制,也会慢慢死在任务墙上。我后来把行动项接进每周例会待办清单,状态长期不变就自动高亮,相关责任人必须在周会上当面解释为什么还没动。这个机制压迫感刚好够,不重,但足够推动人去执行。记住前面那句话:没有自动提醒的复盘行动项,和没写一样。
5.4 过度复盘引发"分析瘫痪"
另一个极端是把所有事都拉来复盘,连发布延迟十分钟都要开一次会。结果团队开始反感,觉得"复盘就是新的大会"。后来我定了触发规则,只有满足以下条件之一才启动完整复盘:有用户可见的影响、有数据损坏和资损风险、或者是同类问题第二次出现。低频小失误用near miss记录就够了,不需要走全流程。复盘是一种投资,必须把钱花在回报最大的事件上,而不是把团队的精力磨光。
5.5 把hindsight工具本身当成终点
最后一个坑最微妙。流程、模板、指标全都建好之后,我一度觉得自己已经把复盘做得很专业了。但后来有一天我翻新出的报告,发现团队开始按模板填空,思路并没有真正打开——大家把"写报告"当成了"完成复盘"。
复盘的本质从来不是文档,而是在下一次决策前,你脑子里真的会多出一个"等等,上次这里就翻过车"的声音。我把这个声音叫作hindsight内化。模板可以删,系统可以换,但只要你养成了动手前主动回看历史教训的习惯,复盘就已经成功了。