电路断路器和退化
Circuit Breaker(CB)是一种保护模式,可中断对降级依赖性的调用,以本地化故障并保护apstream服务和用户。降解(graceful degradation)-在资源不足或出现故障(例如,返回缓存/不完整数据、禁用"昂贵"信息)的情况下,有意识地简化功能,而无需完全集中。
主要目标是通过控制故障而不是级联下降来保持SLO和用户体验。
1)何时应用
成瘾是不稳定的:p95/p99的增长,taymout,错误的答案。
具有严格限制/penalti的外部API。
"沉重"的后端(搜索,咨询,报告),其中撤退加剧了风暴。
高度拥挤的区域,有池枯竭的风险(连接,treds)。
2) CB状态和过渡
经典三驾马车:1.Closed-流量正在发生,错误/潜伏度度量被计算在内。
2.Open-呼叫立即被拒绝(失败快)和/或转换为后退。
3.Half-Open-有限数量的"试用"请求决定是否关闭开关。
打开触发器
每个窗口的错误/定时阈值(例如,≥后者N的50%)。
潜伏阈值(例如p95>目标值)。
组合策略(错误∧超时)。
保留时间(cool-down)
固定(例如10-60秒)或自适应(重复触发时的指数增加)。
3)Taymauts,Retrai和Jitter
Taymauts始终比Apstrim的SLO短,并且在链条上保持一致(截止日期)。
Retrai仅用于等效操作;在大多数情况下,1-2次尝试就足够了。
Backoff+jitter (full jitter)可防止同步重复波。
Hedging(备用查询)-经济且仅适用于非常关键的阅读。
4)Bulkhead绝缘和"保险丝"
按域和流量类型(VIP、背景任务、公共API)划分连接/操作员/队列池。
Caps on concurrency for"昂贵"操作。
接管控制:当队列溢出时,执行前容易发生故障。
5)倒退和退化场景
备选方桉
缓存/堆栈响应:"stale-wile-revalidate",从缓存L2/L3返回数据。
只读:单元写作/命令,允许安全读取。
代孕答复:数据不完整(例如,没有建议/化身)。
功能禁用:暂时隐藏非关键小部件/小部件。
Feature flags:快速改变行为而不发布。
规则
Fallback必须具有确定性,快速且数据安全。
在Log/Trace/度量标准中明确标记退化路径。
6)优先级和流量分流
VIP/有偿计划-赤字的更大优先级/配额。
利率极限和throttling减轻了退化依赖性的负担。
Shed load:在稳定之前,质量温和下降(例如,结果较少、图像精简)。
7)可观察性和信号
CB度量
状态(closed/open/half-open)和状态持续时间。
由于以下原因导致的故障比例:CB开放,计时,5xx,retry-exhausted。
p95/p99在断路器之前和之后潜伏。
通过后退查询的Kol vo/分数。
Tracing
Spans注释:"circuit=opened","fallback=cache","admission=denied"。
与限制(429/RateLimit-)、队列和连接子弹的相关性。
Logi/审计
打开或关闭的原因、阈值、依赖项ID。
8)合同和协议
HTTP
失误:"503 Service Unavailable"带有"Retry-After"(或限制为"429")。
Partial content/Steal: '200'/'206'带有降解元数据(例如'X-Degraded: true')。
缓存策略:"缓存控制:stale-if-error,stale-wile-revalidate"。
gRPC
"UNAVAILABLE","DEADLINE_EXCEED",客户端/代理保单上的转义语义。
查询上下文中的最后期限/时间;沿着链条传播截止线。
相似性
用于POST操作的"Idempotency-Key",边界重复数据消除。
9)类型实现(伪代码)
pseudo onRequest(req):
if circuit. isOpen(dep):
return fallbackOrFail(req)
with timeout(T):
try:
resp = call(dep, req)
circuit. recordSuccess(dep, latency=resp. latency)
return resp except TimeoutError or 5xx as e:
circuit. recordFailure(dep)
if circuit. shouldOpen(dep):
circuit. open(dep, coolDown=adaptive())
return fallbackOrFail(req)
半开放样本
pseudo onTimer():
if circuit. state(dep) == OPEN and coolDownExpired():
circuit. toHalfOpen(dep)
onRequestHalfOpen(req):
if circuit. allowTrial (dep): # e.g. 1 try: call -> success => close catch: reopen with longer coolDown else:
return fallbackOrFail(req)
10)设置阈值
观察窗口:滑动N秒/查询。
错误阈值:窗口中的20-50%(取决于配置文件)。
潜伏阈值:p95 ≤目标SLO(例如300-500 ms);超额计为CB的"错误"。
自适应cool-down:重复触发时为10 s → 30 s → 60 s。
11)测试和溷乱做法
溷乱:注入潜伏期/错误,DNS故障,丢弃数据包。
Game days:在类似弹簧的环境中启动"打开"断路器,验证后退。
金丝雀:首先为1-5%的流量启用SV/降级策略。
SLO预算:允许实验,直到错误预算用尽。
12)与多重性集成
CB状态可以根据负载配置文件来存储per-dependency per-tenant(对于嘈杂的租户)或全局存储。
Fallback数据和缓存按"tenant_id"分段。
优先事项/配额-根据计划(VIP不应受到Starter行为的影响)。
13)售前支票清单
- Taymauts和截止日期是直通和一致的。
- Retrai是有限的,仅用于偶数操作,具有backoff+jitter。
- CB阈值由负载测试数据证明。
- Fallback路径存在,快速且安全;定义了策略缓存。
- Bulkhead隔离:分离池/队列/限制。
- 度量/跟踪器/logi标记降解和CB状态。
- 响应合同文档(HTTP/gRPC)以及标题/代码示例。
- 混沌场景和游戏日定期进行;有一个运行手册。
14)典型错误
没有taymauts → retrai"靠边"和级联下降。
单个全局CB代替选择性(通过结束点/方法)是额外的故障。
开放式断路器→"空白"屏幕代替降级的UX。
没有抖动的retrai →同步的查询风暴。
在短暂的故障中长时间冷静下来,在持续的情况下过短是"翻转"状态。
缺少bulkhead是共享池和"线头块"的耗尽。
15)快速选择策略
高度重要性读数:CB+Steil Response Cache+Hedging(经济)。
记录/付款:严格的taymauts,最少的retrais,idempotency keys,没有"肮脏"的倒退。
外部API:具有激进阈值的CB,自适应冷却下降,严格的旋转。
脉动负载微服务:bulkheads,caps on concurrency,VIP优先级。
结论
电路破坏者和托管退化是体系结构的"保险":它们将混乱的拒绝转化为可预测的行为。清晰的taymauts,有限的jitter中继器,孤立的池,精心设计的后退路径和遥测技术使系统具有抗故障依赖性,即使在高峰和紧急时期也能保持SLO。