Day30-13|9.5.1 软件可靠性测试概述:验证系统在真实运行中的无故障能力

一、教材定位

软件可靠性测试是软件可靠性工程的重要环节。前面的可靠性设计主要通过容错、检错、降低复杂度和系统配置减少故障发生概率、限制故障影响或提高恢复能力,本节则要回答:系统在规定的运行环境、规定的时间和规定的使用方式下,是否确实达到了预期的可靠性目标。

可靠性测试与一般功能测试有联系,但不能等同。功能测试通常关注输入是否得到正确输出,可靠性测试还关注系统经过长时间运行、重复操作、异常注入、负载变化和故障恢复后,是否仍能持续提供正确服务。一个系统可能所有功能用例都通过,却在连续运行数小时后出现内存泄漏;也可能单次请求正确,但在网络抖动、节点重启或消息重复时产生数据不一致。这些问题必须通过面向运行行为的可靠性测试发现。

考试中常见的失分点有三个:一是把可靠性测试写成功能测试的简单重复;二是没有定义运行剖面,测试负载与真实使用不匹配;三是只关注故障率,不说明数据采集、统计模型、通过准则和测试后的改进闭环。

二、可靠性测试的基本概念

1. 测试对象

可靠性测试对象可以是一个组件、服务、子系统或完整系统。对象边界必须明确,因为可靠性指标的含义依赖观察范围。例如,支付接口单独测得的成功率,不能直接代表完整支付流程的可靠性;消息队列本身可用,也不代表消费端不会丢失或重复处理消息。

测试对象还要明确外部依赖。对于依赖数据库、缓存、第三方接口或设备的系统,应说明依赖是使用真实环境、仿真器还是服务虚拟化。否则测试结果可能只反映理想条件,无法说明生产可靠性。

2. 规定条件与规定时间

可靠性不是脱离条件的绝对属性。测试应记录操作系统、硬件规格、网络带宽、数据规模、并发量、版本、配置、依赖状态和运行时长。相同程序在低负载和高负载下的故障率可能完全不同;相同服务在单节点和多节点部署下的恢复行为也不同。

规定时间既可以是连续运行时间,也可以是请求次数、事务数量或任务批次。例如实时服务可以用连续运行 72 小时和累计请求数作为条件,批处理系统可以用连续完成若干批次并覆盖高峰数据量作为条件。时间窗口越短,越难发现低概率和累积性故障。

3. 可靠性故障

可靠性测试中的故障不只包括进程崩溃。常见故障包括:返回错误结果、响应超时、服务不可达、数据丢失、数据重复、状态无法恢复、资源泄漏、性能持续退化、故障切换失败、恢复后业务不一致以及安全控制失效。判定故障时既要看技术结果,也要看业务结果。

应区分故障、错误和失效。错误是系统内部处于不正确状态,故障是错误被激活并影响执行,失效则是系统未能提供规定服务。测试采集这些层次的信息,有助于定位缺陷所在,而不是只记录最终的“请求失败”。

三、可靠性测试与功能、性能测试的区别

测试类型 核心问题 典型关注点 与可靠性测试的关系
功能测试 功能是否按需求工作 输入、输出、业务规则 提供正确性基础,但时间和运行压力通常有限
性能测试 在负载下是否满足性能目标 吞吐量、响应时间、资源使用 提供负载条件,可靠性测试还要关注持续运行和恢复
容错测试 故障发生时能否继续服务 降级、切换、重试、恢复 是可靠性测试的重要组成部分
安全测试 是否能抵御安全威胁 身份、权限、攻击面 安全失效也可能表现为可靠性失效
可靠性测试 在规定条件和时间内能否持续正确服务 故障率、失效率、恢复、数据一致性 综合使用上述测试手段,验证运行质量

功能测试是可靠性的前提,但不是充分条件。性能测试常以短时间达到峰值为目标,可靠性测试则可能要求中等负载下长时间运行,以发现资源积累和状态退化。容错测试通常主动注入故障,可靠性测试还要验证正常运行、异常恢复和恢复后的业务连续性。

