CPT304 SoftwareEngineeringII 软件工程 2 Pt.6 批判性分析 / 关键性分析(Critical Analysis)
2026/6/9 15:56:07 网站建设 项目流程

文章目录

    • 1. 批判性分析(Critical Analysis)介绍
    • 1.1 什么是批判性分析 / 关键性分析
    • 1.2 为什么批判性分析很重要
    • 1.3 批判性思维和批判性分析的区别
  • 2. 批判性分析的技术与工具
    • 2.1 FMEA(Failure Modes and Effects Analysis,失效模式与影响分析)
      • 2.1.1 步骤
        • 2.1.1.1 列出系统的组成部分或功能
        • 2.1.1.2 评估严重程度、发生概率、检测难度(Assess Severity, Occurrence, Detection)
          • 2.1.1.2.1 RPN(Risk Priority Number,风险优先级数)
          • 2.1.1.2.2 收集严重程度 S 的数据
          • 2.1.1.2.3 收集发生概率 O 的数据
          • 2.1.1.2.4 收集发生概率 D 的数据
      • 2.1.2 示例 1
      • 2.1.3 示例 2
      • 2.1.4 练习 1
      • 2.1.5 Quantitative FMEA(定量 FMEA)
      • 2.1.6 Mitigation Prioritization(缓解措施优先级排序)
      • 2.1.7 练习 2
    • 2.2 RCA(Root Cause Analysis,根本原因分析)
      • 2.2.1 五个为什么
      • 2.2.2 示例 1
      • 2.2.3 示例 2
      • 2.2.4 进阶 RCA
        • 2.2.4.1 故障树分析(Fault Tree Analysis,FTA)
          • 2.2.4.1.1 Fault Tree Analysis(FTA,故障树分析) 的作用
          • 2.2.4.1.2 FTA(Fault Tree Analysis,故障树分析)具体怎么工作
          • 2.2.4.1.3 识别并量化原因(Identifying and Quantifying the Causes)
          • 2.2.4.1.4 计算故障发生概率(Calculate Failure Probabilities)
          • 2.2.4.1.5 练习 1
          • 2.2.4.1.6 概率数据的“动态”性质(Dynamic Nature)
          • 2.2.4.1.7 概率数据的“静态”性质(Static Nature)
          • 2.2.4.1.8 概率数据的混合性质(Mixed Nature)
          • 2.2.4.1.9 示例3
          • 2.2.4.1.10 练习 2
    • 2.3 把 RCA 和 FMEA 连接起来

1. 批判性分析(Critical Analysis)介绍

1.1 什么是批判性分析 / 关键性分析

Critical Analysis 是一个系统性的评估过程,用来评估软件产物的:

  1. strengths(优点 / 强项)
  2. weaknesses(缺点 / 弱点)
  3. validity(有效性 / 合理性)

Critical Analysis 在软件工程中的目的是:

  1. 尽早发现缺陷(Identify defects early)。
    例如在需求阶段就发现问题,避免后期开发完才返工。
  2. 提高系统可靠性(Improve system reliability)。
    也就是让软件更稳定、更少出错。
  3. 优化开发流程(Optimize development processes)。
    例如发现某些开发步骤效率低、容易出错,然后进行改进。

1.2 为什么批判性分析很重要

大约 60% 的软件缺陷来源于需求阶段。
在软件上线后再修复 bug,成本可能是在设计阶段修复的 100 倍。
现实世界中的影响例子有:
Therac-25 事故(1985–1987):软件缺陷导致了致命的辐射过量事故。

1.3 批判性思维和批判性分析的区别

批判性思维 是一种比较通用的思考能力,用来解决问题和进行逻辑推理。
批判性分析 是针对某个具体对象进行有重点、有结构的评价。
它们有重叠的地方,都需要:

  1. Logical reasoning(逻辑推理)
  2. Skepticism(怀疑精神 / 不盲目相信)

二者的区别是:
批判性分析会使用某个专业领域里的工具和方法。

2. 批判性分析的技术与工具

  1. 失效模式与影响分析(Failure Modes and Effects Analysis,FMEA)
    找出系统可能会在哪里出错,以及这些错误会造成什么影响(Identifies potential failures and their impact)。
  2. 根本原因分析(Root Cause Analysis,RCA)
    把问题一步步追溯到最根本的原因(Traces problems back to their origin)。
  3. SWOT 分析(SWOT Analysis)
    从四个方面(优势、劣势、机会、威胁)分析一个系统、项目或方案(Evaluates strengths, weaknesses, opportunities, threats)。
  4. 代码审查(Code review)
    系统地检查源代码(Systematic examination of source code)。
  5. 需求验证(Requirements Validation)
    确保需求是清楚的、完整的、可以测试的(Ensures requirements are clear, complete, and testable)。

这些分析方法不只是“最佳做法”,而且经常是法律或行业标准要求必须做的。
例如:医疗软件 需要遵循 ISO 14971 标准。
汽车软件 需要遵循 ISO 26262 标准。

