使用 Polly 构建弹性 .NET 应用程序
Source: Dev.to
现代应用很少是孤立的。它们不断与数据库、第三方 API、微服务和云资源进行通信。
因此,失败不是异常——而是预期。
瞬时网络问题、临时服务中断或短暂的超时,如果不考虑弹性,极易导致本来设计良好的系统出现故障。
在本文中,我们将探讨:
- 软件系统中 resilience 的含义
- 常见的弹性模式
- 如何在 .NET 中使用 Polly 实现 Retry 和 Circuit Breaker 模式
什么是软件系统的弹性?
弹性是指应用程序能够:
- 优雅地处理故障
- 自动从瞬时问题中恢复
- 保持可用性和响应性
当出现问题时,弹性系统不会崩溃或阻塞用户,而是适应并继续运行。可以把弹性机制看作 安全网——在不可避免的故障发生时捕获你的应用程序。
理解瞬态故障
瞬态故障 是一种临时性问题,通常在短时间后自行解决。常见示例包括:
- 临时网络故障
- API 超时
- 短暂的数据库连接失败
- 云服务限流
这些故障 不应视为永久性错误。在短暂延迟后重试操作通常会成功。
重试模式
什么是重试模式?
重试模式 会在放弃之前,自动重新执行失败的操作,次数有限。
何时应该使用重试?
- 网络调用
- 外部 API
- 消息队列
- 云资源
何时不 使用重试?
- 验证错误
- 身份验证失败
- 业务规则违规
使用 Polly 的重试示例
var retryPolicy = Policy
.Handle<HttpRequestException>()
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: attempt => TimeSpan.FromSeconds(2),
onRetry: (exception, timeSpan, retryCount, context) =>
{
Console.WriteLine($"Retry {retryCount} after {timeSpan.TotalSeconds}s");
});
此代码的作用
- 将请求重试最多 3 次
- 每次重试间隔 2 秒
- 仅在出现
HttpRequestException时进行重试
这种方式可以显著提升对瞬时故障的成功率,同时不影响用户体验。
电路断路器模式
电路断路器解决的问题
想象调用一个完全宕机的第三方服务:
- 请求持续失败
- 线程被阻塞
- 系统资源耗尽
- 故障在系统中蔓延
这就是小故障如何演变成系统级宕机。
什么是电路断路器?
电路断路器 防止应用执行可能会失败的操作。它的工作方式类似于电气断路器:
- 检测重复失败
- 暂时停止发送请求
- 让系统恢复
电路断路器状态
| 状态 | 描述 |
|---|---|
| Closed | 请求正常流通。 |
| Open | 请求被立即拒绝(快速失败)。 |
| Half‑Open | 允许有限数量的测试请求以检查恢复情况。 |
使用 Polly 的电路断路器示例
var circuitBreakerPolicy = Policy
.Handle<HttpRequestException>()
.CircuitBreakerAsync(
exceptionsAllowedBeforeBreaking: 5,
durationOfBreak: TimeSpan.FromSeconds(30),
onBreak: (exception, duration) =>
{
Console.WriteLine("Circuit opened");
},
onReset: () =>
{
Console.WriteLine("Circuit closed");
},
onHalfOpen: () =>
{
Console.WriteLine("Circuit half-open");
});
此代码的作用
- 在连续 5 次失败后打开断路器
- 阻止请求 30 秒
- 断路期间结束后自动尝试恢复
组合重试和断路器
单独使用重试可能会使故障服务过载。
单独使用断路器可能会过于激进。
真正的威力来自于将它们结合起来。
var resiliencePolicy = Policy.WrapAsync(
retryPolicy,
circuitBreakerPolicy);
执行示例
await resiliencePolicy.ExecuteAsync(async () =>
{
var response = await httpClient.GetAsync("https://external-api.com/data");
response.EnsureSuccessStatusCode();
});
此设置确保:
- 瞬时故障会被重试
- 持久性故障会触发断路
- 系统稳定性得以保持
为什么选择 Polly?
Polly 是 .NET 生态系统中事实上的弹性库,因为:
- 流畅且富有表现力的 API
- 支持异步和同步操作
- 能够轻松集成
HttpClientFactory - 在生产系统中被广泛使用
支持的模式包括:
- 重试
- 熔断器
- 超时
- 回退
- 隔舱隔离
实际案例
Polly 在以下场景中特别有用:
- 微服务通信
- 金融和交易系统
- 云原生应用
- API 网关
- SignalR 与实时系统
只要存在 I/O 或远程调用的地方,弹性(resilience)就应该被视为首要关注点。
关键要点
- 在分布式系统中,故障是不可避免的
- 弹性(Resilience)可防止小问题演变为宕机
- 重试(Retry)处理瞬时故障
- 熔断器(Circuit Breaker)保护系统稳定性
- Polly 让弹性在 .NET 中变得实用且可投入生产
最终思考
弹性不是可选功能——它是现代应用程序的设计需求。使用像 Polly 这样强大的库实现重试(Retry)和断路器(Circuit Breaker)等模式,可帮助您构建即使在进程外部环境异常时仍保持可用、响应迅速且易于维护的系统。
结论
通过利用已验证的模式和像 Polly 这样的库,您可以构建系统,使其具备:
- 稳定
- 可扩展
- 容错
- 用户友好
如果您的应用程序需要与外部世界交互,它必须具备弹性。
我是 Morteza Jangjoo,致力于“解释我希望有人曾经向我解释的事”。