一、简介
Polly 是一个 .NET 弹性和瞬态故障处理库,旨在帮助开发者构建更健壮和可靠的应用程序。它提供了一系列策略,如重试、断路器、超时、回退和隔离等,用于处理瞬态故障和提高系统的弹性。
二、原理和功能
Polly 的核心原理是通过定义和应用策略来处理可能出现的故障。这些策略可以组合使用,以应对不同类型的故障场景。以下是一些主要功能:
- 重试(Retry):在操作失败时自动重试指定次数。
- 断路器(Circuit Breaker):在检测到连续失败后短暂停止操作,以防止系统过载。
- 超时(Timeout):为操作设置最大执行时间,超过时间则取消操作。
- 回退(Fallback):在操作失败时提供备用方案。
- 隔离(Bulkhead Isolation):限制并发执行的操作数量,以防止资源耗尽。
三、作用
Polly 的主要作用是增强应用程序的弹性和容错能力,使其能够更好地应对网络抖动、服务不可用等瞬态故障,从而提高系统的稳定性和用户体验。
四、实现案例
以下是基于 ASP.NET Core 6 和 Polly 的几个实际应用场景的代码示例。
场景一:重试策略
在这个示例中,我们将使用 Polly 的重试策略来处理 HTTP 请求失败的情况。
using Microsoft.Extensions.DependencyInjection;
using Polly;
using Polly.Extensions.Http;
using System;
using System.Net.Http;
using System.Threading.Tasks;
var builder = WebApplication.CreateBuilder(args);
// 注册 HttpClient 并配置重试策略
builder.Services.AddHttpClient("MyClient")
.AddPolicyHandler(GetRetryPolicy());
var app = builder.Build();
app.MapGet("/", async (IHttpClientFactory httpClientFactory) =>
{
var client = httpClientFactory.CreateClient("MyClient");
var response = await client.GetAsync("https://api.example.com/data");
return response.IsSuccessStatusCode ? "Success" : "Failed";
});
app.Run();
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
场景二:断路器策略
在这个示例中,我们将使用 Polly 的断路器策略来保护系统免受连续失败的影响。
using Microsoft.Extensions.DependencyInjection;
using Polly;
using Polly.CircuitBreaker;
using Polly.Extensions.Http;
using System;
using System.Net.Http;
using System.Threading.Tasks;
var builder = WebApplication.CreateBuilder(args);
// 注册 HttpClient 并配置断路器策略
builder.Services.AddHttpClient("MyClient")
.AddPolicyHandler(GetCircuitBreakerPolicy());
var app = builder.Build();
app.MapGet("/", async (IHttpClientFactory httpClientFactory) =>
{
var client = httpClientFactory.CreateClient("MyClient");
try
{
var response = await client.GetAsync("https://api.example.com/data");
return response.IsSuccessStatusCode ? "Success" : "Failed";
}
catch (BrokenCircuitException)
{
return "Circuit is open!";
}
});
app.Run();
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(2, TimeSpan.FromMinutes(1));
}
场景三:超时策略
在这个示例中,我们将使用 Polly 的超时策略来确保 HTTP 请求不会无限期挂起。
using Microsoft.Extensions.DependencyInjection;
using Polly;
using Polly.Timeout;
using Polly.Extensions.Http;
using System;
using System.Net.Http;
using System.Threading.Tasks;
var builder = WebApplication.CreateBuilder(args);
// 注册 HttpClient 并配置超时策略
builder.Services.AddHttpClient("MyClient")
.AddPolicyHandler(GetTimeoutPolicy());
var app = builder.Build();
app.MapGet("/", async (IHttpClientFactory httpClientFactory) =>
{
var client = httpClientFactory.CreateClient("MyClient");
try
{
var response = await client.GetAsync("https://api.example.com/data");
return response.IsSuccessStatusCode ? "Success" : "Failed";
}
catch (TimeoutRejectedException)
{
return "Request timed out!";
}
});
app.Run();
static IAsyncPolicy<HttpResponseMessage> GetTimeoutPolicy()
{
return Policy.TimeoutAsync<HttpResponseMessage>(10); // 10秒超时
}
场景四:组合策略
在这个示例中,我们将组合重试、断路器和超时策略,以应对复杂的故障场景。
using Microsoft.Extensions.DependencyInjection;
using Polly;
using Polly.CircuitBreaker;
using Polly.Extensions.Http;
using Polly.Timeout;
using System;
using System.Net.Http;
using System.Threading.Tasks;
var builder = WebApplication.CreateBuilder(args);
// 注册 HttpClient 并配置组合策略
builder.Services.AddHttpClient("MyClient")
.AddPolicyHandler(GetCombinedPolicy());
var app = builder.Build();
app.MapGet("/", async (IHttpClientFactory httpClientFactory) =>
{
var client = httpClientFactory.CreateClient("MyClient");
try
{
var response = await client.GetAsync("https://api.example.com/data");
return response.IsSuccessStatusCode ? "Success" : "Failed";
}
catch (BrokenCircuitException)
{
return "Circuit is open!";
}
catch (TimeoutRejectedException)
{
return "Request timed out!";
}
});
app.Run();
static IAsyncPolicy<HttpResponseMessage> GetCombinedPolicy()
{
var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
var circuitBreakerPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(2, TimeSpan.FromMinutes(1));
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(10);
return Policy.WrapAsync(retryPolicy, circuitBreakerPolicy, timeoutPolicy);
}
方法参数解释:
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
具体来说,这段代码的作用是:
- 处理瞬态 HTTP 错误(如网络问题、服务器过载等)。
- 如果收到 404 Not Found 响应,也会进行重试。
- 重试三次,每次重试之间的等待时间呈指数增长。
下面是对每个方法的详细解释:
-
HttpPolicyExtensions.HandleTransientHttpError()
:- 这是一个扩展方法,用于捕获常见的瞬态 HTTP 错误,如 5xx 系列的服务器错误和网络连接失败等。
-
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
:- 这个方法用于指定额外的条件,即当 HTTP 响应状态码为 404 Not Found 时也进行重试。
-
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))
:WaitAndRetryAsync
方法定义了一个异步的重试策略。- 参数
3
表示最多重试三次。 - 第二个参数是一个函数,定义了每次重试之间的等待时间。这里使用的是指数退避算法:第一次重试等待 2^1 秒,第二次重试等待 2^2 秒,第三次重试等待 2^3 秒。
五、总结:
通过这些示例,你可以看到如何使用 Polly 来增强 ASP.NET Core 应用程序的弹性和容错能力。根据具体的业务需求,可以灵活组合和调整这些策略。