概念
Polly是一个被.net基金会支持认可的框架,Polly是一个.NET弹性和瞬态故障处理库,允许开发人员以流畅和线程安全的方式表达策略,如重试、断路器、超时、舱壁隔离和回退。
Polly的7种策略
Polly是一个.NET Core中的弹性和瞬态故障处理库,它提供了多种策略来处理服务故障,确保系统的健壮性和可用性。以下是Polly的一些主要功能:
- 重试策略(Retry):当服务调用失败时,Polly可以自动进行重试,这有助于处理那些可能因为暂时性问题导致的服务不可用情况。
- 断路器(Circuit Breaker):当检测到服务连续不可用时,断路器策略会介入,快速返回错误响应,避免对下游服务的持续请求,从而预防服务雪崩现象。
- 超时策略(Timeout):为服务调用设置一个最大执行时间,超过这个时间的服务调用将被认为失败,可以采取预设的应对措施。
- 舱壁隔离(Bulkhead Isolation):通过限制对服务的并发调用数量,防止因某个服务的问题影响到整个系统的稳定性。
- 缓存策略(Cache):提供一种机制,可以在服务调用的结果不变的情况下直接使用缓存结果,减少不必要的服务调用。
- 降级策略(Fallback):当服务调用失败时,可以提供一个备用的逻辑或者数据作为响应,提高用户体验。
-
策略组合(PolicyWrap) : Polly针对不同的故障有不同的策略,我们可以灵活的组合策略,上述的六种策略可以灵活组合使用。
Polly的策略定义了“故障”和“动作”两个部分,其中“故障”可以包括异常、超时等情况,而“动作”则包括降级、重试、熔断等应对措施。这些策略可以单独使用,也可以组合使用,以适应不同的业务需求和场景。
综上所述,Polly是一个功能丰富的库,它能够帮助开发者在.NET Core微服务架构中实现服务治理,提高系统的弹性和稳定性。通过使用Polly,可以有效地处理服务故障,保证服务的高可用性。
代码部分(整合成了一个类,可直接依赖注入)
1.创建一个ASP.NET CORE Web Api或者ASP.NET CORE MVC项目。
2.Nuget引入Polly程序包。
3.Polly服务治理工具类。
/// <summary>
/// 服务治理
/// </summary>
public class PollyHelper
{
Policy PolicyExecutes = Policy.Bulkhead(5);
ISyncPolicy? pollyCircuitBreaker;
ISyncPolicy? policyFallback;
ISyncPolicy? policy;
/// <summary>
/// 降级策略(回退策略)
/// </summary>
/// <param name="actionFallback"></param>
/// <param name="actionExecute"></param>
public void PollyFallback(Action actionFallback, Action actionExecute)
{
//以下代码声明Policy处理ArgumentException异常,处理异常大动作为降级,policy.Execute()方法是指没有发生异常时,我们的业务逻辑。
//声明Policy处理ArgumentException异常--当异常类型与定义监控异常类型ArgumentException不匹配的情况下是不会执行Fallback()的
ISyncPolicy _policy = Polly.Policy.Handle<ArgumentException>().Or<ArgumentException>()
//出现异常时的动作
.Fallback(() => { actionFallback.Invoke(); });
//没有异常时正常正常的业务逻辑
_policy.Execute(() => { actionExecute.Invoke(); });
}
/// <summary>
/// 重试策略
/// </summary>
/// <param name="actionExecute">正常逻辑</param>
public void PollyRetry(Action actionExecute)
{
ISyncPolicy _policy = Polly.Policy.Handle<ArgumentException>().Retry(5);
//没有异常时正常正常的业务逻辑
_policy.Execute(() => { actionExecute.Invoke(); });
}
/// <summary>
/// 熔断策略
/// </summary>
/// <param name="exceptionsAllowedBeforeBreaking"></param>
/// <param name="durationOfBreak"></param>
/// <param name="aonBreak"></param>
/// <param name="aonReset"></param>
/// <param name="aonHalfOpen"></param>
/// <param name="execute"></param>
public void PollyCircuitBreaker(int exceptionsAllowedBeforeBreaking, TimeSpan durationOfBreak, Action aonBreak, Action aonReset, Action aonHalfOpen, Action actionFallback, Action execute)
{
//熔断策略
if (policy == null)
{
pollyCircuitBreaker = Policy.Handle<Exception>()
.CircuitBreaker(
// 熔断前允许出现几次错误
exceptionsAllowedBeforeBreaking,
// 熔断时间
durationOfBreak,
// 熔断时触发 OPEN
onBreak: (ex, breakDelay) =>
{
aonBreak.Invoke();
},
// 熔断恢复时触发 CLOSE
onReset: () =>
{
aonReset.Invoke();
},
// 熔断时间到了之后触发,尝试放行少量(1次)的请求,
onHalfOpen: () =>
{
aonHalfOpen.Invoke();
}
);
// 回退策略,降级!
policyFallback = Policy.Handle<Exception>()
.Fallback(() =>
{
actionFallback.Invoke();
}, exception =>
{
Console.WriteLine($"Fallback异常:{exception.GetType()}");
});
policy = Policy.Wrap(policyFallback, pollyCircuitBreaker);
}
policy.Execute(() => { execute.Invoke(); });
}
/// <summary>
/// 超时+回退策略
/// </summary>
/// <param name="actionFallback"></param>
/// <param name="actionExecute"></param>
public void PollyTimeOut(Action actionFallback, Action actionExecute)
{
//超时
Policy policyTimeout = Policy.Timeout(3, TimeoutStrategy.Pessimistic);
//降级
Policy policyFallback = Policy.Handle<Exception>()
.Fallback(() =>
{
actionFallback.Invoke();
});
Policy policy = policyFallback.Wrap(policyTimeout);
policy.Execute(() =>
{
actionExecute.Invoke();
});
}
/// <summary>
/// 隔离策略
/// </summary>
/// <param name="actionExecute"></param>
public void PollyBulkhead(Action actionExecute)
{
//不能在方法中使用Policy,否则失效。因为会重新创建一个Policy。
PolicyExecutes.Execute(() =>
{
actionExecute.Invoke();
});
}
/// <summary>
/// Polly组合(策略组合)
/// </summary>
/// <returns></returns>
public ISyncPolicy CreatePolly()
{
// 超时1秒
var timeoutPolicy = Policy.Timeout(1, TimeoutStrategy.Pessimistic, (context, timespan, task) =>
{
Console.WriteLine("执行超时,抛出TimeoutRejectedException异常");
});
// 重试2次
var retryPolicy = Policy.Handle<Exception>()
.WaitAndRetry(
2,
retryAttempt => TimeSpan.FromSeconds(2),
(exception, timespan, retryCount, context) =>
{
Console.WriteLine($"{DateTime.Now} - 重试 {retryCount} 次 - 抛出{exception.GetType()}-{timespan.TotalMilliseconds}");
});
// 连续发生两次故障,就熔断3秒
var circuitBreakerPolicy = Policy.Handle<Exception>()
.CircuitBreaker(
// 熔断前允许出现几次错误
2,
// 熔断时间
TimeSpan.FromSeconds(5),
// 熔断时触发 OPEN
onBreak: (ex, breakDelay) =>
{
Console.WriteLine($"{DateTime.Now} - 断路器:开启状态(熔断时触发)");
},
// 熔断恢复时触发 // CLOSE
onReset: () =>
{
Console.WriteLine($"{DateTime.Now} - 断路器:关闭状态(熔断恢复时触发)");
},
// 熔断时间到了之后触发,尝试放行少量(1次)的请求,
onHalfOpen: () =>
{
Console.WriteLine($"{DateTime.Now} - 断路器:半开启状态(熔断时间到了之后触发)");
}
);
// 回退策略,降级!
var fallbackPolicy = Policy.Handle<Exception>()
.Fallback(() =>
{
Console.WriteLine("这是一个Fallback");
}, exception =>
{
Console.WriteLine($"Fallback异常:{exception.GetType()}");
});
// 策略从右到左依次进行调用
// 首先判断调用是否超时,如果超时就会触发异常,发生超时故障,然后就触发重试策略;
// 如果重试两次中只要成功一次,就直接返回调用结果
// 如果重试两次都失败,第三次再次失败,就会发生故障
// 重试之后是断路器策略,所以这个故障会被断路器接收,当断路器收到两次故障,就会触发熔断,也就是说断路器开启
// 断路器开启的3秒内,任何故障或者操作,都会通过断路器到达回退策略,触发降级操作
// 3秒后,断路器进入到半开启状态,操作可以正常执行
return Policy.Wrap(fallbackPolicy, circuitBreakerPolicy, retryPolicy, timeoutPolicy);
}
}
4.依赖注入
//依赖注入,polly需要注册成单例,因为一但注册成瞬时的每次调用重新生成一个对象,服务策略失效
builder.Services.AddSingleton<PollyHelper>();
5.控制器代码
[Route("api/[controller]")]
[ApiController]
public class PollyController : ControllerBase
{
private readonly PollyHelper _pollyHelper;
//构造函数注入
public PollyController(PollyHelper pollyHelper)
{
_pollyHelper = pollyHelper;
}
/// <summary>
/// 降级策略
/// </summary>
/// <returns></returns>
[HttpGet("Fallback")]
public void GetFallback()
{
_pollyHelper.PollyFallback(() =>
{
Console.WriteLine("方法出错,开始降级");
}, () =>
{
Console.WriteLine("开始处理正常业务");
Console.WriteLine(".................................");
Console.WriteLine("执行正常业务处理");
Console.WriteLine(".................................");
throw new ArgumentException();
Console.WriteLine("正业务处理完成");
});
}
/// <summary>
/// 重试策略
/// </summary>
/// <returns></returns>
[HttpGet("Retry")]
public void GetRetry()
{
_pollyHelper.PollyRetry(() =>
{
Console.WriteLine("开始处理正常业务");
Console.WriteLine(".................................");
Console.WriteLine("执行正常业务处理");
Console.WriteLine(".................................");
throw new ArgumentException();
Console.WriteLine("正业务处理完成");
});
}
/// <summary>
/// 熔断策略
/// </summary>
/// <returns></returns>
[HttpGet("CircuitBreaker_Ioc")]
public void GetCircuitBreaker(int a = 0, bool b = false)
{
Console.WriteLine($"*****************for*****************");
for (int i = a; i < 20; i++)
{
_pollyHelper.PollyCircuitBreaker(3, TimeSpan.FromSeconds(2), () =>
{
Console.WriteLine("断路器:开启状态(熔断时触发)");
}, () =>
{
Console.WriteLine("断路器:关闭状态(熔断恢复时触发)");
}, () =>
{
Console.WriteLine("断路器:半开启状态(熔断时间到了之后触发)");
}, () =>
{
Console.WriteLine("这是一个Fallback开始降级");
}, () =>
{
Console.WriteLine($"-------------第{i}次请求-------------");
Console.WriteLine("正常情况下:开始执行");
Thread.Sleep(1000);
if (i < 3) throw new Exception("出错了");
Console.WriteLine("正常情况下:执行结束");
});
}
Console.WriteLine($"*****************forend****************");
//此处是为了等待熔断接回(配置了熔断2秒,这里等一下,要不下次请求还没接上直接报错)
Thread.Sleep(5000);
if (b)
{
Console.WriteLine($"*****************跳出+{b.ToString()}*****************");
return;
}
GetCircuitBreaker(3, true);
}
/// <summary>
/// 策略封装
/// </summary>
/// <returns></returns>
[HttpGet("Wrap")]
public void GetWrap()
{
//重试3次
Policy policyRetry = Policy.Handle<Exception>()
.Retry(3);
//降级
Policy policyFallback = Policy.Handle<Exception>()
.Fallback(() =>
{
Console.WriteLine("降级了");
});
//重试三次后降级
Policy policyWarp = policyFallback.Wrap(policyRetry);
policyWarp.Execute(() =>
{
Console.WriteLine("开始执行");
for (int i = 0; i < 100; i++)
{
if (i % 2 == 0)
throw new Exception("出错了");
}
Console.WriteLine("执行结束");
});
}
/// <summary>
/// 超时策略
/// </summary>
/// <returns></returns>
[HttpGet("Timeout")]
public void GetTimeout()
{
_pollyHelper.PollyTimeOut(() => { Console.WriteLine("降级"); }, () =>
{
Console.WriteLine("开始执行");
Thread.Sleep(5000);//阻塞5秒钟,模拟超时
Console.WriteLine("执行结束");
});
}
/// <summary>
/// 隔离策略(Bulkhead Isolation)
/// </summary>
/// <returns></returns>
[HttpGet("Bulkhead")]
public void GetBulkhead()
{
//制定策略最大的并发数为5
for (int i = 0; i < 6; i++)
{
Task.Factory.StartNew(() =>
{
try
{
_pollyHelper.PollyBulkhead(() => { Console.WriteLine($"********************开始执行程序**************************"); });
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
});
}
}
/// <summary>
/// Polly测试
/// </summary>
/// <returns></returns>
[HttpGet("Test")]
public void GetTest()
{
var policy = _pollyHelper.CreatePolly();
for (int i = 0; i < 20; i++)
{
Console.WriteLine($"-------------第{i}次请求-------------");
policy.Execute(() =>
{
// 从10次开始,正常请求成功
if (i < 10)
{
Thread.Sleep(3000);
}
else
{
Console.WriteLine($"{DateTime.Now}:请求成功");
}
});
Thread.Sleep(1000);
}
}
}
总结:
Polly是一个.NET Core微服务框架,用于实现容错、重试、熔断等策略。它可以帮助开发者在分布式系统中提高可靠性和稳定性。Polly提供了丰富的策略,如重试策略、熔断策略、超时策略等,可以灵活地应用于微服务架构中。通过使用Polly,开发者可以更好地处理异常情况,提高系统的可用性和性能。
标签:CORE,Console,策略,Polly,熔断,WriteLine,Policy,NET From: https://blog.csdn.net/m0_59178355/article/details/136605237