四、可靠性测试的目标

1. 发现可靠性缺陷

测试要发现导致服务中断、数据错误、资源泄漏、恢复失败和性能退化的缺陷。尤其应关注低频、高影响和难以复现的问题。对偶发缺陷,应保留请求上下文、节点、配置、时间线和相关日志,不能只记录“偶现失败”。

2. 验证可靠性设计

容错、检错、降级、重试、主备切换、断点续传、幂等和补偿等设计都需要通过测试验证。测试不能只证明“发生故障后程序没有退出”,还要证明服务结果正确、状态一致、恢复时间满足目标,且不会因为重试和切换产生重复副作用。

3. 评估可靠性指标

测试可以为平均无故障时间、平均修复时间、失效率、可用性、故障恢复时间、任务成功率和数据一致性等指标提供数据。指标必须有明确的统计口径,例如是否将用户取消、非法请求和第三方拒绝计入故障,是否把计划停机排除在可用性分母之外。

4. 为可靠性改进提供依据

测试结果应进入缺陷管理、架构改进和运维策略。若某一类故障反复出现,应追溯到设计、实现、配置或流程层,而不是简单增加测试次数。可靠性测试的最终价值不是产生一份报告,而是推动系统降低故障概率和故障影响。

五、可靠性测试的典型过程

第一步:明确目标与判定准则

先把“可靠”转化为可观察目标,例如连续运行 48 小时无严重故障,订单成功率不低于某阈值,故障切换时间不超过目标,恢复后数据差异为零或在规定范围内。没有准则,测试结束时只能凭主观感觉判断通过。

第二步:建立运行剖面

运行剖面描述用户操作、业务事务、输入数据、发生概率和负载变化。测试应按照真实或预期概率生成事务,而不是平均地随机点击所有功能。高频路径、低频高风险路径、批量任务和异常操作都要根据业务重要性分配比例。

第三步:准备环境与初始状态

环境应可重复部署,数据应有基线和清理方案,依赖服务要记录版本和配置。若测试需要故障注入,应先确认注入工具不会改变被测对象的正常逻辑。每轮测试开始前,应保证初始状态可描述、可恢复。

第四步:执行并采集数据

除了成功和失败数量,还要采集故障时间、故障类型、触发场景、恢复时间、资源曲线、日志、链路追踪、数据校验结果和用户影响。高可靠系统的测试数据应同时包含技术维度和业务维度,避免技术指标正常但业务账实不符。

第五步:分析、定位和复测

对故障进行分类和去重,判断是环境问题、测试脚本问题、已知限制还是产品缺陷。修复后要在相同场景复测,并增加回归场景验证没有引入新的问题。对于随机故障,应保存种子、输入和时间线,尽可能把偶发问题转化为可重放问题。

第六步:形成结论和改进闭环

报告中应给出测试条件、样本量、运行剖面、故障统计、指标计算、未解决风险和是否达到目标。未达到目标时,不能用“继续观察”替代处置,应明确责任、改进措施、再次测试时间和放行条件。

六、可靠性测试方法

1. 可靠性增长测试

通过运行、发现故障、修复缺陷和再次运行,使系统可靠性逐步提高。该方法适用于开发和测试阶段,重点在于根据故障趋势判断系统是否在增长。若故障不断暴露但修复无效,说明改进措施或根因分析存在问题。

2. 运行测试

按照真实运行剖面执行大量业务操作,观察规定时间内的故障情况。运行测试强调代表性,输入分布、业务顺序和资源条件应尽量接近实际生产。仅执行边界和极端数据,不能代表正常运行可靠性。

3. 强度测试

逐步增加负载、并发、数据规模或资源压力,研究系统在接近极限时的失效规律。强度测试可以发现容量不足和性能退化,但要注意它不等同于可靠性结论。超过设计边界后的失败不一定表示系统违反可靠性目标。

4. 异常与故障注入测试