2.1 FMEA(Failure Modes and Effects Analysis,失效模式与影响分析)

FMEA 是主动预防型的,它是一种计划工具,用来在麻烦发生之前就阻止它。
FMEA 会列出系统中所有可能的故障,然后对它们进行评分,最后决定哪些问题要优先修复。
这里的评估标准有:

缩写英文中文含义
SSeverity严重程度问题发生后有多严重
OOccurrence发生概率这个问题有多可能发生
DDetection检测难度这个问题在发生前有多容易被发现

一般来说:
S 越高,说明后果越严重;
O 越高,说明越容易发生;
D 越高,说明越难提前发现。
然后通常会计算一个风险优先级:
RPN = S × O × D
RPN 越高,说明这个问题越应该优先处理。

假设我们正在开发一个 网上商店系统。我们提前预测到:
支付系统可能会失败,比如信用卡无法处理付款。然后我们按照 S、O、D 标准评估该问题的严重程度、发生概率和检测难度,并计算 RPN。根据 RPN 的高低,我们判断该失效模式的优先级。如果 RPN 较高,就需要优先添加相应的预防措施、缓解措施或备用方案,例如备用支付方式、失败重试、异常监控和防止重复扣款机制。

2.1.1 步骤

  1. 列出系统的组成部分或功能(List components/functions of the system)。
  2. 识别潜在的失效模式,也就是找出每个部分可能会怎么出错(Identify potential failure modes)。
  3. 评估三个指标,并计算风险优先级数 RPN(Assess severity, occurrence, detection (Risk Priority Number: RPN))。
缩写英文中文含义
SSeverity严重程度这个故障发生后有多严重
OOccurrence发生概率这个故障有多可能发生
DDetection检测难度这个故障有多难被提前发现
2.1.1.1 列出系统的组成部分或功能

我们应该把系统中的哪些功能纳入 FMEA 分析?
我们可以根据评估风险 SOD 去回答这个问题。
SOD 在这一步上那就是:

  1. 如果这个功能失败,后果很严重(Failures have high impact,Severity, S)。
  2. 这个功能比较容易出错,发生概率较高(Failures are likely,Occurrence, O)。
  3. 这个功能出错以后不容易被提前发现(Failures are hard to catch,Detection, D)。

所以在做 FMEA 时,应该优先选择那些“出错后影响严重、发生概率较高、又不容易被发现”的系统功能进行分析。、

具体的步骤如下:

  1. 理解系统的目的和范围(Understand the System’s Purpose and Scope)
  2. 评估关键性和影响(Assess Criticality and Impact)
  3. 评估使用频率和暴露程度(Evaluate Usage and Exposure)
  4. 检查复杂性和变更频率(Check Complexity and Change Frequency)
  5. 评估检测难度(Assess Detection Challenges)
  6. 利用历史故障记录(Leverage Historical Failures)
  7. 考虑外部接口(Consider External Interfaces)
2.1.1.2 评估严重程度、发生概率、检测难度(Assess Severity, Occurrence, Detection)

这里我们再看一下SOD分别是什么意思:

  1. Severity,S(严重程度):
    如果这个故障发生了,它对系统、用户或业务的影响有多严重?评分一般是 1(minor) 到 10(catastrophic)。
  2. Occurrence,O(发生概率):
    这个故障发生得有多频繁?评分也是 1(rare) 到 10(frequent)。
  3. Detection,D(检测难度):
    在问题影响用户之前,我们有多大可能提前发现它?评分也是 1(always detected) 到 10(undetectable)。
2.1.1.2.1 RPN(Risk Priority Number,风险优先级数)

RPN = Severity × Occurrence × Detection
(风险优先级数 = 严重程度 × 发生概率 × 检测难度)
也就是:RPN = S × O × D

RPN 高的问题需要立即关注。
但是,批判性分析要求:任何 Severity 为 9 或 10 的项目,不管总 RPN 是多少,都必须被处理,因为它对人的生命或整个系统完整性的风险太高,不能忽视。

2.1.1.2.2 收集严重程度 S 的数据

也就是说,不能随便给 S 打分,可以以下面的几种方法来收集数据。

用户影响分析(User Impact Analysis):
数据来源:

  • User stories(用户故事)
  • Requirements docs(需求文档)
  • Customer support tickets(客户支持工单 / 客服反馈记录)

方法:检查这个故障会怎样影响用户。

利益相关者意见(Stakeholder Input):
数据来源:

  • Product managers(产品经理)
  • Developers(开发人员)
  • Business analysts(业务分析师)

方法:可以开一个讨论会,或者做问卷调查,让相关人员根据业务目标给影响程度打 1 到 10 分。

行业标准(Industry Standards):
数据来源:我们可以参考行业里的 FMEA 指南或软件风险管理标准。
例如:
AIAG:汽车行业常用的 FMEA 指南;
IEC 60812:关于 FMEA 方法的国际标准;
ISO 27001:信息安全管理标准,常用于软件安全风险分析。

