<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Resilience on 纪伟的个人博客</title><link>https://www.jiwei.space/tags/resilience/</link><description>Recent content in Resilience on 纪伟的个人博客</description><generator>Hugo -- gohugo.io</generator><language>zh</language><lastBuildDate>Fri, 06 Feb 2026 10:00:00 +0800</lastBuildDate><atom:link href="https://www.jiwei.space/tags/resilience/index.xml" rel="self" type="application/rss+xml"/><item><title>Polly 的前世今生：从 Policy 到 ResiliencePipeline 的韧性范式重构</title><link>https://www.jiwei.space/posts/dotnet/polly-deep-dive/</link><pubDate>Fri, 06 Feb 2026 10:00:00 +0800</pubDate><guid>https://www.jiwei.space/posts/dotnet/polly-deep-dive/</guid><description>&lt;p&gt;在分布式系统里，“调用失败”不是异常，而是常态。网络会抖、依赖会慢、对端会短暂挂掉。如果你的代码只会 &lt;code&gt;try/catch&lt;/code&gt; 然后把异常往上抛，那一次偶发的 503 就会变成一次真实的业务损失——订单失败、请求超时、用户体验坍塌。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Polly&lt;/strong&gt; 就是 .NET 生态用来回答这个问题的答案。它是事实标准的韧性（resilience）框架，把“重试、熔断、超时、降级、限流”这些原本散落各处的容错逻辑，抽象成可组合、可配置、可观测的策略积木。&lt;/p&gt;
&lt;p&gt;但 Polly 在 v8 做了一次近乎重写的范式升级：从“以 &lt;code&gt;Policy&lt;/code&gt; 为中心”迁到“以 &lt;code&gt;ResiliencePipeline&lt;/code&gt; 为中心”。这次重构不是换一套 API 那么简单，而是重新定义了“.NET 应用该如何做韧性工程”。这篇文章我们就把 Polly 的前世今生、七大策略、管线组合、可观测性，以及它背后的设计思想一次讲透。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;顺带：这篇和《HttpClient 的前世今生》是姊妹篇——HttpClient 负责“怎么把请求发出去”，Polly 负责“请求失败了怎么办”，两者在 .NET 8 通过 &lt;code&gt;Microsoft.Extensions.Http.Resilience&lt;/code&gt; 最终合流。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="一为什么需要韧性故障是分布式系统的常态"&gt;&lt;a href="#%e4%b8%80%e4%b8%ba%e4%bb%80%e4%b9%88%e9%9c%80%e8%a6%81%e9%9f%a7%e6%80%a7%e6%95%85%e9%9a%9c%e6%98%af%e5%88%86%e5%b8%83%e5%bc%8f%e7%b3%bb%e7%bb%9f%e7%9a%84%e5%b8%b8%e6%80%81" class="header-anchor"&gt;&lt;/a&gt;一、为什么需要韧性：故障是分布式系统的常态
&lt;/h2&gt;&lt;p&gt;进入具体策略之前，先建立心智模型。分布式系统的故障大致分三类，&lt;strong&gt;每一类需要完全不同的对策&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;故障类型&lt;/th&gt;
 &lt;th&gt;典型场景&lt;/th&gt;
 &lt;th&gt;正确对策&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;瞬时故障&lt;/strong&gt; (transient)&lt;/td&gt;
 &lt;td&gt;网络抖动、短暂 5xx、限流 429&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;重试&lt;/strong&gt;——大概率自愈&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;持续故障&lt;/strong&gt; (sustained)&lt;/td&gt;
 &lt;td&gt;依赖真的挂了、磁盘满了&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;熔断&lt;/strong&gt;——停止徒劳重试，保护下游&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;自身过载&lt;/strong&gt; (overload)&lt;/td&gt;
 &lt;td&gt;自己被打爆、连接池耗尽&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;限流 / 舱壁&lt;/strong&gt;——主动收缩，保住容量&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;如果你对这三类故障用同一招（比如“一律重试三次”），就会在最坏情况下火上浇油：对端已经挂了你还猛重试，把下游彻底压垮，同时耗光自己的线程和连接。&lt;/p&gt;
