返回分布式系统与数据链路模块
Distributed Quality / Tutorial 19
稳定性、容灾与故障演练教程
从缓存局部故障继续扩大范围,证明商城在服务、网络、数据库和第三方异常下能够止损、恢复并保持资金数据正确。
9 个章节故障注入 + 恢复验证RTO / RPO / 证据链
01
先定义稳定性,而不是盲目拔服务
业务结果优先一次完整演练闭环
稳态基线成功率与延迟
注入故障单一、可撤销
观察响应检测、隔离、降级
撤销恢复数据对账与复盘
商城故障矩阵
| 故障 | 业务风险 | 通过标准 |
|---|---|---|
| 订单服务宕机 | 新订单无法创建 | 摘除实例;健康实例承接;不产生半单 |
| 网络延迟与丢包 | 超时、重复提交、重试风暴 | 超时预算有效;幂等;重试有上限 |
| 数据库主从切换 | 短暂写失败或读旧数据 | 恢复在 RTO 内;无事务丢失 |
| 支付渠道失败 | 已扣款但订单未确认 | 对账与补偿可追踪,不重复扣款 |
| 对象存储不可用 | 凭证上传失败 | 核心交易不被非核心附件拖垮 |
稳定性不是“永不失败”,而是故障发生时影响范围可控、核心业务有明确退路、数据不被破坏,并能在承诺时间内恢复。
02
把演练写成可停止的实验
先准备再注入演练前
- 限定隔离测试环境、服务、流量和持续时间。
- 确定稳态指标:下单成功率、重复扣款数、P99、消息积压。
- 写明假设、注入方式、负责人和观察人。
- 设置停止条件、回滚操作和数据清理方式。
演练后
- 先撤销故障并确认资源恢复。
- 对账订单、库存、支付和退款。
- 保存指标、日志、Trace 与操作时间线。
- 把暴露的问题转成缺陷、告警或自动化用例。
实验卡示意
hypothesis: 订单服务损失 1 个实例时,下单成功率仍 >= 99.5%
scope: staging / 10% test traffic / 10 minutes
abort: error_rate > 5% for 60s OR duplicate_payment > 0
recovery: remove fault -> wait healthy -> reconcile orders03
演练服务宕机与实例摘除
无半单、可接管用例:当一个订单实例突然宕机时,健康实例应接管请求
- 预热固定测试流量并记录实例分布。
- 只终止一个测试实例,保持其余依赖不变。
- 观察健康检查、负载均衡摘除时间和错误率。
- 对超时请求使用同一幂等键重试。
- 核对订单、库存预占和支付单,确认没有重复或半成品。
- 恢复实例,确认不会一次性消费过期任务造成尖峰。
故障响应时间线
检测
健康检查识别异常
隔离
流量停止进入坏实例
接管
健康实例处理新请求
恢复
补偿并回到稳态
04
注入网络延迟、抖动与丢包
验证超时预算网络故障用例
| 用例标题 | 注入 | 断言 |
|---|---|---|
| 当库存接口延迟 800ms 时,订单服务应在预算内失败或降级 | 延迟 + 抖动 | 超时边界明确,不无限等待 |
| 当支付回调响应丢失时,渠道重试不应重复扣款 | 响应丢包 | 同一回调幂等,订单最终一致 |
| 当消息链路间歇丢包时,事件应重试并可追踪 | 10% 丢包 | 无静默丢失,超限进入死信并告警 |
Toxiproxy 示例(隔离环境)
toxiproxy-cli toxic add inventory --type latency --attribute latency=800 --attribute jitter=100
toxiproxy-cli toxic remove inventory -n latency_downstream超时、重试和熔断要作为组合测试。单看重试成功率,可能掩盖重试风暴对下游造成的二次伤害。
05
验证数据库主从切换
事务与时间窗口先定义两个目标
- RTO:从数据库不可用到商城恢复可接受服务的最长时间。
- RPO:切换后允许丢失的数据时间窗口;订单与支付通常要求接近零。
用例:当主库失效并切换到新主库时,已确认订单不应丢失
- 持续创建带 run_id 的订单并记录提交时间。
- 在授权的测试集群触发主库故障。
- 观察连接重建、写入失败和只读窗口。
- 恢复后按订单号对账数据库、库存和支付流水。
- 检查旧主库回归时不会产生双主写入。
切换验收
| 检查点 | 证据 |
|---|---|
| 可用性 | 错误开始与恢复时间,计算实际 RTO |
| 数据完整性 | 切换前后业务键连续,无已确认事务丢失 |
| 一致性 | 读写分离不会长期读到旧订单状态 |
| 运维动作 | 告警、切换、回切和负责人时间线完整 |
06
控制第三方支付与物流失败
不能控制依赖也能测试支付未知结果的处理
支付请求携带幂等键
渠道超时结果未知
主动查询按流水号确认
补偿对账更新订单或退款
用例:当支付渠道超时但实际扣款成功时,系统应通过查询或对账确认结果
- 使用可编程 Stub 返回超时,同时写入“渠道成功”状态。
- 禁止客户端无新幂等键重复发起支付。
- 验证查询、回调或对账任务把订单推进到 PAID。
- 若超过业务期限,验证自动退款且退款只发生一次。
- 报告必须关联 orderNo、paymentNo、channelNo 与 traceId。
07
验证限流、熔断、降级与恢复
保护核心交易分级保护策略
| 能力 | 商城例子 | 测试重点 |
|---|---|---|
| 限流 | 活动入口限制瞬时请求 | 返回可识别状态;不误伤支付回调 |
| 熔断 | 库存依赖持续失败后快速失败 | 阈值、半开探测、恢复正确 |
| 降级 | 暂时关闭推荐与评价 | 核心下单仍可用;页面明确提示 |
| 排队 | 秒杀请求进入有界队列 | 队列满时快速拒绝;不超卖 |
| 恢复 | 依赖正常后逐步放量 | 避免同时重试形成恢复风暴 |
用例标题示例
当库存服务连续失败触发熔断时,商城应停止无效调用,并在半开探测成功后逐步恢复。
08
用真实恢复证明备份可用
备份存在不等于能恢复备份恢复演练步骤
- 选取隔离恢复环境,记录备份版本、时间点、加密和保留策略。
- 恢复数据库与必要对象存储,不覆盖当前环境。
- 执行结构校验、行数与控制总额对账。
- 抽取订单—支付—退款链路做业务级验证。
- 测量实际 RTO/RPO,检查密钥、权限和应用连接。
- 销毁临时恢复环境前保存脱敏证据。
业务对账示意
SELECT COUNT(*) AS orders, SUM(pay_amount) AS paid
FROM orders
WHERE created_at < :restore_point;
-- 与支付流水控制总额、退款累计金额交叉核对不要用“备份任务成功”替代恢复测试。只有把备份恢复成可运行、可查询、业务关系正确的数据,才证明恢复能力存在。
09
完成一次可审计的故障演练
练习与清单练习
- 为商城交易链列出服务、网络、数据库和第三方四类故障。
- 为每类故障写稳态指标、注入方式、停止条件和恢复步骤。
- 执行一次单实例宕机和一次 800ms 延迟实验。
- 完成订单、库存、支付、退款对账并计算 RTO/RPO。
- 写复盘:假设是否成立,哪道防线失效,下次如何自动验证。
安全
- 范围隔离
- 操作可撤销
- 停止条件明确
- 负责人在线
证据
- 基线已保存
- 指标日志 Trace 齐全
- 业务 ID 可串联
- 恢复时间可计算
收尾
- 故障已撤销
- 数据已对账
- 资源回到基线
- 改进项有负责人