方法:使用预先定义好的严重程度评分表(predefined severity tables)。

历史数据(Historical Data):
数据来源:可以参考过去系统中真实发生过的问题记录,比如:

  • Incident reports(事故报告)
  • Post-mortems(事后复盘报告)
  • Bug trackers(缺陷跟踪系统),比如 Jira

方法:分析过去故障造成过什么影响。

2.1.1.2.3 收集发生概率 O 的数据

在 FMEA 里评估一个故障“有多容易发生”时,不能完全凭感觉,要参考多方面。

日志分析(Log Analysis):
数据来源:

  • System logs(系统日志)
  • Error tracking(错误追踪工具),比如 Sentry、New Relic

方法:统计一段时间内故障发生的次数。

测试数据(Testing Data):
数据来源:

  • Unit test results(单元测试结果)
  • Integration test results(集成测试结果)
  • Load test results(负载测试结果 / 压力测试结果)

方法:运行测试来模拟不同条件下系统是否会出错。

开发人员估计(Developer Estimates):
数据来源:

  • Software engineers(软件工程师)
  • Architects(系统架构师)

方法:根据代码复杂度和过去的 bug 记录,讨论并估计故障发生概率。

使用模式 / 使用规律(Usage Patterns):
数据来源:数据分析工具(Analytics),例如:Google Analytics、server metrics
通过数据分析工具或服务器指标来观察用户怎么使用系统。
方法:把故障和用户活动情况联系起来分析。

基准数据 / 行业参考数据(Benchmarks):
数据来源:行业数据或者供应商服务等级协议(vender SLA),例如 AWS uptime stats
方法:使用典型故障率来估计问题发生概率,例如:网络中断平均每小时 0.01 次。

2.1.1.2.4 收集发生概率 D 的数据

我们可以从多个方面判断一个故障是否容易被发现。
测试覆盖率(Test Coverage):
数据来源:Test reports,例如 JaCoCo、pytest 这些测试工具生成的报告。
方法:测量有多少比例的代码被测试到了。

监控系统(Monitoring Systems):
数据来源:Logs, alerts,例如 Prometheus、Datadog。
方法:检查故障发生时,系统是否会触发报警。

质量保证流程(QA Processes):
数据来源:Development lifecycle,例如代码审查、静态分析。
意思是是说看开发流程中有没有质量检查环节。
方法:评估这些控制措施是否足够强。

用户报告 / 用户反馈(User Reports):
数据来源:

  • Support tickets(客服工单)
  • Bug reports(Bug 报告 / 缺陷报告)

方法:如果是用户先发现问题,而不是系统提前发现,那么 Detection 分数就高。

设计审查(Design Reviews):
数据来源:

  • Architecture docs(架构文档)
  • Peer reviews(同行评审 / 同事评审)

可以通过检查系统架构文档、让其他工程师评审设计,判断系统有没有内置的检查机制。
方法:评估系统中是否有内置检查机制。

2.1.2 示例 1

我们用几个例子来说明 FMEA。
示例1是游戏 App。
需求层面的 FMEA:
功能 / 需求:游戏要能在所有手机上运行。
失效模式:游戏在旧手机上卡顿。
RPN 评分:
严重程度(S)= 8,如果游戏很卡,玩家可能会直接退出游戏。
发生概率(O)= 4,因为市场上还有不少用户在用旧手机,所以这个问题有一定可能发生。但不是所有用户都会遇到,所以不是特别高。
检测难度(D)= 3,因为这个问题比较容易测试。开发团队可以拿一些旧手机测试游戏运行情况,很容易发现卡不卡。
所以,RPN = 8 × 4 × 3 = 96
解决方案:优化图形。

2.1.3 示例 2

这里分析一个银行 APP。
从系统设计角度分析 FMEA:
功能:把钱转到另一个账户。
失效模式:如果服务器宕机,转账可能失败。
RPN 评分:
严重程度(S)= 10,因为银行转账涉及用户的钱。
如果转账失败导致钱丢失、扣款异常、账户金额错误,这就是非常严重的问题。
发生概率(O)= 2,服务器宕机不是每天都会发生,所以发生概率较低。
检测难度(D)= 5,比如服务器突然宕机,可能只有在转账请求发送时才发现。
如果没有良好的监控、重试机制和状态检查,就可能比较难及时发现和处理。
所以,RPN = 10 × 2 × 5 = 100
解决方案:添加离线队列(offline queue)。当服务器暂时不可用时,系统不要直接让转账请求丢失,而是先把请求安全地排队保存起来,等服务器恢复后再继续处理。

2.1.4 练习 1

我们尝试通过一个练习更加全方位的使用 FMEA。

任务:对一个在线投票系统进行 FMEA 分析。
需要分析的功能:

  1. 用户身份验证
  2. 投票提交
  3. 结果统计

我们的步骤还是:

  1. 识别 3 个失效模式。或者说是找出 3 个可能出错的情况。
  2. 给每个故障打 S、O、D 分数。
  3. 计算RPN。