&lt;p&gt;Polly 的价值正在于此：&lt;strong&gt;它把不同故障对应的策略做成可组合的积木，让你按需拼装&lt;/strong&gt;。理解了这一点，下面的 API 都是好理解的“积木说明书”。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;边界提示：本文讨论的所有策略都挂在&lt;strong&gt;调用方&lt;/strong&gt;一侧——HttpClient 对自己的&lt;strong&gt;出站调用&lt;/strong&gt;做保护，下游服务器并不知情。所以这是“我调别人时给自己加韧性”，与服务端的入站限流 / 降级是两套东西。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="二前世今生v7-到-v8-的范式重构"&gt;&lt;a href="#%e4%ba%8c%e5%89%8d%e4%b8%96%e4%bb%8a%e7%94%9fv7-%e5%88%b0-v8-%e7%9a%84%e8%8c%83%e5%bc%8f%e9%87%8d%e6%9e%84" class="header-anchor"&gt;&lt;/a&gt;二、前世今生：v7 到 v8 的范式重构
&lt;/h2&gt;&lt;p&gt;这是理解现代 Polly 最关键的一节。我们对比两段代码。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;v6/v7：以 &lt;code&gt;Policy&lt;/code&gt; 为中心。&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// v7：每个策略是一个 Policy 对象，手动 wrap 组合&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;retry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Policy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HttpRequestException&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HttpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsSuccessStatusCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitAndRetryAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;breaker&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Policy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HttpRequestException&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CircuitBreakerAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wrapped&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WrapAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;breaker&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 手动组合&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;wrapped&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;它的特征与局限：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;同步 / 异步分裂&lt;/strong&gt;：&lt;code&gt;Policy&lt;/code&gt; 与 &lt;code&gt;PolicyAsync&lt;/code&gt; 是两套世界，泛型 &lt;code&gt;Policy&amp;lt;T&amp;gt;&lt;/code&gt; 又是一套，心智负担重。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结果与异常用不同 API&lt;/strong&gt;：&lt;code&gt;.Handle&amp;lt;&amp;gt;()&lt;/code&gt; 管异常，&lt;code&gt;.OrResult(...)&lt;/code&gt; 管返回值，谓词表达割裂。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;手动 &lt;code&gt;PolicyWrap&lt;/code&gt; 组合&lt;/strong&gt;：顺序靠参数位置，缺乏统一的管线抽象。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;几乎无可观测性&lt;/strong&gt;：重试了几次、熔断是否打开，全靠你自己打日志，韧性是个“黑盒”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置与代码耦合&lt;/strong&gt;：阈值写死在代码里，改配置要重新发布。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;v8：以 &lt;code&gt;ResiliencePipeline&lt;/code&gt; 为中心。&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// v8：管线 + 策略 + 配置对象，结果与异常用统一谓词&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ResiliencePipelineBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HttpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddRetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;RetryStrategyOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HttpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MaxRetryAttempts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Delay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;BackoffType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DelayBackoffType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exponential&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UseJitter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ShouldHandle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;PredicateBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HttpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HttpRequestException&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsSuccessStatusCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddCircuitBreaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CircuitBreakerStrategyOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HttpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FailureRatio&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MinimumThroughput&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;SamplingDuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;BreakDuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;驱动这次重构的有四股力量：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;统一&lt;/strong&gt;：一个 &lt;code&gt;ResiliencePipeline&lt;/code&gt; 同时支持同步/异步、泛型化，策略即插即用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可观测&lt;/strong&gt;：内建 metrics（&lt;code&gt;Polly&lt;/code&gt; meter）与 telemetry，韧性第一次“看得见”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置驱动&lt;/strong&gt;：options 对象 + 校验 + 注册表 + 运行时热更新，配置与代码解耦。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能&lt;/strong&gt;：管线编译一次反复复用，大幅减少每次执行的分配。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以 v8 不是“换个写法”，而是&lt;strong&gt;把韧性从“手写策略”提升为“可运维的工程基础设施”&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="三核心心智strategy-与-pipeline"&gt;&lt;a href="#%e4%b8%89%e6%a0%b8%e5%bf%83%e5%bf%83%e6%99%bastrategy-%e4%b8%8e-pipeline" class="header-anchor"&gt;&lt;/a&gt;三、核心心智：Strategy 与 Pipeline
&lt;/h2&gt;&lt;p&gt;整个 v8 只有两个核心概念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Strategy（策略）&lt;/strong&gt;：单一韧性能力（重试、熔断、超时……），是管线的积木。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pipeline（管线）&lt;/strong&gt;：有序组合的策略链，外层策略包裹内层策略。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;执行模型是经典的“洋葱”，但比一句话更能帮助理解的是它的代码形态。每个策略本质是这样一个函数（伪代码）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ResilienceContext&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ── 下行：调用内层前的准备 / 门禁（启动计时、看熔断状态）──&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;outcome&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 把控制权交给内层&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ── 上行：拿到结果后的决策（重试？记失败？抛超时？）──&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;next()&lt;/code&gt; 就是“内层那一段”：调用 &lt;code&gt;next&lt;/code&gt; = 控制权往内走，&lt;code&gt;next&lt;/code&gt; 返回 = 控制权往回走。整条管线是一摞这样的函数嵌套——&lt;strong&gt;下行做门禁、上行做决策&lt;/strong&gt;，真正的判断几乎都在拿到结果之后。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;顺手认出这个模式：它就是&lt;strong&gt;责任链（Chain of Responsibility）&lt;/strong&gt;——和《设计模式实战（六）》里讲过的 ASP.NET Core 中间件同源。严格说，Polly 是责任链的“装饰器链”变体：经典 GoF 责任链是“某个 handler 处理掉就结束”的单向链；这里是&lt;strong&gt;双向洋葱&lt;/strong&gt;，每个节点都参与（既预处理又后处理），请求一路下到真正的调用、结果再原路返回穿过所有节点。入站中间件、出站 &lt;code&gt;DelegatingHandler&lt;/code&gt;、Polly 管线——同一个模式的三次复用。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;以标准顺序 &lt;code&gt;TotalTimeout( Retry( CircuitBreaker( AttemptTimeout( Exec ) ) ) )&lt;/code&gt;（顺序的讲究见第五节）为例，看一次完整生命周期：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;下行（请求往里走） 上行（结果往外走）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;══════════════════ ══════════════════
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;① 总计时启动 ─┐ ┌─ 总计时释放
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;② 重试 第1次 ─┤ ├─ 重试：要不要再来一次？
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;③ 熔断 看状态(闭?) ─┤ ├─ 熔断：记一笔，要不要开路？
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;④ 单次计时启动 ─┤ ├─ 单次计时释放
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └→ Exec：真正发 HTTP ──────────────→ 结果原路返回 ─┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;两个最能帮你“看透”的认知：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;重试不是“从管顶重来”，而是 Retry 策略在上行阶段重新调用它的内层 &lt;code&gt;next&lt;/code&gt;&lt;/strong&gt;。所以&lt;strong&gt;总计时器跨所有重试持续在跑&lt;/strong&gt;（它在 Retry 外面，只启动一次），而&lt;strong&gt;单次计时器每次重试都重新建&lt;/strong&gt;（它在 Retry 里面）——这正是“总超时在外、单次超时在内”的运行时含义。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;熔断开路时，它在下行就短路&lt;/strong&gt;：状态为开时，熔断策略&lt;strong&gt;根本不调 &lt;code&gt;next&lt;/code&gt;&lt;/strong&gt;，直接返回失败——下游一个请求都收不到。这就是“保护下游”的运行时含义。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;v8 还在底层引入了一个关键抽象：&lt;strong&gt;&lt;code&gt;Outcome&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt;——用“结果对象”统一表达“成功值 / 异常”。过去异常控制流和返回值检查是两条路，现在统一成一条：策略拿到的是 &lt;code&gt;Outcome&amp;lt;T&amp;gt;&lt;/code&gt;，用同一套 &lt;code&gt;ShouldHandle&lt;/code&gt; 谓词决定它算不算“需要处理的故障”。这是 v8 一切简洁性的根基。&lt;/p&gt;
&lt;h2 id="四七大韧性策略"&gt;&lt;a href="#%e5%9b%9b%e4%b8%83%e5%a4%a7%e9%9f%a7%e6%80%a7%e7%ad%96%e7%95%a5" class="header-anchor"&gt;&lt;/a&gt;四、七大韧性策略
&lt;/h2&gt;&lt;p&gt;这是 Polly 的核心武器库。其中重试、熔断、超时是“三大件”，必须吃透；其余四个按场景补充。&lt;/p&gt;
&lt;h3 id="41-重试retry对抗瞬时故障"&gt;&lt;a href="#41-%e9%87%8d%e8%af%95retry%e5%af%b9%e6%8a%97%e7%9e%ac%e6%97%b6%e6%95%85%e9%9a%9c" class="header-anchor"&gt;&lt;/a&gt;4.1 重试（Retry）——对抗瞬时故障
&lt;/h3&gt;&lt;p&gt;最常用，也最容易被滥用。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;退避（backoff）&lt;/strong&gt;：&lt;code&gt;Constant&lt;/code&gt; / &lt;code&gt;Linear&lt;/code&gt; / &lt;code&gt;Exponential&lt;/code&gt; 三种。绝对不要“立即重试”，否则瞬时故障下会形成同步重试风暴。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;必须加抖动（Jitter）&lt;/strong&gt;：&lt;code&gt;UseJitter = true&lt;/code&gt;。给每次退避叠加一个随机量，避免大量客户端在同一时刻集体重试（“惊群效应”）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;精确的谓词&lt;/strong&gt;：&lt;code&gt;ShouldHandle&lt;/code&gt; 决定“什么算可重试”。&lt;strong&gt;不是所有异常都该重试&lt;/strong&gt;——4xx 业务错误重试一百次结果也一样，只会浪费配额。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;必须有上限&lt;/strong&gt;：&lt;code&gt;MaxRetryAttempts&lt;/code&gt; 必须封顶，否则一次失败被放大成 N 倍流量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;幂等性&lt;/strong&gt;：重试 &lt;code&gt;GET&lt;/code&gt; 很安全；重试 &lt;code&gt;POST&lt;/code&gt; 必须带幂等键（Idempotency-Key），否则可能产生重复下单。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="42-熔断circuit-breaker在持续故障下保护下游"&gt;&lt;a href="#42-%e7%86%94%e6%96%adcircuit-breaker%e5%9c%a8%e6%8c%81%e7%bb%ad%e6%95%85%e9%9a%9c%e4%b8%8b%e4%bf%9d%e6%8a%a4%e4%b8%8b%e6%b8%b8" class="header-anchor"&gt;&lt;/a&gt;4.2 熔断（Circuit Breaker）——在持续故障下保护下游
&lt;/h3&gt;&lt;p&gt;当依赖真的挂了，重试只会火上浇油。熔断器的职责是&lt;strong&gt;主动停止调用，给下游喘息&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;三态循环：&lt;strong&gt;Closed（正常）→ Open（熔断，请求直接快速失败，不真正调用）→ Half-Open（试探性放行少量请求）→ 判定恢复则 Closed、否则重新 Open&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;v8 的熔断是&lt;strong&gt;高级实现&lt;/strong&gt;：它基于“采样窗口内的失败率”（&lt;code&gt;FailureRatio&lt;/code&gt; + &lt;code&gt;MinimumThroughput&lt;/code&gt; + &lt;code&gt;SamplingDuration&lt;/code&gt;），而不是简单的“连续失败 N 次”。这更贴近真实流量——偶尔一两次抖动不会误开熔断，但持续的失败率上升会被及时捕捉。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;作用域：熔断是“按下游聚合”的，不是单请求、也不是全 App 一个。&lt;/strong&gt; 这是最容易误解的地方：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;熔断器是&lt;strong&gt;有状态机&lt;/strong&gt;，状态挂在一条 &lt;code&gt;ResiliencePipeline&lt;/code&gt; 实例上，被“经过它的所有调用”&lt;strong&gt;共享&lt;/strong&gt;。失败率是&lt;strong&gt;跨请求聚合统计&lt;/strong&gt;的，不是每个请求自己单独算。&lt;/li&gt;
&lt;li&gt;但粒度是&lt;strong&gt;按下游 / 按 pipeline 隔离&lt;/strong&gt;：你给 &lt;code&gt;OrderApi&lt;/code&gt; 和 &lt;code&gt;InventoryApi&lt;/code&gt; 各配一套，各有各的熔断器，一个挂了不会误伤另一个。绝不该让全 App 共用一个 client/pipeline。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;单个请求的重试触发不了熔断&lt;/strong&gt;：虽然标准顺序下每次重试尝试都会被熔断器记一个采样，但开路有吞吐量门槛（&lt;code&gt;MinimumThroughput&lt;/code&gt;，标准默认要求窗口内至少约 100 次吞吐）+ 失败率门槛（约 10%）。一个请求的几次重试远凑不齐——要开路，得跨请求集体证明“这个下游不行了”。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;和重试对照着看，本质就清晰了：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;/th&gt;
 &lt;th&gt;重试（Retry）&lt;/th&gt;
 &lt;th&gt;熔断（Circuit Breaker）&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;状态&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;无状态&lt;/strong&gt;，每次调用自己循环&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;有状态&lt;/strong&gt;，跨请求共享&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;作用域&lt;/td&gt;
 &lt;td&gt;单次调用内部&lt;/td&gt;
 &lt;td&gt;整条 pipeline（按下游）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;判断依据&lt;/td&gt;
 &lt;td&gt;“这一次”失败 → 再来&lt;/td&gt;
 &lt;td&gt;“一段时间内多次调用”的失败率&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;重试是“单兵作战”，熔断是“全队观察”。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;哲学点：熔断不只是“保护下游不被打爆”，更是“给上游一个快速失败（fail-fast）”——与其让请求挂 30 秒超时，不如毫秒级返回失败，把容量留给其他能成功的请求。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="43-超时timeout给每次调用一个上限"&gt;&lt;a href="#43-%e8%b6%85%e6%97%b6timeout%e7%bb%99%e6%af%8f%e6%ac%a1%e8%b0%83%e7%94%a8%e4%b8%80%e4%b8%aa%e4%b8%8a%e9%99%90" class="header-anchor"&gt;&lt;/a&gt;4.3 超时（Timeout）——给每次调用一个上限
