Polly官方介绍
Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner.
翻译过来大概意思是:Polly 是一个 .NET 弹性和瞬态故障处理库,允许开发人员以线程安全的方式来实现重试、断路、超时、隔离和回退策略。
首先这里的说的瞬态故障包含了程序发生的异常和出现不符合开发者预期的结果。
所谓瞬态故障,就是说故障不是必然会发生的,而是偶然可能会发生的,比如网络偶尔会突然出现不稳定或无法访问这种故障。至于弹性,就是指应对故障 Polly 的处理策略具有多样性和灵活性,它的各种策略可以灵活地定义和组合。
一 、熔断降级——概念及原理
1. 什么是熔断
熔断就是在被调用端出现宕机,和超时两种情况出现的一种策略应对机制。
熔断就好比保险丝,我们先来看一看保险丝的情况
2. 为什么要使用熔断
1、服务调用出现异常(包括超时和宕机两种情况)
如果服务连续几次都出现异常,那么就将服务进行熔断一段时间,
3. 什么是降级
4. 为什么要使用降级
1、服务主动降级(选择性放弃)
主动将服务进行进行异常返回
2、服务异常降级
如果服务调用出现超时或者宕机的情况,就按照自定义的策略进行返回。
项目中熔断降级的目的是保证系统的弹性,使系统高可用
5. Polly熔断原理
二 、熔断降级——Polly介绍
1. 熔断降级工具
- Polly
- Hystrix
2. 主要功能
- 重试(Retry)
- 断路器(Circuit-breaker)
- 超时检测(Timeout)
- 缓存(Cache)
- 降级(FallBack)
3. Polly官网地址
http://www.thepollyproject.org/
三 、熔断降级——Polly项目应用
1. Polly使用
- 条件
- .Net Core项目
- 微服务项目
- Polly
- Polly Http扩展
- 步骤
- 先通过nuget进行安装
Microsoft.Extensions.Http.Polly
- 然后在HttpClient后面添加扩展方法
AddPolicyHandler()
- 然后在团队服务里面,测试宕机,和超时情况
2. Polly策略搭配
熔断策略
.AddPolicyHandler(Policy<HttpResponseMessage>.Handle<Exception>().CircuitBreakerAsync(3, TimeSpan.FromSeconds(10), (ex, ts) => {
Console.WriteLine($"服务{name}断路器开启,异常消息:{ex.Exception.Message}");
Console.WriteLine($"服务{name}断路器开启时间:{ts.TotalSeconds}s");
}, () => {
Console.WriteLine($"服务{name}断路器重置");
}, () => {
Console.WriteLine($"服务{name}断路器半开启(一会开,一会关)");
}))
降级策略
var fallbackResponse = new HttpResponseMessage
{
Content = new StringContent("系统出现异常,请稍后重试"),
StatusCode = HttpStatusCode.GatewayTimeout
};
.AddPolicyHandler(Policy<HttpResponseMessage>.HandleInner<Exception>().FallbackAsync(options.httpResponseMessage, async b =>
{
// 1、降级打印异常
Console.WriteLine($"服务{name}开始降级,异常消息:{b.Exception.Message}");
// 2、降级后的数据
Console.WriteLine($"服务{name}降级内容响应:{options.httpResponseMessage.Content.ToString()}");
await Task.CompletedTask;
}))
重试策略
.AddPolicyHandler(Policy<HttpResponseMessage>
.Handle<Exception>()
.RetryAsync(options.RetryCount)
)
超时机制
超时机制必须要慎用
,需要考虑相关服务的幂等性
.AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(options.TimeoutTime)));
3. Polly封装
- 条件
- IServiceCollection扩展类
- HttpClientPolly选项类
- 步骤
- 创建
PollyHttpClientServiceCollectionExtensions
类
/// <summary>
/// Httpclient扩展方法
/// </summary>
/// <param name="services">ioc容器</param>
/// <param name="name">HttpClient 名称(针对不同的服务进行熔断,降级)</param>
/// <param name="action">熔断降级配置</param>
/// <param name="TResult">降级处理错误的结果</param>
/// <returns></returns>
public static IServiceCollection AddHttpClientPolly(this IServiceCollection services,string name,Action<HttpClientPollyOptions> action)
{
// 1、创建选项配置类
HttpClientPollyOptions options = new HttpClientPollyOptions();
action(options);
// 2、配置httpClient,熔断降级策略
services.AddHttpClient(name)
//2.1 降级策略
.AddPolicyHandler(Policy<HttpResponseMessage>.HandleInner<Exception>().FallbackAsync(options.httpResponseMessage, async b =>
{
Console.WriteLine($"服务{name}开始降级,异常消息:{b.Exception.Message}");
Console.WriteLine($"服务{name}降级内容响应:{options.httpResponseMessage.Content.ToString()}");
await Task.CompletedTask;
}))
// 2.2 断路器策略
.AddPolicyHandler(Policy<HttpResponseMessage>.Handle<Exception>().CircuitBreakerAsync(options.CircuitBreakerOpenFallCount, TimeSpan.FromSeconds(options.CircuitBreakerDownTime), (ex, ts) => {
Console.WriteLine($"服务{name}断路器开启,异常消息:{ex.Exception.Message}");
Console.WriteLine($"服务{name}断路器开启时间:{ts.TotalSeconds}s");
}, () => {
Console.WriteLine($"服务{name}断路器关闭");
}, () => {
Console.WriteLine($"服务{name}断路器半开启(时间控制,自动开关)");
}))
// 2.3 重试策略
.AddPolicyHandler(Policy<HttpResponseMessage>
.Handle<Exception>()
.RetryAsync(options.RetryCount)
)
// 2.4 超时策略
.AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(options.TimeoutTime)));
return services;
}
- 然后创建熔断,降级,重试,超时
HttpClientPollyOptions
配置类
/// <summary>
/// 超时时间设置,单位为秒
/// </summary>
public int TimeoutTime { set; get; }
/// <summary>
/// 失败重试次数
/// </summary>
public int RetryCount { set; get; }
/// <summary>
/// 执行多少次异常,开启短路器(例:失败2次,开启断路器)
/// </summary>
public int CircuitBreakerOpenFallCount { set; get; }
/// <summary>
/// 断路器开启的时间(例如:设置为2秒,短路器两秒后自动由开启到关闭)
/// </summary>
public int CircuitBreakerDownTime { set; get; }
/// <summary>
/// 降级处理(将异常消息封装成为正常消息返回,然后进行响应处理,例如:系统正在繁忙,请稍后处理.....)
/// </summary>
public HttpResponseMessage httpResponseMessage { set; get; }
- 封装后的代码调用
services.AddPollyHttpClient("cyf",options => {
options.TimeoutTime = 1;
options.RetryCount = 3;
options.CircuitBreakerOpenFallCount = 2;
options.CircuitBreakerDownTime = 100;
options.httpResponseMessage = fallbackResponse;
});