结果如下:

  1. 用户认证 / 身份验证的失效模式是密码泄露。
    评分是:
    Severity = 10:非常严重,因为会影响投票合法性和用户安全;
    Occurrence = 3:发生概率不是特别高;
    Detection = 4:有一定可能发现,但不一定很容易;
    RPN = 10 × 3 × 4 = 120。
  2. 投票提交的失效模式是重复投票。
    评分是:
    Severity = 8:比较严重,因为会影响投票公平性;
    Occurrence = 2:发生概率较低;
    Detection = 5:检测难度中等;
    RPN = 8 × 2 × 5 = 80。
  3. 结果统计 / 计票的失效模式是计票错误。
    评分是:
    Severity = 10:非常严重,因为会直接影响最终投票结果;
    Occurrence = 1:发生概率很低;
    Detection = 3:相对容易检测;
    RPN = 10 × 1 × 3 = 30。

2.1.5 Quantitative FMEA(定量 FMEA)

传统 FMEA 里,S、O、D 通常是人工打分,范围是 1 到 10。这种打法有一定主观性,因为分数主要靠经验判断。

进阶方法:进阶 FMEA 会尽量用真实数据来代替主观打分。

严重程度(S)可以用具体指标来衡量,比如:系统停机时间百分比、收入损失。
发生概率(O)可以用历史数据或 MTTF 来判断,比如:MTTF(Mean Time To Failure,平均无故障时间)。
检测能力(D)可以用测试覆盖率或检测概率来表示。比如:测试覆盖率 80%,这就相当于原来传统 FMEA 的 2 分。
因此传统 FMEA 里:D 越高 = 越难发现 = 风险越大。
现在在 D 表示检测概率(detection probability),因此D% 越高 = 越容易发现 = 风险越低。

所以现在 RPN 的计算公式为 RPN = S × O × (1 - D%)(RPN = 严重程度 × 发生概率 ×(1 - 检测概率))

2.1.6 Mitigation Prioritization(缓解措施优先级排序)

做完 FMEA 后,我们不仅要知道哪些风险高,还要决定先解决哪个问题最划算、最值得投入资源。

我们使用成本—收益模型(Cost-Benefit Model)解决这个问题。
成本—收益模型(Cost-Benefit Model)用两个方面来判断:

  • Cost = Development effort (hours) + Tooling cost
    也就是说修复成本包括花费的时间以及所花费的成本。
    比如修复一个数据库崩溃问题,需要工程师工作 50 小时,成本大约是 5000 美元。
  • Benefit = Risk reduction (ΔRPN × Impact)
    意思是说收益来自于风险降低了多少。
    比如修复这个数据库崩溃问题,可以将 RPN 从 200 降低到 50,并减少 10K 美元损失,那么这里的收益就是 (200 - 50)× 10,000 = 1,500,000 美元,所以就是投资回报率(ROI,Return on Investment)高。

2.1.7 练习 2

我们通过一个练习尝试使用定量 RPN 的 FMEA。
练习要求我们分析一个云存储 API。
失效模式:高负载情况下上传失败。
MTTF(Mean Time To Failure,平均无故障时间)= 1000 h
Downtime = = $5K/h,意思是系统停机或上传功能不可用时,每小时损失 5000 美元。
Test Coverage = 90%。

因此指标计算如下:
严重程度(S):$5K/hour × 1-hour outage = $5K impact → 8,因为上传失败停机 1 小时,每小时损失 5000 美元,这个损失比较高,但还没有达到灾难级别。
发生概率(O):MTTF = 1000 hours → Failure rate = 1/1000 = 0.001/hour → 2,MTTF = 1000 h,所以 1 / 1000 = 0.001 次/小时,这个发生概率比较低,所以给 2。
检测能力(D):90% coverage → D% = 0.9 → (1 - 0.9) = 0.1 → 1,这个计算用具体的公式参考,较为简单。
我们现在计算 RPN = 8 × 2 × 1 = 16。
缓解措施:增加自动扩容机制,用来应对流量高峰。

2.2 RCA(Root Cause Analysis,根本原因分析)

RCA 是反应型的(reactive),它像侦探工具一样,用来在问题发生之后找出原因并修复问题。
例子:网上商店上线后,支付系统崩溃了。我们开始问“为什么?”最后发现原因是服务器无法承受 1000 个用户同时访问,因为之前没有做负载测试。

2.2.1 五个为什么

对于 RCA,我们的常用方法是 五个为什么(5 Whys)。
遇到问题后,不只停留在表面原因,而是连续追问“为什么”,直到找到根本原因。
不一定真的必须问满 5 次,重点是要一直追问到真正原因。

例如我们前面问题是:系统在高峰负载时崩溃。
然后开始追问:为什么系统崩溃?(Why? → Server overload)
因为服务器过载了。
继续追问:为什么服务器会过载?(Why? → Insufficient scaling.)
因为扩展能力不够。
接着追问:为什么扩展能力不够的问题之前没发现?(Why? → No load testing.)
因为没有做负载测试。