&lt;/h3&gt;&lt;p&gt;没有超时的重试等于无限挂起。Polly 提供两种模式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Optimistic（乐观 / 协作式）&lt;/strong&gt;：通过 &lt;code&gt;CancellationToken&lt;/code&gt; 通知委托“该取消了”。要求被调方响应取消（HttpClient 就响应），&lt;strong&gt;推荐默认&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pessimistic（悲观 / 强制式）&lt;/strong&gt;：用 &lt;code&gt;Task.WhenAny&lt;/code&gt; 强制隔离，即使委托不响应取消也不会无限拖。用于调用无法响应取消的旧代码。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通常配两层：&lt;strong&gt;总超时&lt;/strong&gt;（包住整个重试过程）+ &lt;strong&gt;每次尝试超时&lt;/strong&gt;（包住单次调用）。两层都不可少。&lt;/p&gt;
&lt;h3 id="44-对冲hedging对抗尾延迟"&gt;&lt;a href="#44-%e5%af%b9%e5%86%b2hedging%e5%af%b9%e6%8a%97%e5%b0%be%e5%bb%b6%e8%bf%9f" class="header-anchor"&gt;&lt;/a&gt;4.4 对冲（Hedging）——对抗尾延迟
&lt;/h3&gt;&lt;p&gt;针对 p99 抖动：发出第一个请求，若在 &lt;code&gt;Delay&lt;/code&gt; 内没返回，就&lt;strong&gt;并行&lt;/strong&gt;再发一个，谁先回用谁。在 p99 严重的系统里（想想 Jeff Dean 那张“延迟尾部放大”图），对冲能把慢请求的尾部显著拉平。代价是多打流量，&lt;strong&gt;只适合幂等或廉价的调用&lt;/strong&gt;。它对应 HttpClient 侧的 &lt;code&gt;AddStandardHedgingHandler&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="45-限流rate-limiter控制自身或下游速率"&gt;&lt;a href="#45-%e9%99%90%e6%b5%81rate-limiter%e6%8e%a7%e5%88%b6%e8%87%aa%e8%ba%ab%e6%88%96%e4%b8%8b%e6%b8%b8%e9%80%9f%e7%8e%87" class="header-anchor"&gt;&lt;/a&gt;4.5 限流（Rate Limiter）——控制自身或下游速率
&lt;/h3&gt;&lt;p&gt;基于 &lt;code&gt;System.Threading.RateLimiting&lt;/code&gt;（令牌桶 / 并发限制器）。客户端侧限流，既是保护下游别被自己打爆，也是保护自己别把下游配额用光。&lt;/p&gt;
&lt;h3 id="46-舱壁bulkhead故障隔离与容量保护"&gt;&lt;a href="#46-%e8%88%b1%e5%a3%81bulkhead%e6%95%85%e9%9a%9c%e9%9a%94%e7%a6%bb%e4%b8%8e%e5%ae%b9%e9%87%8f%e4%bf%9d%e6%8a%a4" class="header-anchor"&gt;&lt;/a&gt;4.6 舱壁（Bulkhead）——故障隔离与容量保护
&lt;/h3&gt;&lt;p&gt;限制&lt;strong&gt;并发执行数&lt;/strong&gt;，超出时快速拒绝而非排队堆积。它的核心价值是&lt;strong&gt;隔离&lt;/strong&gt;：把不同依赖放进不同“舱室”，一个慢依赖拖不垮整艘船——避免一个慢下游占满线程池/连接池，导致整个进程假死。&lt;/p&gt;
&lt;h3 id="47-降级fallback优雅失败"&gt;&lt;a href="#47-%e9%99%8d%e7%ba%a7fallback%e4%bc%98%e9%9b%85%e5%a4%b1%e8%b4%a5" class="header-anchor"&gt;&lt;/a&gt;4.7 降级（Fallback）——优雅失败
&lt;/h3&gt;&lt;p&gt;所有策略都兜不住时，返回一个默认值、缓存或兜底逻辑，让用户看到“降级但可用”的结果，而不是刺眼的 500。这是用户体验的最后一道防线。&lt;/p&gt;
&lt;h2 id="五组合管线顺序就是语义"&gt;&lt;a href="#%e4%ba%94%e7%bb%84%e5%90%88%e7%ae%a1%e7%ba%bf%e9%a1%ba%e5%ba%8f%e5%b0%b1%e6%98%af%e8%af%ad%e4%b9%89" class="header-anchor"&gt;&lt;/a&gt;五、组合：管线顺序就是语义
&lt;/h2&gt;&lt;p&gt;策略本身只是积木，&lt;strong&gt;怎么排列它们决定了语义&lt;/strong&gt;。这是 Polly 最容易被用错的地方。.NET 8 标准韧性管线给出的“出厂正确顺序”（由外到内）是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Rate Limiter / Bulkhead ← 入口：先把流量关在门外
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Total Timeout ← 总超时：包住整个重试过程
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Retry ← 重试：处理瞬时故障
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Circuit Breaker ← 熔断：持续故障时让重试快速失败
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Attempt Timeout ← 内层：单次尝试的时限
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;你的业务调用
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;每一层的位置都有理由：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;限流/舱壁在最外&lt;/strong&gt;：在进入任何重试逻辑前先控制并发与速率，防止“重试放大流量”冲垮自己。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;总超时包住重试&lt;/strong&gt;：否则 3 次重试 × 每次挂 30 秒，一个请求能拖 90 秒。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重试在熔断之外&lt;/strong&gt;：每次重试尝试都会经过熔断器；一旦熔断打开，重试会立刻拿到 fast-fail，不真正调用下游，而重试自身的失败计数仍能正常累计。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;每次尝试超时在最内&lt;/strong&gt;：它只约束单次调用，不约束整个重试链。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对冲变体（&lt;code&gt;AddStandardHedgingHandler&lt;/code&gt;）则把“重试 + 熔断 + 单次超时”整体塞进对冲策略的内部，外面包一层总超时。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;这个“顺序敏感的洋葱模型”，和 &lt;code&gt;DelegatingHandler&lt;/code&gt;、ASP.NET Core 中间件完全同构。&lt;strong&gt;理解了管线的语义，就理解了 .NET 一大类框架的设计语言。&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="六配置驱动options-与-registry"&gt;&lt;a href="#%e5%85%ad%e9%85%8d%e7%bd%ae%e9%a9%b1%e5%8a%a8options-%e4%b8%8e-registry" class="header-anchor"&gt;&lt;/a&gt;六、配置驱动：Options 与 Registry
&lt;/h2&gt;&lt;p&gt;v8 把配置从代码里解放出来。options 对象带校验，命名管线集中注册、可热更新：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 在 DI 中集中注册一条命名管线，配置可来自 appsettings 并热更新&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddResiliencePipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;order-api&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddRetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;RetryStrategyOptions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MaxRetryAttempts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;BackoffType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DelayBackoffType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exponential&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UseJitter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddCircuitBreaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CircuitBreakerStrategyOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;FailureRatio&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 取用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ResiliencePipelineProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;DoAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetPipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;order-api&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;好处是：阈值集中在配置里，运维可调；options 在启动时校验，配错了启动就报错而不是上线才暴雷；结合 &lt;code&gt;IOptionsMonitor&lt;/code&gt; 还能运行时热更新。&lt;strong&gt;韧性配置和业务代码彻底解耦。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="七可观测性v8-最大的飞跃"&gt;&lt;a href="#%e4%b8%83%e5%8f%af%e8%a7%82%e6%b5%8b%e6%80%a7v8-%e6%9c%80%e5%a4%a7%e7%9a%84%e9%a3%9e%e8%b7%83" class="header-anchor"&gt;&lt;/a&gt;七、可观测性：v8 最大的飞跃
&lt;/h2&gt;&lt;p&gt;这可能是 v8 最被低估的进步。开启一行 &lt;code&gt;.EnableTelemetry()&lt;/code&gt;，Polly 就会通过 &lt;code&gt;System.Diagnostics.Metrics&lt;/code&gt;（meter 名 &lt;code&gt;Polly&lt;/code&gt;）和结构化日志，把韧性事件全部上报：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;重试了几次、每次因为什么失败；&lt;/li&gt;
&lt;li&gt;熔断器的状态切换（Closed → Open → Half-Open）；&lt;/li&gt;
&lt;li&gt;超时、限流、舱壁拒绝的计数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些指标可以直接进 OpenTelemetry / Prometheus / Grafana 仪表盘。&lt;/p&gt;
&lt;p&gt;为什么这很重要？&lt;strong&gt;看不见的韧性是危险的。&lt;/strong&gt; 一个配错的熔断器可能静默地把一半流量快速失败，而你在告警里只看到“错误率升高”却无从定位。v8 把可观测性作为一等公民，让韧性&lt;strong&gt;可监控、可调优、可归因&lt;/strong&gt;——这是它从“库”升级为“基础设施”的标志。&lt;/p&gt;
&lt;h2 id="八与-httpclient-合流microsoftextensionshttpresilience"&gt;&lt;a href="#%e5%85%ab%e4%b8%8e-httpclient-%e5%90%88%e6%b5%81microsoftextensionshttpresilience" class="header-anchor"&gt;&lt;/a&gt;八、与 HttpClient 合流：Microsoft.Extensions.Http.Resilience
&lt;/h2&gt;&lt;p&gt;回到姊妹篇。.NET 8 的 &lt;code&gt;Microsoft.Extensions.Http.Resilience&lt;/code&gt; 是 Polly v8 与 &lt;code&gt;IHttpClientFactory&lt;/code&gt; 的官方桥梁：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddHttpClient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderApi&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddStandardResilienceHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 一行挂上“总超时 + 重试 + 熔断 + 单次超时”&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;AddStandardResilienceHandler&lt;/code&gt; / &lt;code&gt;AddStandardHedgingHandler&lt;/code&gt; 本质上就是把上面那条标准 v8 管线接进 HttpClient 的 &lt;code&gt;DelegatingHandler&lt;/code&gt; 出站管线。于是你&lt;strong&gt;在工厂和类型化 client 的基础上，免费获得 Polly v8 的全部策略与可观测性&lt;/strong&gt;——两大生态在此统一。这也是为什么现在绝大多数应用不再手写 &lt;code&gt;ResiliencePipelineBuilder&lt;/code&gt;，而是直接用标准 handler。&lt;/p&gt;
&lt;h2 id="九设计思想polly-教会了我们什么"&gt;&lt;a href="#%e4%b9%9d%e8%ae%be%e8%ae%a1%e6%80%9d%e6%83%b3polly-%e6%95%99%e4%bc%9a%e4%ba%86%e6%88%91%e4%bb%ac%e4%bb%80%e4%b9%88" class="header-anchor"&gt;&lt;/a&gt;九、设计思想：Polly 教会了我们什么
&lt;/h2&gt;&lt;p&gt;回头看，Polly 的演进浓缩了几个值得带走的思想：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;“故障是常态，韧性是工程义务”。&lt;/strong&gt; 在分布式系统里，容错不是可选优化，而是基本功。把重试/熔断当业务逻辑的一部分来设计，而不是事后补丁。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“策略即管线，组合优于硬编码”。&lt;/strong&gt; 和 HttpClient、ASP.NET Core 一脉相承——把横向关注点拆成可插拔的策略，按顺序组合，而不是在每个调用点重复 &lt;code&gt;try/catch&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“Outcomes over exceptions”。&lt;/strong&gt; v8 用 &lt;code&gt;Outcome&amp;lt;T&amp;gt;&lt;/code&gt; 统一表达成败，摆脱“用异常做控制流”的旧范式。这是更健康、更易组合的失败模型。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“可观测的韧性”。&lt;/strong&gt; 看不见就调不了。把可观测性内置进框架，让韧性从黑盒变成仪表盘上的一等指标。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“对下游负责”。&lt;/strong&gt; 熔断、限流、舱壁，本质都是“自我约束以保护整个系统”。一个有责任感的客户端，应当主动限制自己，而不是无限重试把下游压垮。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="十决策与避坑清单"&gt;&lt;a href="#%e5%8d%81%e5%86%b3%e7%ad%96%e4%b8%8e%e9%81%bf%e5%9d%91%e6%b8%85%e5%8d%95" class="header-anchor"&gt;&lt;/a&gt;十、决策与避坑清单
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;按故障选策略&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;你遇到的问题&lt;/th&gt;
 &lt;th&gt;用&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;偶发网络抖动 / 短暂 5xx&lt;/td&gt;
 &lt;td&gt;Retry + Jitter&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;依赖持续故障&lt;/td&gt;
 &lt;td&gt;Circuit Breaker&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;请求偶发慢 / p99 高&lt;/td&gt;
 &lt;td&gt;Hedging&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;自己被打爆 / 保护下游配额&lt;/td&gt;
 &lt;td&gt;Rate Limiter&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;一个慢依赖拖垮全盘&lt;/td&gt;
 &lt;td&gt;Bulkhead&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;想给用户兜底体验&lt;/td&gt;
 &lt;td&gt;Fallback&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;任何调用都必须有&lt;/td&gt;
 &lt;td&gt;Timeout&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;常见坑&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;重试风暴：无 jitter + 无退避，瞬时故障下集体同步重试。&lt;/li&gt;
