韧性模式Skill resilience-patterns

此技能专注于在分布式系统中实现韧性模式,包括断路器、重试策略、舱壁隔离等,以优雅地处理故障、防止级联失败并确保系统可用性。关键词:韧性模式、断路器、重试、舱壁、超时、回退、负载脱落、优雅降级、健康检查。

架构设计 0 次安装 0 次浏览 更新于 3/11/2026

name: 韧性模式 description: 用于实现断路器、重试、舱壁或其他韧性模式。涵盖分布式系统的故障处理策略。 allowed-tools: 读取, 全局搜索, 文本搜索

韧性模式

用于构建能够优雅处理故障、优雅降级和自动恢复的系统的模式。

何时使用此技能

  • 实现断路器
  • 设计重试策略
  • 使用舱壁隔离故障
  • 构建容错系统
  • 处理级联故障

为什么韧性重要

在分布式系统中,故障不是例外——而是常态。

网络会失败。服务会崩溃。数据库会超时。
问题不是如果,而是何时。

韧性 = 能够优雅地处理故障

目标:
- 防止级联故障
- 优雅降级
- 自动恢复
- 保持可用性

核心韧性模式

1. 重试模式

什么:自动重试失败的操作
何时:瞬态故障(网络波动、暂时不可用)

简单重试:
┌─────────┐     ┌─────────┐     ┌─────────┐
│ 请求 │────►│ 失败 │────►│ 重试 │───► 成功
└─────────┘     └─────────┘     └─────────┘

使用退避:
请求 → 失败 → 等待 100ms → 重试
                失败 → 等待 200ms → 重试
                       失败 → 等待 400ms → 重试
                              失败 → 放弃

退避策略:
- 固定:每次重试等待相同时间
- 线性:100ms, 200ms, 300ms...
- 指数:100ms, 200ms, 400ms, 800ms...
- 指数 + 抖动:添加随机性以防止惊群效应

重试最佳实践

做:
- 添加抖动以防止惊群效应
- 设置最大重试次数
- 使用指数退避
- 仅重试瞬态故障
- 记录重试以提高可见性

不做:
- 盲目重试非幂等操作
- 重试客户端错误(400s)
- 无限重试
- 对所有重试使用相同延迟

2. 断路器模式

什么:暂时停止调用失败的服务
何时:服务持续失败

状态:
┌──────────────────────────────────────────────────────────┐
│                                                          │
│   ┌────────┐    失败     ┌────────┐    超时       │
│   │ 关闭 │─────────────►│ 打开 │─────────────┐    │
│   │        │                │        │             │    │
│   └────┬───┘                └────────┘             │    │
│        │                         ▲                 │    │
│        │                         │                 ▼    │
│        │  成功           失败          ┌────────┐ │
│        └────────────────────────────────────►│ 半开 │ │
│                                 成功      │        │ │
│                              ◄───────────────┴────────┘ │
│                                                          │
└──────────────────────────────────────────────────────────┘

关闭:正常操作,请求通过
打开:失败超过阈值,快速失败
半开:测试服务是否恢复

断路器配置

关键参数:

失败阈值:多少失败后打开
- 太低:轻微问题就打开
- 太高:保护不足
- 典型:5-10次失败或50%错误率

超时(打开持续时间):保持打开多久
- 太短:可能太快重试
- 太长:恢复慢
- 典型:30-60秒

成功阈值:从半开关闭所需的成功次数
- 典型:1-3次成功请求

3. 舱壁模式

什么:隔离组件以包含故障
何时:防止一个故障拖垮整个系统

船类比:
┌─────────────────────────────────────────────┐
│ 无舱壁的船                     │
│  ┌───────────────────────────────────────┐  │
│  │ 一个洞 → 整艘船进水         │
│  └───────────────────────────────────────┘  │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ 有舱壁的船                        │
│  ┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐   │
│  │      │  │  X   │  │      │  │      │   │
│  │ 正常 │  │进水│  │ 正常 │  │ 正常 │   │
│  └──────┘  └──────┘  └──────┘  └──────┘   │
│ 一个舱室进水,其他保持干燥    │
└─────────────────────────────────────────────┘