2.2.2 示例 1

我们再看几个示例。
第一个例子是有关一个太空射击游戏崩溃的问题。
我们尝试用五个为什么去进行 RCA。
为什么?因为敌人生成得太快。
为什么敌人生成太快?因为循环没有限制。
根本原因:缺少敌人生成速率上限。
解决方法:添加限制。

2.2.3 示例 2

我们再看一个银行 APP 的例子。
问题:转账重复。
为什么?因为重新点击转账按钮重新发送了请求。
为什么重试会导致重复转账?因为系统没有检查唯一 ID。
根本原因:缺少交易 ID。也就是说,系统没有给每笔转账设置唯一的交易编号,所以无法判断两次请求是不是同一笔交易。
解决方法:添加 ID。这样即使用户点击重试,系统也能识别:这是同一笔转账请求,不应该重复执行。

2.2.4 进阶 RCA

基础 RCA 通过 5 Whys 方法挖掘问题的根本原因。
进阶 RCA 通过 故障树分析(Fault Tree Analysis,FTA)。
FTA (Fault Tree Analysis,故障树分析)用逻辑树和概率来分析故障原因。

FTA 会把一个最终故障放在最上面,比如:系统崩溃
然后往下分解可能原因:

  • 服务器过载;
  • 数据库故障;
  • 网络中断;
  • 代码死循环;
  • 第三方服务失败。

每个原因还可以继续往下分解,并且可以给它们加上发生概率。
这样就能判断哪个原因最可能导致系统故障。

FTA 还可以用贝叶斯推断(Bayesian Inference)来分析。
贝叶斯推断(Bayesian Inference)用统计方法不断修正(refine)我们对原因的判断(guesses)。

2.2.4.1 故障树分析(Fault Tree Analysis,FTA)

故障树分析(Fault Tree Analysis,FTA)是进阶 RCA 里的一种方法,用来系统地分析某个故障是由哪些原因造成的。
FTA 是一种自上而下的(top-down)、演绎式(deductive)的分析方法,用来识别和分析某个具体系统故障的原因。
自上而下(top-down)是因为先从最上面的故障开始,然后一步步往下找原因。
演绎式(deductive)是从一个已知的问题出发,推导出可能导致它的原因。

顶事件放在故障树最上面,下面的分支就是导致这个故障的各种可能原因、子原因和条件。

因此 FTA 是可视化的、逻辑化的、系统化的(visual, logical, and systematic)。

2.2.4.1.1 Fault Tree Analysis(FTA,故障树分析) 的作用

FTA 的目的如下:

  1. 识别系统薄弱点(Identifying Weak Points):通过可视化地展示单个组件的故障如何在系统中传播,FTA 可以帮助工程师找到“单点故障”。
  2. 定量可靠性评估(Quantitative Reliability Assessment):FTA 可以帮助计算顶事件发生的概率。
  3. 确定安全与资源投入的优先级(Prioritizing Safety and Resources):FTA 可以帮助我们判断资源应该投到哪里。
  4. 诊断和故障排查(Diagnostic Troubleshooting):当故障真的发生以后,可以用故障树来检查各个组件的状态,从而定位问题。

总结一下就是 FTA 的作用是帮助我们找出系统薄弱点,计算故障发生概率,决定资源优先投入在哪里,并在故障发生后帮助排查原因。

2.2.4.1.2 FTA(Fault Tree Analysis,故障树分析)具体怎么工作

FTA 的具体步骤如下:

  1. 定义顶事件(Define the Top Event)
  2. 识别原因(Identify Causes)
  3. 使用逻辑门(Use Logic Gates)
  4. 继续向下拆分原因(Break Down Further)
  5. 量化(Quantify)
  6. 分析(Analyze)

前面提到的逻辑门包括两种:

逻辑门意思
OR gate只要其中一个原因发生,顶事件就可能发生
AND gate必须多个原因同时发生,顶事件才会发生

事件也可以进行划分:

  • 顶事件(Top event):故障树最上面的事件,也就是我们最终要分析的主要故障。
  • 中间事件(Intermediate event):中间事件是顶事件下面的原因,但它本身还可以继续被分解。
  • 基本事件(Basic event):基本事件是最底层、不能再继续分解的具体原因。
  • 未展开事件(Undeveloped event):这是一个暂时不继续分析的事件。

下图给出了一个例子。

2.2.4.1.3 识别并量化原因(Identifying and Quantifying the Causes)

在做故障树分析时,我们要找出哪些组件故障、系统问题或操作问题可能导致 Top Event(顶事件)。
设计工程师 / 系统工程师可以从系统结构角度找原因,运维和维护团队可以从真实运行情况、日志和故障现场中提供证据,帮助我们判断哪些原因可能导致顶事件。

设计工程师 / 系统工程师(Design / Systems Engineers):他们负责识别硬件或软件组件之间是如何交互的,并判断哪些组件故障可能导致顶事件。
运维和维护团队(Operations & Maintenance Teams):他们是问题发生后最先响应的人。运维团队可以告诉我们系统实际运行时是什么样的(ground truth,真实情况),而不只是设计文档里写的样子。

