
做过几年架构评审的人大概都有过这种体验会议室里坐满了人PPT 一页页翻过去讲的是服务怎么拆分、数据库怎么分库、消息队列怎么削峰。讲的人眉飞色舞听的人频频点头。然后有人冷不丁问了一句如果支付回调那个服务挂了订单状态会不会乱全场安静三秒接着开始有人含糊其辞地打圆场。这个场景几乎每个团队都碰到过。我们习惯性地把架构设计理解成把功能搭起来却很少系统性地去问这套东西坏掉的时候会怎样。FMEAFailure Mode and Effects Analysis故障模式与影响分析就是专门回答这个问题的工具。它最早来自航空和汽车行业后来被硬件、制造、医疗一路沿用现在越来越多软件团队把它拿来梳理架构风险。这篇文章我从零讲起不假设你有任何可靠性工程背景把 FMEA 怎么用在架构上、每个参数怎么定、工作坊怎么开、我踩过哪些坑一次说清楚。如果你正在做系统拆分、准备上线一个新模块或者单纯觉得自家架构总有点说不清楚的风险这套方法应该用得上。1. 为什么架构评审总是漏掉它坏了会怎样1.1 一次典型的架构评审现场到底发生了什么架构评审的默认视角是正向的从需求到功能从功能到组件从组件到部署。这个链条天然会把失效路径挤出去因为需求文档里几乎不写当依赖不可用时应该怎样。更麻烦的是会议这种社交场景本身。绝大多数人不愿意在公开场合说这个东西以后会炸一来显得悲观二来如果没炸反而像在挑事。于是评审会变成了功能确认会大家把接口定义清楚了字段对齐了当成完成风险那部分被默契地跳过。我在参与过的一次项目里见过极端案例一个活动系统把抽奖、发券、扣库存串在同一条同步调用链上评审时所有人都盯着并发量能不能撑住没人问如果发券服务超时前面的库存扣了该怎么办。上线后第一次大促发券服务因为下游短信通道抖动卡了 30 秒库存扣减链路被拖垮最后超卖了小几万单。事后复盘大家才发现这个失效场景在评审阶段完全可以被推演出来只是没人主动去想。1.2 FMEA 和架构文档的分工边界在哪很多人第一反应是这不就是架构文档该写的东西吗。其实两者分工很明确。架构文档回答的是系统由什么组成、彼此怎么协作、数据怎么流动它描述的是正常态FMEA 回答的是每个组成部分会以什么方式失效、失效的影响有多大、我们能不能提前发现、要不要处理。一个是静态结构描述一个是动态风险枚举缺了任何一半架构认知都是瘸的。打个比方架构文档像一张城市地图标着道路、立交、地铁线FMEA 像一张哪些路段容易积水、暴雨时哪条路会堵死、有没有备用路线的应急清单。地图告诉你城市长什么样应急清单才能在真出事的时候救你。做架构的人往往只顾着画地图很少有人愿意坐下来认认真真列一张应急清单。1.3 从零理解FMEA 本质上是一张有纪律的风险清单撇开一堆术语FMEA 的本质非常朴素它就是一张风险清单只不过列的时候有纪律。它要求你针对每一个功能或构件逐个问三个问题——它可能以什么方式坏掉失效模式坏掉之后后果有多严重严重度这个坏掉的概率有多大、我们能不能提前发现发生度、探测度把这三个维度量化打分排出优先级再决定哪些必须改架构、哪些加监控、哪些干脆接受。它的价值不在于那张表本身而在于它强制你把担心变成条目。人在脑内想风险是发散且健忘的一旦落到表格里、加上分数和责任人它就变成了可以被跟踪、被验证、被关闭的工程对象。这也是为什么我建议架构 FMEA 一定要写下来哪怕只用在线表格。2. 架构 FMEA 的五要素把模糊的担心变成可计算的数字2.1 功能基线先定义正常到底长什么样很多人上来就直接列故障结果列着列着就乱了。正确的第一步是先定义功能基线也就是这个模块在正常情况下应该做什么。注意功能基线要写到可观测的程度不能写处理订单而要写接收支付回调后在 200ms 内把订单状态从待支付更新为已支付并触发发货通知。粒度越具体后面列失效模式就越容易。我的经验是功能基线最好从接口和关键路径两头切。接口那头列出每个对外暴露的能力路径那头列出一次完整业务需要经过的几个关键步骤。两头一交叉功能清单基本就全了。这一步偷懒后面所有分析都会空转因为失效模式无处依附。2.2 失效模式不是宕机而是具体到某种错误新手最常见的毛病是把失效模式写成服务挂了。这太笼统导致后面完全没法分析。合格的失效模式要具体到以什么方式偏离预期。同样是订单状态更新失败可以拆成好几种回调根本没收到、收到了但处理超时、处理成功但状态没落库、落库了但下游没收到通知。这四种失效的严重度、探测方式、应对手段完全不同。我一般用一组固定的引导词来发散避免漏项延迟变慢、错误返回错误码、丢失数据没到、重复数据到了两次、乱序顺序错了、不一致多处数据对不上、不可用整个能力没了。这七个词套到任何一个功能上基本都能逼出一批失效模式。2.3 严重度 S架构视角下的后果分级严重度Severity衡量的是失效一旦发生后果有多严重。制造业常用 1 到 10 分软件架构里不需要那么细我习惯用 1 到 5 分把标准写死到团队能达成一致的程度。下面这张表是我在几个团队里推行过的版本可以直接改吧改吧拿去用分值后果描述典型表现5数据不可恢复或资损资金错账、订单超卖、核心数据丢失4核心业务整体不可用主链路瘫痪大面积用户无法下单3部分功能受损但有绕行某个非核心功能失败用户可换路径2体验下降响应变慢、偶发报错主流程仍可完成1无感知只影响日志、监控等非业务部分关键在于这张表要团队一起过一遍并签字确认否则每个人心里的5 分都不一样。我见过最离谱的情况是同一个消息积压场景开发打 2 分、运维打 5 分吵了半小时才发现大家对后果的理解完全不同。2.4 发生度 O 和探测度 D概率与可发现性发生度Occurrence是对失效发生概率的估计。软件里没法像制造业那样统计百万次故障率我一般用定性判断结合历史事故数据。1 分是几乎不会发生5 分是经常发生。如果有监控数据就按过去半年的实际触发次数来定档没有数据就靠资深同学的经验判断但要写明判断依据方便以后校准。探测度Detection衡量的是失效发生时我们能多快发现。这里有个反直觉的点探测度分越高代表越难发现。1 分是监控秒级告警并自动定位5 分是用户投诉了我们才知道。软件系统里最危险的往往就是探测度 5 的失效比如数据不一致、静默丢失它们不报警、不崩溃安安静静地错等发现时已经烂了很久。2.5 RPN 只是排序工具不是决策终点把三个分数乘起来得到 RPN风险优先数这是最经典的做法。但我要提醒一句RPN 只用来排优先级不能当作唯一的决策依据。它的最大问题是严重度 5 的项如果发生度、探测度都很低乘出来可能还不如一个严重度 3 但频繁发生的问题高结果高危项被排在后面。实际操作里我的做法是双轨排序先按严重度分档严重度 4 及以上的单独拉出来无论 RPN 多少都必须处理剩下的再按 RPN 排序分配精力。这样既保证了高危项不遗漏又保留了量化排序的效率。这一条是我踩过坑之后才改过来的后面第 7 节会详细说。3. 逐层拆解把 FMEA 套到架构的四种对象上3.1 构件级失效单个服务的崩溃与降级构件是架构里最直观的对象一个服务、一个中间件实例、一段定时任务都算。构件级 FMEA 要问的是它完全不可用时上游怎么办它部分可用比如只剩一半副本时行为会不会异常它处理变慢时会不会把上游线程池拖满这里有个容易被忽略的细节很多构件的失效不是挂而是半死不活。我就遇到过某个查询服务在 GC 停顿期间仍然能接受连接但每个请求都要等好几秒才返回结果上游所有调用线程全被占住整条链路跟着雪崩。所以构件级分析一定要把变慢这一档单独列出来不能只考虑可用和不可用两种状态。应对手段通常是三件套熔断、限流、降级。熔断负责快速切断对病态依赖的调用限流负责保护自己不被压垮降级负责在主路径失败时提供一个可接受的替代结果。这三样在 FMEA 表里要作为预防/探测措施逐条对应上去哪条失效模式没有对应措施就要标红。3.2 接口级失效超时、重试放大与幂等缺口接口是构件之间的接缝最容易出问题。我在接口级 FMEA 里固定检查几个点。超时设置每个同步调用有没有明确的超时超时值是不是和上游的整体预算匹配我见过下游设 60 秒超时、上游只给 3 秒预算的等于下游还没超时上游早断了超时形同虚设。重试放大加了重试之后一次用户请求会不会在下游放大成好几次如果下游已经过载重试只会火上浇油。正确做法是重试要带退避和抖动并且只在幂等的操作上重试。幂等缺口所有会被重试、被消息重复投递的接口是不是都做了幂等没有幂等重试就从提高成功率变成了制造脏数据。这几条我会在表里做成固定的检查项每次评审都过一遍。3.3 数据级失效一致性、缓存与消息丢失数据失效最隐蔽也最贵。要拆的维度包括跨库/跨服务写入的最终一致性靠什么保证消息投递是至少一次还是至多一次业务能不能容忍重复或丢失缓存和数据库之间的一致性窗口有多大窗口内读到旧数据会不会引发业务错误举个例子一个库存扣减如果先写数据库再删缓存中间进程崩了就会出现缓存里是旧库存、数据库是新库存的状态用户看到的可售数和实际对不上。这类问题的严重度往往打 4 到 5 分但探测度也高很难第一时间发现所以 RPN 会被顶得很高处理优先级应该排在前面。处理手段包括改成先更新数据库再延迟双删、引入对账任务、给关键数据加读时校验等。3.4 部署级失效单点、容量与依赖级联部署视角看的是整套东西作为一个整体会不会垮。单点是最经典的失效模式某个组件只有一份它没了整个系统就没了。数据库主库、只有一个实例的配置中心、单节点的定时任务调度器都是常见的隐藏单点。容量与级联同样关键。一个下游依赖的容量上限是多少当它被打满时是快速失败还是排队拖死上游依赖链路上任何一环没有隔离都可能引发级联故障。我在部署级分析时会画一张依赖关系图然后逐条问这条边断了会怎样这条边堵了会怎样把答案填进失效表。这一步做完往往能一眼看出架构里最脆弱的几处连接。4. 一场能出结论的 FMEA 工作坊怎么开4.1 会前准备范围、功能清单与参与人FMEA 工作坊最忌讳人来齐了才想聊啥。会前必须定三样东西。范围这次分析哪个模块、哪条链路边界划清楚否则会无限扩散。功能清单把第 2.1 节说的功能基线提前整理好发给参会人。参与人至少要有架构负责人、一线开发、运维/SRE有条件的话拉上测试。开发懂细节运维懂线上真实故障架构懂全局这三类人凑齐才算数。时间上我的建议是单次不超过 90 分钟一个模块开一到两次。如果范围太大就拆成几次开每次只啃一条核心链路。人一多、时间一长注意力必然涣散产出质量会断崖下跌。4.2 会中节奏从发散失效模式到收敛措施会议节奏我一般拆成三段。第一段发散针对每个功能点用前面那七个引导词快速过一遍把所有能想到的失效模式写出来这个阶段不评判、不打分先求量。第二段收敛对每条失效模式定严重度、发生度、探测度这一步最容易吵架所以要提前把打分标准第 2.3 节那张表贴出来有分歧就对照标准而不是各自拍脑袋。第三段定措施对每条高优先级条目明确改什么、谁负责、什么时候完成、怎么验证。这里有个纪律措施必须落到具体动作不能写加强监控这种空话要写成给支付回调加超时 3 秒 三次退避重试 失败进死信队列并告警负责人张三下周三前完成用压测验证。4.3 会后产出把表变成可跟踪的任务会开完不算完FMEA 的价值在会后。我会把工作表整理成两部分一部分是风险台账记录所有失效模式及其评分另一部分是行动项清单把每条改进措施拆成可跟踪的工单进到日常的研发管理流程里。这里有个很实用的技巧给行动项打上验证方式标签。比如加熔断这条验证方式就是注入下游延迟观察是否在阈值内熔断。没有验证方式的行动项十有八九会烂尾因为你根本不知道它做没做到位。4.4 怎么避免把 FMEA 开成吐槽大会FMEA 有个天然倾向就是变成互相甩锅的场合。你这个服务老超时你们运维上次扩容太慢。一旦出现这种情况主持人要立刻把话题拉回到失效模式和后果上只谈系统行为不谈人。我的做法是提前声明一条规则会上只描述现象和后果不评价人责任人的确定放到会后单独沟通。另一个常见问题是讨论过度深入实现细节比如为了某个超时到底设 2 秒还是 3 秒争论半小时。这时候主持人要果断喊停把它记成待定项会后小范围定。工作坊的目的是找出高危风险并分配措施不是把所有技术细节当场敲定。5. 案例拆解一个订单链路的架构 FMEA 实操5.1 场景与功能基线假设我们分析一条简化的下单链路用户下单后系统依次执行创建订单、扣减库存、调用支付、支付成功后更新订单状态并通知发货。功能基线定为——用户点击下单后 1 秒内返回下单结果支付成功后 5 秒内订单状态变为已支付并发出一次发货通知。链路涉及的构件包括订单服务、库存服务、支付网关、消息队列、发货服务。我们逐一对每个功能点做失效模式分析。5.2 失效模式清单把前面的方法套上去能列出一张像下面这样的表失效模式严重度 S发生度 O探测度 DRPN现有措施支付回调丢失订单长期待支付43448无回调补偿库存扣减超时但实际已扣53460无对账发货通知重复发送33218已有去重表消息队列积压导致通知延迟24324有积压告警订单状态更新成功但发货消息发送失败42432无本地消息表5.3 RPN 排序与改进措施按严重度优先、RPN 辅助的原则最先要处理的是库存扣减超时但实际已扣和支付回调丢失。前者严重度 5涉及资损后者导致订单状态长期错乱影响用户和运营。对应的措施可以这样定库存扣减改为带预留的最终一致方案扣减后落一条流水另起对账任务定期比对库存与订单不一致就自动补偿或告警支付回调增加主动查询兜底下单后启动延时任务若一段时间内未收到回调则主动向支付网关查询状态订单状态更新与发货消息之间引入本地消息表保证改状态和发消息最终一致。5.4 改进之后再做一次复评措施落地后要重新打分验证风险是不是真的降下来了。上面的库存扣减超时在引入对账和补偿后探测度从 4 降到 2RPN 掉到 30 左右且即便发生也能自动修复严重度的实际影响也被削弱。复评这一步很多人会跳过但它恰恰是闭环的关键——不复评你永远不知道措施有没有用。6. FMEA 和混沌工程、故障演练怎么衔接6.1 FMEA 管想得到混沌工程管验得了FMEA 是在纸上推演失效混沌工程是在真实系统里主动注入故障看反应。两者不是替代关系而是上下游。FMEA 帮你列出哪些失效值得担心混沌工程帮你验证当这个失效真的发生时系统是不是像你设计的那样反应。没有 FMEA混沌工程容易变成随机搞破坏没有混沌工程FMEA 的措施只能停在纸面上永远不知道有没有效。6.2 从 FMEA 条目直接生成演练场景这里有个很顺手的做法FMEA 表里每一条高分失效模式都可以直接翻译成一个演练场景。支付回调丢失对应注入回调丢弃下游超时对应注入网络延迟消息积压对应注入消费端停顿。演练的预期结果就是 FMEA 里写的应对措施应该表现出的行为比如应触发熔断并降级到备用路径。这样一来演练不再是瞎试而是有的放矢。6.3 把演练结果反哺回 FMEA演练跑完结果要写回 FMEA 表。如果实测发现熔断没触发、降级路径也挂了说明当初的措施评估过于乐观探测度或发生度要重新打分并补新的措施。这个FMEA 出题、演练验证、结果回填的循环跑上几轮之后你手里就会有一份越来越准的架构风险地图这比任何文档都值钱。7. 落地时最容易踩的几个坑7.1 只填表不改架构最常见的失败模式就是表填得漂漂亮亮架构一动不动。团队开完工作坊表格存档然后该怎样还怎样。问题出在没有把措施接到研发流程上。解决办法是把 FMEA 行动项纳入版本迭代和需求一样排期、一样验收否则它永远是重要但不紧急的那一档。7.2 迷信 RPN 数字阈值我前面提过很多团队会设一条 RPN 阈值线比如大于 100 就处理。这很危险因为严重度 5 的低频风险可能算不出高分却被放过了。我的建议是永远以严重度分档为主、RPN 排序为辅严重度到 4、5 的项不管 RPN 多低都要看因为这类失效一旦发生就是事故。7.3 严重度打分全靠拍脑袋没有统一标准的打分等于没打分。三个人给同一个场景打出三个分数后面所有排序都失去意义。所以第 2.3 节那张打分表必须团队共建、书面确认遇到分歧就翻开标准逐条对照。这张表最好半年校准一次因为业务在变后果的严重程度也在变。7.4 做完一次就不再更新架构 FMEA 不是一次性文档。系统在演进新的依赖、新的流量形态、新的业务规则都会带来新的失效模式。我的习惯是每次大的架构变更或者上线大功能前翻出 FMEA 表更新一轮重点看新增的链路有没有被覆盖。更新时不用全量重做增量补几条往往就够了。7.5 把分析范围铺得过宽导致半途而废贪多是另一个隐形杀手。第一次做就想把整个系统全分析一遍结果开了三次会还在讲登录模块团队直接失去耐心。我的做法是挑最核心、最贵、最容易出事的链路先啃拿到第一份成果让团队尝到甜头再逐步铺开。先跑通一条链路的完整闭环比全面铺开却处处夹生要有效得多。最后分享一个我自己一直在用的小技巧把 FMEA 的第一轮成果做成一张简单的风险热力图横轴是发生频率、纵轴是后果严重度把每条失效模式点上去。开会时大家一眼就能看出哪些点挤在右上角——那些就是必须优先处理的重灾区。这张图比一长串 RPN 数字直观得多也更容易让非技术背景的同学参与进来。用久了你会发现它慢慢成了团队对自家架构哪里最虚的共同认知而这恰恰是做架构最该有的底气。