4. 事件树分析(ETA):从初始事件到后果的全链路推演
事件树分析,说白了就是「如果这个坏了,接下来会发生什么」。
我刚开始做稳定性分析时,总喜欢直接拍脑袋说「这个故障会导致系统崩溃」。后来被架构师怼了一次:「你怎么知道一定会崩溃?中间有没有降级?有没有熔断?有没有重试?」
嗯,从那以后,我就老老实实用事件树了。
4.1 事件树的核心逻辑
事件树是一种正向推理方法。它从一个初始事件(比如「数据库连接池耗尽」)开始,沿着系统设计的防护措施逐层推演,最终得到各种可能的后果。
你可以把它想象成一个决策树,只不过每个节点不是「你选A还是B」,而是「这个防护措施生效了,还是失效了」。
关键概念:事件树不是用来分析「为什么会发生」,而是用来分析「发生后会怎样」。
我个人习惯把事件树分成三个要素:
- 初始事件(IE):触发整个链条的那个故障
- 安全功能(SF):系统里用来拦截故障的防护措施
- 后果(Consequence):最终落到用户头上的结果
举个例子:
初始事件是「上游服务超时」。安全功能依次是:重试机制 → 熔断器 → 降级策略 → 兜底缓存。每个环节都有「成功」和「失败」两条分支。
你想想看,如果重试成功了,后面根本不会触发熔断。如果重试失败但熔断生效了,那后续流量就被挡住了。只有所有防护都失效,才会导致「用户看到500」这个最严重的后果。
4.2 事件树的构建方法
构建事件树其实不复杂,但需要你对系统的防护措施了如指掌。我一般按下面几步来:
4.2.1 确定初始事件
初始事件从哪里来?从故障模式库、从历史事故、从混沌工程实验里来。
我在项目中遇到过最典型的初始事件是「缓存节点宕机」。当时我们以为这只是个小问题,结果事件树一画,发现后面连着6层防护,其中2层已经形同虚设了。
我的经验:初始事件不要选得太宽泛。「网络故障」太笼统,要具体到「跨AZ网络延迟超过500ms」这种级别。
4.2.2 列出安全功能
按故障传播路径,把系统里所有可能拦截这个故障的机制列出来。顺序很重要——必须是故障实际经过的顺序。
比如一个典型的微服务调用链路:
- 客户端重试(SF1)
- 负载均衡健康检查(SF2)
- 服务端限流(SF3)
- 服务端熔断(SF4)
- 降级返回默认值(SF5)
注意,有些安全功能是并行的,有些是串行的。事件树只处理串行关系,并行的情况需要拆成多个分支。
4.2.3 逐层展开分支
每个安全功能都有两个分支:成功(S)和失败(F)。
从初始事件开始,第一层安全功能分出2条路径,第二层再各分出2条,以此类推。n个安全功能,最多有2ⁿ条路径。
但实际中很多路径会被剪枝——比如「重试成功」之后,后面的熔断、降级根本不会触发,那条路径就终止了。
注意:不要机械地画满2ⁿ条路径。事件树的价值在于「剪枝」,而不是「穷举」。我曾经见过有人画了64条路径的事件树,其中50条在现实中根本不可能发生。
4.3 成功/失败路径分析
路径分析的核心是回答两个问题:
- 这条路径最终导致什么后果?
- 这条路径发生的概率有多大?
我习惯把路径分成三类:
| 路径类型 | 描述 | 例子 |
|---|---|---|
| 安全路径 | 所有防护都生效,故障被完全隔离 | 重试成功 → 用户无感知 |
| 降级路径 | 部分防护失效,但最终有兜底 | 重试失败 → 熔断生效 → 降级返回缓存数据 |
| 失效路径 | 所有防护全部失效,故障直达用户 | 重试失败 → 熔断失效 → 降级失败 → 用户看到500 |
这里有个坑:很多人只关注失效路径,觉得「反正降级路径用户还能用,不用管」。但降级路径的体验往往是「能用但很难受」,比如返回了过期的数据、功能残缺、响应变慢。这些在稳定性分析里同样需要评估。
4.4 后果评估与概率计算
终于到了算账的时候。
4.4.1 后果评估
每条路径的后果,我一般从三个维度打分:
- 影响范围:多少用户、多少业务受影响
- 影响时长:故障持续多久
- 影响程度:完全不可用 vs 部分功能受损
打分标准每个团队不一样,但至少要能区分出「可接受」和「不可接受」的后果。
我的习惯:后果评估一定要拉上业务方一起做。技术团队觉得「返回默认值」可以接受,业务方可能觉得「默认值导致订单金额错误」是P0事故。
4.4.2 概率计算
每条路径的概率 = 初始事件概率 × 各安全功能成功/失败概率的乘积。
举个例子:
初始事件「缓存节点宕机」的概率是 0.01(每100次请求发生1次)。
安全功能概率:
- 重试成功概率:0.9(重试机制比较靠谱)
- 熔断成功概率:0.95
- 降级成功概率:0.8(降级逻辑写得比较糙)
那么「重试失败 → 熔断成功 → 降级成功」这条路径的概率就是:
0.01 × (1-0.9) × 0.95 × 0.8 = 0.00076
也就是每10万次请求,大约有76次会走这条降级路径。
而「所有防护全部失效」的概率是:
0.01 × (1-0.9) × (1-0.95) × (1-0.8) = 0.00001
每10万次请求只有1次。看起来很低,但如果你的系统每天处理1亿请求,那就是每天100次——这个数字你还觉得低吗?
避坑指南:概率数据从哪里来?我一般三个来源:线上监控的统计数据、混沌工程实验的实测数据、以及专家经验估算。千万不要只用「我觉得」来拍概率,那跟算命没区别。
4.5 事件树的可视化
光用文字描述事件树太抽象了。下面这张图展示了一个典型的事件树结构:
4.6 事件树的常见误区
做了这么多年稳定性分析,我总结了几个人容易踩的坑:
误区一:忽略条件概率
安全功能的成功概率不是独立的。比如「熔断成功」的概率,在「重试已经失败3次」的条件下,和正常情况下是不一样的。我见过有人直接把独立概率相乘,算出来的结果跟实际差了10倍。
误区二:只画树,不算账
事件树的价值在于量化。如果你画完树不计算概率、不评估后果,那跟画个思维导图没区别。我曾经评审过一个事件树,画了30多个节点,但一个概率数字都没有——这种分析报告我直接打回去重做。
误区三:忽略时间因素
事件树默认是「瞬间完成」的,但现实中防护措施有响应时间。比如熔断器需要10秒才能触发,那在这10秒内系统可能已经崩溃了。我的建议是:在事件树旁边加一个时间轴,标注每个环节的延迟。
4.7 事件树与故障树的配合
最后说一句,事件树和故障树(FTA)是天生一对。
故障树从顶事件往下推,找原因。事件树从初始事件往上推,看后果。两者结合,就是完整的「原因 → 故障 → 后果」链条。
我自己的习惯是:先用故障树分析出关键初始事件,再用事件树分析每个初始事件的影响。这样既知道「为什么会坏」,也知道「坏了会怎样」。