到这里我们成功识别了原因(Identifying the causes)。

我们现在开始量化原因(Quantifying the causes)。
可靠性工程师(Reliability Engineers):可靠性工程师会使用历史数据、制造商规格说明,以及 MTBF 来给基本事件分配具体数值。
安全 / 风险管理部门(Safety / Risk Management,HSE):在高风险行业,比如石油天然气或航空业,这些部门负责确保量化后的风险符合监管标准。
数据科学家(Data Scientists)在现代软件环境中,数据分析人员可以通过日志、遥测数据和大量用户会话中的错误率来量化原因。

2.2.4.1.4 计算故障发生概率(Calculate Failure Probabilities)

我们现在通过一个例子来看一下怎么计算故障发生概率(Calculate Failure Probabilities)。

我们先提供几个底层原因的发生概率:

事件中文意思概率/故障率
Server offline服务器离线0.01/hour
Auth failed认证失败0.02/hour
Too many transactions交易太多0.05/hour
No lock timeout没有锁超时机制0.1
No validation没有输入验证0.03

那么现在支付网关失败的概率是多少呢?
支付网关失败的可能有两种:服务器离线 或 认证失败。
因此这里是一个 OR gate(或门)。
因此如果 A 和 B 是两个独立事件:
A = Server offline
B = Auth failed
那么:p(A OR B) = 1 - p(A 不发生 AND B 不发生)
也就是:p(A OR B) = 1 - (1 - p(A)) × (1 - p(B))
代入数字:p(Server offline) = 0.01
p(Auth failed) = 0.02
p(Payment Gateway failed)
= 1 - [(1 - 0.01) × (1 - 0.02)]
= 1 - 0.99 × 0.98
= 1 - 0.9702
= 0.0298/hour

那么我们现在要计算数据库锁死的概率怎么计算呢?
数据库锁死 = 交易太多 AND 没有锁超时机制
这里是 AND gate(与门),表示两个条件要同时发生,才会导致数据库锁死。
所以计算方法是:
p(DB locks) = p(Too many transactions) × p(No lock timeout)
代入数字:
p(Too many transactions) = 0.05/hour
p(No lock timeout) = 0.1
p(DB locks) = 0.05 × 0.1 = 0.005/hour

计算输入崩溃的概率:
输入崩溃 = 没有输入验证 OR 某个未展开事件
但是这个 undeveloped event(未展开事件) 没有给具体概率。
因此:p(Input crash) = 0.03

计算结账失败的概率:
它由三个中间事件导致,就是我们刚刚计算的三个:支付网关失败、数据库锁死、输入崩溃.
这三个之间是 OR gate(或门)。
只要其中任何一个发生,都可能导致结账失败。
所以公式是:
p(Checkout fails)
= 1 - (1 - 0.0298) × (1 - 0.005) × (1 - 0.03)
= 1 - 0.9702 × 0.995 × 0.97
= 1 - 0.9364
= 0.0636/hour

这里或许有人会有问题,为什么计算 OR gate(或门)的时候是 1 减去两者都不发生的概率,而不是直接将这里 事件 A 和 事件 B 的概率相加。
因为对于两个独立事件,有四种情况,事件 A 和 事件 B 都发生;事件 A 发生 但事件 B 不发生; 事件 B 发售 但事件 A 不发生; 事件 A 和 B 都不发生。
OR gate(或门)是只要有一个发生,那么上层事件就会发生,所以这里包含前三种情况。
那么如果我们直接将 事件 A 和 事件 B 的概率相加,这里 事件 A 发生的概率包含事件 A 和 事件 B 都发生;事件 A 发生 但事件 B 不发生两种情况的概率。
事件 B 发生的概率包含事件 A 和 事件 B 都发生;事件 B 发生 但事件 A 不发生两种情况的概率。
所以这里两种情况都发生的概率算了两次,所以不能在这个例子中直接 0.01 + 0.02。
计算“至少一个事件发生”的概率的步骤是:

  1. 先算两个事件都不发生的概率。
  2. 用 1 减去这个结果。

也就是上面计算的过程。

2.2.4.1.5 练习 1

我们现在尝试一个场景:用户无法登录银行 App。
现在我们建立一个 fault tree(故障树),然后计算登录失败的概率。
顶事件:Login fails(登录失败)
它可能由两个原因导致:DB down(数据库宕机)、Auth error(认证错误)。
只要数据库宕机,或者认证错误,用户就可能登录失败。
这是 OR gate(或门)。
数据库宕机可能由两个原因导致:
Power outage(停电),概率是 0.01/hour;
DB crash(数据库崩溃),概率是 0.02/hour。
这里也是 OR gate(或门)。

认证错误需要两个条件同时发生:
Bad credentials(用户凭证错误),比如用户名或密码错误,概率 0.04/hour;
No retry(没有重试机制),概率 0.5。
这里是 AND gate(与门)。