舱壁实现

线程池隔离:
┌────────────────────────────────────────────────────────┐
│ 应用程序                                            │
│                                                        │
│  ┌─────────────────┐  ┌─────────────────┐            │
│  │ 服务A 池  │  │ 服务B 池  │            │
│  │ [10 线程]    │  │ [10 线程]    │            │
│  └────────┬────────┘  └────────┬────────┘            │
│           │                    │                      │
│           ▼                    ▼                      │
│      服务 A             服务 B                  │
│      (慢)                (健康)                  │
└────────────────────────────────────────────────────────┘

服务A慢不会耗尽服务B的线程

信号量隔离:
- 限制每个依赖的并发请求
- 比线程池更轻量
- 适合异步操作

4. 超时模式

什么:限制操作等待时间
何时:始终(每个外部调用都需要超时)

无超时:
请求 → 服务挂起 → 调用者永远等待 → 资源耗尽

有超时:
请求 → 服务挂起 → 5秒后超时 → 调用者处理失败

超时类型:
- 连接超时:建立连接的时间
- 读取超时:接收响应的时间
- 总体超时:允许的总时间

超时最佳实践

设置超时:
- 连接:1-5秒(快速失败)
- 读取:基于p99延迟 + 缓冲
- 总体:连接 + 读取 + 处理之和

例子:
连接超时:2s
读取超时:10s(p99是5s,2倍缓冲)
总体超时:15s

级联考虑:
如果A调用B调用C:
- C超时 < B超时 < A超时
- 每层有重试缓冲

5. 回退模式

什么:当主要失败时提供替代方案
何时:有降级但可接受的替代方案

回退选项:
┌────────────────────────────────────────────────────────┐
│ 主要失败?选项:                                │
│                                                        │
│ 1. 缓存数据:返回陈旧但有效的数据           │
│ 2. 默认值:返回安全默认值                 │
│ 3. 降级服务:减少功能性            │
│ 4. 替代服务:不同提供者            │
│ 5. 优雅错误:友好错误信息             │
└────────────────────────────────────────────────────────┘

例子:
主要:实时价格服务
回退1:缓存价格(< 5分钟旧)
回退2:最后已知价格带警告
回退3:"价格暂时不可用"

6. 速率限制模式

什么:控制请求速率
何时:保护服务免受过载

客户端速率限制:
- 限制发出请求
- 防止压垮依赖

服务器端速率限制:
- 限制进入请求
- 防止流量峰值

参见:rate-limiting-patterns技能获取详情

模式组合

典型韧性堆栈

请求流:
┌─────────────────────────────────────────────────────────┐
│                                                         │
│  ┌────────────┐                                        │
│  │  超时   │ ← 总体请求超时              │
│  │ ┌────────┐ │                                        │
│  │ │ 重试  │ │ ← 使用指数退避            │
│  │ │┌──────┐│ │                                        │
│  │ ││断路器││ ← 如果服务关闭则快速失败            │
│  │ ││      │  │                                        │
│  │ │└──────┘│ │                                        │
│  │ │┌──────┐│ │                                        │
│  │ ││舱壁│ ← 与其他调用隔离             │
│  │ │└──────┘│ │                                        │
│  │ └────────┘ │                                        │
│  └────────────┘                                        │
│         │                                              │
│         ▼                                              │
│   ┌──────────┐                                         │
│   │  服务  │                                         │
│   └──────────┘                                         │
│         │                                              │
│   失败?──────► 回退                             │
│                                                         │
└─────────────────────────────────────────────────────────┘

应用顺序

从外到内:

1. 超时:总体时间限制
2. 重试:从瞬态故障尝试恢复
3. 断路器:停止调用失败服务
4. 舱壁:将此调用与其他隔离
5. [调用服务]
6. 回退:优雅处理失败

负载脱落

什么是负载脱落?

当系统过载时:
- 接受能处理的
- 优雅拒绝其余
- 更好地为一些用户服务好,而不是所有用户差

基于优先级脱落:
- 高优先级:从不脱落
- 中:中等负载时脱落
- 低:首先脱落

实现

方法:

1. 基于队列:
   - 固定大小队列
   - 队列满时拒绝
   - 基于优先级服务

2. 基于速率:
   - 每秒最大请求数
   - 超时时拒绝
   - 返回503或429

3. 自适应:
   - 监控延迟/错误率
   - 随着压力增加减少接受
   - 随着系统稳定恢复

优雅降级

降级级别

级别0:完全功能性
└── 一切正常

级别1:禁用非必要功能
└── 推荐关闭,分析延迟

级别2:减少功能性
└── 只读模式,仅缓存数据

级别3:最小功能性
└── 仅核心功能,无个性化

级别4:维护模式
└── 静态页面,"很快回来"

过渡:
基于系统健康指标自动
或通过功能标志手动

功能降级例子

高负载时的电子商务:

完整功能:
- 实时库存
- 个性化推荐
- 实时聊天支持
- 详细分析

降级:
- 缓存库存(5分钟延迟)
- 通用推荐
- 仅联系表单
- 分析排队

最小:
- 静态"有货"状态
- 无推荐
- 仅邮件支持
- 分析丢弃

健康检查

健康检查类型

1. 存活检查:
   "进程是否存活?"
   - 简单ping
   - 如果运行返回200
   - 用于重启决策

2. 就绪检查:
   "能否处理流量?"
   - 检查依赖
   - 如果就绪返回200
   - 用于负载均衡器

3. 深度健康检查:
   "一切是否正常?"
   - 全面检查
   - 可能较慢
   - 用于监控/调试

健康检查最佳实践

做:
- 保持存活检查简单快速
- 在就绪检查中检查所有关键依赖
- 在响应中包含版本/构建信息
- 返回适当状态码

不做:
- 在存活检查中阻塞依赖
- 在健康检查中包含重操作
- 暴露敏感信息
- 忘记处理依赖超时

测试韧性

如何测试

1. 单元测试:
   - 隔离测试每个模式
   - 模拟失败
   - 验证行为

2. 集成测试:
   - 测试模式组合
   - 注入失败
   - 验证恢复

3. 混沌工程:
   - 在生产类似环境中测试
   - 随机失败
   - 验证系统行为

参见:chaos-engineering-fundamentals技能

实现考虑

库 vs 自定义

库(推荐):
- Polly (.NET)
- Resilience4j (Java)
- Hystrix (Java, 已弃用)
- go-resilience (Go)

好处:
- 经过实战检验
- 文档齐全
- 社区支持
- 内置指标

自定义实现:
- 仅当特定需求时
- 高维护负担
- 细微错误风险

监控韧性

跟踪指标:

断路器:
- 状态变化
- 打开持续时间
- 失败率

重试:
- 重试次数
- 重试成功率
- 最终成功/失败

舱壁:
- 并发调用
- 拒绝
- 队列深度

超时:
- 超时次数
- 延迟分布

最佳实践

1. 每个外部调用都需要超时
   没有调用应该永远等待

2. 仅重试瞬态失败
   不要重试400错误

3. 每个依赖一个断路器
   不同服务需要不同保护

4. 舱壁关键路径
   隔离重要与不重要

5. 计划回退
   知道失败时该做什么

6. 监控一切
   无法修复看不见的东西

7. 测试失败路径
   快乐路径测试不够

相关技能

  • chaos-engineering-fundamentals - 测试韧性
  • distributed-transactions - 处理事务中的失败
  • rate-limiting-patterns - 控制请求速率