&lt;li&gt;重试不可幂等的 &lt;code&gt;POST&lt;/code&gt; 不带幂等键 → 重复下单。&lt;/li&gt;
&lt;li&gt;有重试、有单次超时，却忘了总超时 → 单请求拖到天荒地老。&lt;/li&gt;
&lt;li&gt;熔断阈值设太敏感（正常抖动就开）或太迟钝（形同虚设）。&lt;/li&gt;
&lt;li&gt;把 4xx 业务错误当成“可重试故障”。&lt;/li&gt;
&lt;li&gt;韧性策略没开 telemetry，上线即黑盒，出事无从定位。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="结语"&gt;&lt;a href="#%e7%bb%93%e8%af%ad" class="header-anchor"&gt;&lt;/a&gt;结语
&lt;/h2&gt;&lt;p&gt;Polly 从一个“重试库”长成了“.NET 韧性工程的基础设施”。v8 的 &lt;code&gt;ResiliencePipeline&lt;/code&gt; 范式重构，让韧性&lt;strong&gt;统一、可配置、可观测&lt;/strong&gt;——这三点，恰恰是生产级分布式系统最需要的。&lt;/p&gt;
&lt;p&gt;当你下一次写出 &lt;code&gt;AddStandardResilienceHandler()&lt;/code&gt; 时，背后是一套经过千锤百炼的韧性工程语言：重试带抖动、熔断保护下游、超时封顶延迟、一切皆可观测。理解了这套语言，你写出的就不再是“能跑的代码”，而是“对下游负责、对自己克制、对故障坦然”的分布式客户端。&lt;/p&gt;</description></item></channel></rss>