我们先计算 DB down(数据库宕机)的概率:
p(DB down) = 1 - (1 - 0.01) × (1 - 0.02)
= 1 - 0.99 × 0.98
= 1 - 0.9702
= 0.0298/hour
再计算Auth error(认证错误)的概率:
p(Auth error) = 0.04 × 0.5
= 0.02/hour
最后计算登录失败的概率:
p(Login fails)
= 1 - (1 - 0.0298) × (1 - 0.02)
= 1 - 0.9702 × 0.98
= 1 - 0.950796
= 0.049204/hour

2.2.4.1.6 概率数据的“动态”性质(Dynamic Nature)

故障树里有些事件的概率是 随时间发生的故障率,比如“每小时发生多少次”;有些事件则是 没有时间单位的条件概率或状态概率。
所以前者这些是 动态事件,会随着时间发生,所以用 每小时 来表示故障率。后者这些事件是 静态条件,不是按小时发生的。

Dynamic(动态)指的是:
这些事件会随着时间随机发生,不是一直固定存在的状态。
如果一个概率写成 “每小时多少”,比如 0.01/hour,它表示的是故障率(failure rates)。故障率(failure rates)指的是某个故障在一段时间内发生得有多频繁。
故障率被用于:

  • 动态事件:那些随机发生或间歇发生的事件。
  • 基于时间分析的系统:当我们分析系统在一段时间内的行为时,就会用这种动态概率。

在故障树分析中,故障率(failure rate)通常和 MTTF(Mean Time To Failure,平均无故障时间)有关系。
例如:网关服务器离线的故障率是:0.01/hour
那它的 MTTF 就是:MTTF = 1 / 故障率 = 1 / 0.01 = 100 hours

在软件系统中,每小时故障率 通常来自三类数据。

  1. Logs(日志):可以通过历史日志来统计故障率。
    比如:服务器在 500 小时内崩溃了 5 次。
    那么故障率就是:5 / 500 = 0.01/hour。
  2. Metrics(监控指标):可以通过监控系统的数据计算故障或异常发生率。
    比如:在 1000 小时内发生了 50 次流量高峰。
    那么发生率就是:50 / 1000 = 0.05/hour
    也就是说,平均每小时发生 0.05 次流量高峰。
  3. Vendor Specs(供应商规格说明):也可以参考供应商提供的可靠性数据,比如服务器、云服务、数据库服务的可用性说明。
    例如:服务商承诺 99.9% uptime(系统正常运行时间比例)。
    所以可以近似理解为:downtime rate = 0.001
2.2.4.1.7 概率数据的“静态”性质(Static Nature)

概率的静态性质(Static Nature)指的是:这个问题不是随着时间随机发生的,而是系统设计或配置中本来就存在的状态。
没有时间单位的概率是静态概率。它们不是故障率,而是一次性的、没有单位的概率。
适用于:

  • Constant Conditions(固定条件 / 常态条件):有些问题不是运行过程中突然发生的,而是系统本身就存在的缺陷,比如:
    Design flaws(设计缺陷);
    Configuration errors(配置错误);
    Missing features(缺少某个功能)。
  • State-Based Events(状态型事件):静态概率表示某个状态在某一时刻是否成立的可能性,而不是它发生得有多频繁。
    比如:No lock timeout = 0.1
    意思不是“没有锁超时每小时发生 0.1 次”,而是:
    在当前系统设计中,存在“没有设置锁超时”这个问题的可能性是 0.1。
    No validation = 0.03
    意思是“没有输入验证”这个问题存在的概率是 3%。
    这些静态概率 通常来自三个方面:
  1. Code Reviews(代码审查):通过代码审查发现大约 3% 的代码提交缺少输入验证。
  2. Design Audits(设计审计 / 设计检查):通过设计检查或配置审计发现大约 10% 的配置缺少超时设置。
  3. Assumption(假设 / 粗略估计):如果没有足够的数据,就只能根据经验做一个粗略估计。
2.2.4.1.8 概率数据的混合性质(Mixed Nature)

我们前面计算的时候使用的是:
p(Checkout fails) = 1 - (1 - 0.0298) × (1 - 0.005) × (1 - 0.03)
这里默认了所有概率是 同一种类型、可以直接比较和组合的概率。
如果我们细看这里 0.0298 和 0.005 是基于时间的概率 / 故障率。而 0.03 是静态概率。

2.2.4.1.9 示例3

我们现在用一个 视频流媒体 App 卡住/冻结 的例子来说明 动态概率 和 静态概率 混合出现时该怎么理解。

这里的顶事件是视频播放冻结 / 卡住。
下面的原因可能是网络断开、视频编解码器过时。
网络断开是一个基于时间的动态故障率。
过时的视频编解码器是一个非时间型概率。