主动模拟节点宕机、网络延迟、磁盘满、依赖不可用、消息重复、时钟偏移和数据损坏,验证检错、降级、切换、恢复和补偿。故障注入应有范围、权限、停止条件和回滚方案,不能在没有隔离的生产环境中随意执行。

5. 老化与耐久测试

在较长时间内保持稳定负载,观察内存、句柄、连接、磁盘、缓存、队列和索引等资源是否逐步积累。老化测试特别适合发现内存泄漏、连接未释放、日志膨胀和定时任务叠加等问题。

七、案例分析:订单服务可靠性测试

某电商平台准备上线新的订单服务。功能测试已覆盖下单、支付、取消和退款,但上线试运行后出现高峰期订单状态长时间不一致。调查发现,测试只使用单节点和小数据量,未测试消息重复、支付回调延迟、数据库主备切换和服务重启后的未完成订单。

改进后的可靠性测试首先定义目标:订单核心操作成功率达到目标值,服务连续运行指定时长无严重故障,单节点故障后在规定时间内恢复,恢复后订单状态和支付状态一致。其次建立运行剖面,按真实比例生成浏览、下单、支付回调、取消和查询事务,并加入高峰、低谷和突发流量。再次设计故障场景,包括消息重复、消息乱序、数据库短暂不可用、实例重启、网络延迟和回调超时。每个场景都检查幂等、重试、补偿和最终对账。

测试报告不只记录接口成功率,还要记录订单状态转换错误、重复扣款、未完成订单数量、恢复时间、消息积压和数据差异。若发现订单状态不一致,应定位是状态机、消息处理、事务边界还是补偿任务的问题,并在修复后对同一故障场景进行重放。只有这些证据均满足目标,才可以形成上线建议。

八、综合知识练习

题1

为什么功能测试全部通过,仍然不能说明软件可靠?

参考答案:功能测试通常验证有限输入下的功能正确性,运行时间、负载、故障和恢复场景不足,无法发现资源泄漏、长时间退化、节点故障、网络异常、重复消息和恢复后数据不一致等问题。可靠性测试还要验证规定条件和时间内的持续正确服务。

题2

可靠性测试报告应至少包含哪些内容?

参考答案:应包含测试对象和版本、环境与配置、运行剖面、数据规模和样本量、测试时长、故障定义、故障分类、故障与恢复统计、资源与业务指标、可靠性指标计算、未解决风险、通过准则和改进建议。

题3

如何避免可靠性测试只测“技术可用”而忽略业务正确?

参考答案:建立技术指标与业务指标的双重观测,除响应码、延迟、资源和进程状态外,还要检查订单状态、金额、库存、消息数量和对账结果;在故障切换和恢复后执行端到端业务校验,并明确数据一致性和补偿完成的判定条件。

九、论文写作素材

论文中可以这样表述可靠性测试工作:

“针对传统功能测试无法覆盖长时间运行、异常依赖和恢复一致性的问题,我根据系统实际业务建立运行剖面,明确事务比例、输入数据、负载变化和外部依赖。测试过程中同时采集技术指标和业务指标,设计节点故障、网络延迟、消息重复、数据库切换和资源老化等场景,验证系统的检错、降级、切换、重试、幂等和补偿机制。对发现的故障保留完整上下文,修复后进行原场景重放和回归验证,最终依据故障率、恢复时间、业务成功率和数据一致性判断是否满足可靠性目标。”

写案例时应体现“目标—剖面—场景—数据—判定—改进”的结构,不能只写进行了压力测试和稳定性测试。若题目涉及高可用系统,还要明确故障发生期间和恢复后的业务状态是否正确。

十、今日复盘

  1. 可靠性测试验证的是规定条件和规定时间内持续提供正确服务的能力。
  2. 功能测试是基础,但不能替代长时间、故障、恢复和数据一致性验证。
  3. 测试前必须定义可靠性目标、运行剖面和通过准则。
  4. 测试数据要同时覆盖技术指标、故障信息、恢复信息和业务结果。
  5. 可靠性测试必须形成发现问题、定位根因、修复、重放、回归和改进的闭环。