mcpField
A
arch-circuit-breaker

arch-circuit-breaker

github.com/yonatankarp开发139 次安装23 周前更新
代码仓库

关于 arch-circuit-breaker

面向软件架构的技能,介绍如何保护服务免受故障或缓慢依赖项影响。内容涵盖断路器,以及超时、舱壁隔离、带退避和抖动的重试与备用方案,并说明这些模式的适用场景。

主要功能

  1. 01断路器的关闭、开启与半开启状态
  2. 02超时和舱壁隔离指导
  3. 03带退避与抖动的重试
  4. 04备用方案策略考量
  5. 05故障阈值与冷却时间
  6. 06韧性库参考

适用场景

  1. 01防止慢调用耗尽线程
  2. 02保护服务免受下游故障影响
  3. 03选择重试和超时行为
  4. 04规划服务降级时的备用方案

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yonatankarp/software-design-skills --skill arch-circuit-breaker

安装后在 Claude Code 中输入/arch-circuit-breaker确认已加载。

详细介绍

一句话概述

暂时停止调用故障依赖项,让它有时间恢复,也避免你的服务被超时拖垮。配合使用隔舱(按依赖项隔离资源)、带退避的重试(应对暂时性故障)和超时(限定故障窗口),即可构建完整的弹性方案。

何时使用此技能

  • 服务间调用(REST、gRPC、消息代理),下游可能发生故障或变慢。
  • 可能出现性能退化的外部依赖项(数据库、第三方 API、支付服务商)。
  • 任何一个缓慢的依赖项都可能引发连锁故障的系统:线程被阻塞、线程池耗尽,服务停止接受请求。
  • 任何你原本会写下“我只要一直重试,直到成功就行”的场景——这会引发你即将造成的连锁故障。

何时不使用此技能

  • 所有依赖项都在进程内——没有需要防范的网络故障模式。
  • 应直接向调用方传递的简单同步故障——断路器会隐藏故障,而这并不总是理想的。
  • 总体调用量很低,缓慢的调用不会引发连锁故障——运维开销大于收益。

核心内容

断路器。 包装依赖项调用的状态机:

  • 关闭——调用正常通过。在滑动窗口中统计故障次数。故障超过阈值时,转为打开状态。
  • 打开——调用快速失败,不触及依赖项。冷却时间结束后,转为半开状态。
  • 半开——少量探测调用可以通过。若调用成功,转为关闭状态;若失败,则返回打开状态。

断路器通过在本地吸收故障来防止连锁故障。调用方会快速失败(返回回退结果或错误),而不是不断堆积在缓慢的调用上。

隔舱。 按依赖项隔离资源,避免一个有问题的邻居拖垮其他部分。例如:为每个下游服务使用单独的线程池,为每个数据库使用单独的连接池。该概念源自船体分舱设计,可避免一个舱室破损就导致整艘船沉没。

超时。 每次远程调用都必须设置超时。没有超时时,缓慢的依赖项会耗尽发起调用的线程/协程,并引发连锁故障。将超时设为有限且保守的值——快速失败并重试,总比无限等待好。

带退避和抖动的重试。

  • 重试:发生暂时性故障时再次尝试。
  • 退避:在重试之间等待(通常采用指数退避:100ms、200ms、400ms、800ms……)。
  • 抖动:随机化等待时间,避免大量重试同时发生并冲击正在恢复的依赖项。

只应针对暂时性错误(超时、5xx、连接被拒绝)进行重试。绝不要针对 4xx 重试——这是永久性的客户端错误。

回退。 依赖项不可用时,返回有用的内容,而不是错误。可以是缓存值、默认值或“服务降级;仅返回部分数据”。回退策略是产品决策,不应设为默认行为——应审慎选择。

库。 不要自己实现。JVM:Resilience4j。.NET:Polly。Node:opossum。它们都能将上述模式组合成可配置的弹性管道。

决策启发

  • 每次远程调用都应先设置超时,然后使用断路器,再配置隔舱。预期会遇到暂时性故障时,再添加重试。
  • 故障阈值:要足够低,能快速响应;也要足够高,能吸收随机故障。可从 20 次调用中失败率达到 50% 开始,再据此调整。
  • 冷却时间:对于偶尔出现故障、但本身健康的依赖项,设为几十秒;对于需要人工干预的依赖项,设为几分钟。
  • 重试时始终加入抖动。同步重试会引发惊群效应。
  • 回退是产品决策。团队的 PM 应了解“降级模式”的具体表现。

反模式

  • 没有超时。 调用一直挂起会耗尽线程池。这是导致级联故障最常见的原因。
  • 重试时不采用退避策略。 会立即加重已不堪重负的依赖项的负载。
  • 遇到 4xx 时重试。 永久性错误反复重试,造成持续的资源争用。
  • 断路器阈值针对了错误的维度。 故障率是按时间窗口计算的;脱离窗口背景的原始故障计数毫无意义。
  • 断路器没有回退方案。 开启状态意味着“快速失败”,但如果调用方没有备用方案,你只是给故障换了个名字。
  • 手写断路器。 Resilience4j / Polly 多年来已处理好各种边界情况。不要自己实现。

另请参阅

  • arch-microservices — 服务之间必须使用断路器。
  • arch-saga — 调用其他服务的 Saga 步骤需要这种保护。
  • arch-event-driven — 故障模型不同;断路器模式适用于同步调用。
  • kp-structured-concurrency — Kotlin 的 withTimeout 可为进程内协程代码处理超时问题。

参考资料

  • Michael Nygard,《Release It!》(Pragmatic Bookshelf)——弹性模式的权威著作;断路器概念最早在此书中提出。
  • Richards & Ford,《Fundamentals of Software Architecture》中关于微服务和分布式架构的章节。
  • Resilience4j 文档——具体实现的参考资料。

评论

支持 Markdown