我们有两种方式解决这里的混合问题。

  1. 把静态概率转换成时间型概率。
    如果有 10% 的系统实例使用了过时的 codec,并且假设在高负载下,这个过时 codec 有一定概率导致播放冻结。
    我们作出假设:每小时有 10% 的概率因为 codec 解码失败而导致视频卡住。
    那么现在两个原因都变成时间型概率:
    Network disconnected = 0.02/hour
    Outdated codec = 0.1/hour
    顶事件是视频播放卡住。
    它们之间是 OR gate。
    所以公式是:
    p(Video playback freeze)
    = 1 - [(1 - 0.02) × (1 - 0.1)]
    = 1 - (0.98 × 0.9)
    = 1 - 0.882
    = 0.118/hour
    我们可以用 MTTF 表示,那就是 MTTF = 1 / 故障率 = 1 / 0.118 ≈ 8.47 小时。
  2. 把静态概率当作条件概率来处理。
    不要强行把静态概率改成 /hour 的故障率,而是把它看成一个前提条件。
    前一种方法把“10% 的概率使用过时 codec”理解成:每小时有 10% 的概率因为 codec 过时导致视频冻结。
    这样做其实有点不严谨。
    0.1 表示系统存在过时 codec 的概率是 10%。
    只有当它和某个触发事件同时出现时,才会导致播放冻结。比如:系统有过时 codec;用户刚好播放了不兼容的视频流。
    因此这里不要把静态概率强行改成每小时概率,而是把它看成一个条件。这个条件需要和某个触发事件同时发生,才会导致故障。
    我们把它拆成两个条件:Incompatible Stream = 0.05/hour 和 Outdated Codec = 0.1。
    所以计算这里的 p(Codec fails) = 0.5 × 0.2 = 0.1/hour
    Video Playback Freeze 的概率:
    p(Video playback freeze)
    = 1 - (1 - 0.02) × (1 - 0.1)
    = 1 - 0.98 × 0.9
    = 1 - 0.9702
    = 0.0298/hour
    约等于:0.03/hour
    那么 MTTF = 1 / 0.03 = 33.3 hours

所以包括我们前面举例的 Checkout Failure(结账失败)的故障树计算。
我们计算的是:p(Checkout fails) = 1 - (1 - 0.0298) × (1 - 0.005) × (1 - 0.03)
= 0.0636/hour
因为 malicious attack(恶意攻击) 是一个 undeveloped event(未展开事件),为了简化计算,暂时不考虑它。
我们现在把 No validation(没有输入验证) 这个静态概率,当作 条件概率 来处理。
更严谨的计算应该是:
p(Input crash) = p(No validation) × p(Bad input occurs)
如果假设:
p(No validation) = 0.03
p(Bad input occurs) = x/hour
那么:
p(Input crash) = 0.03 × x
然后新的结账失败概率是:
p(Checkout fails)
= 1 - (1 - 0.0298) × (1 - 0.005) × [1 - (0.03 × x)]

2.2.4.1.10 练习 2

我们现在分析一个实时聊天 App,最上层故障事件是:用户意外断开连接。
原因有:

  1. 网络掉线:0.03/hour
  2. 服务器崩溃:由两个因素组成,服务器过载,每小时概率 0.04;没有重试机制,概率 0.2。这里是 AND gate。
  3. 客户端 Bug:有两个因素组成,客户端代码 bug,每小时概率 0.02;用户没有更新客户端,概率 0.1。这里是 OR gate。

因此我们计算概率的话,如果使用方法一那么计算如下:
p(Server Crash) =0.04 × 0.2 = 0.008/hour
p(Client Bug)=1−(1−0.02)(1−0.1)
=1−(0.98)(0.9)
=1−0.882
=0.118/hour

那么p(User Disconnects)=1−(1−0.03)(1−0.008)(1−0.118)
=1−(0.97)(0.992)(0.882)
=1−0.84869568
=0.15130432/hour
也就是:用户意外断连概率约为 0.1513/hour,即每小时约 15.13%。
MTTF≈6.61 hours,平均大约每 6.61 小时 会发生一次用户意外断连。

2.3 把 RCA 和 FMEA 连接起来

把 RCA 和 FMEA 连接起来,就是把一次“事后得到的教训”,转化成“以后提前预防的措施”。
RCA 是 reactive:问题发生之后,分析为什么出问题;
FMEA 是 proactive:问题发生之前,提前预测风险并预防。

RCA 可以发现原来不知道的风险。
比如系统上线后才发现一个问题:
数据库发生死锁,系统崩溃了。
这个问题可能之前 FMEA 没有预测到。
RCA 的输出是一个具体的、真实发生过的原因。

把 RCA 的发现更新到 FMEA 文档里。
RCA 做完之后,不是写个报告就结束,而是要把发现的问题加入 FMEA 表格。
这样以后做系统设计、测试和上线检查时,就会提前考虑这个风险。

简单总结一下那就是:RCA 是事后找原因,FMEA 是事前防风险。把 RCA 和 FMEA 连接起来,就是把真实事故中发现的根本原因,补充进 FMEA 表格,让以后类似问题可以被提前识别和预防。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询