环境:
- window 10 x64 企业版
- vs2019 企业版 16.7.5
- Polly 7.2.1
- Ocelot.Provider.Polly 16.0.1
说明:
在上一篇《c#:Ocelot熔断机制体验》,我实验了Ocelot的熔断机制,但在我试验的过程中,发现后台服务报500异常并不会被ocelot计入熔断的触发条件,这引起了我的好奇。
于是,我找到Ocelot.Provider.Polly
的源码以及Polly
的介绍,出了这篇文章。
参照:.NET Core微服务之基于Polly+AspectCore实现熔断与降级机制
一、Polly
的介绍和功能实验
Polly是一种开源的.NET弹性和瞬态故障处理库,允许我们以非常顺畅和线程安全的方式来执诸如行重试,断路,超时,故障恢复等策略。
Polly的github地址:https://github.com/App-vNext/Polly
下面先实验Polly
的功能,然后再看Ocelot.Provider.Polly
的源码。
首先我们新建一个.net core控制台工程,然后引入Polly
:
<ItemGroup>
<PackageReference Include="Polly" Version="7.2.1" />
</ItemGroup>
1.1 Polly中的降级
所谓降级就是,当我们指定的代码处理失败时就执行我们备选的代码。
看下面实例:
/// <summary>
/// 降级
/// </summary>
public static void Case1()
{
ISyncPolicy policy = Policy.Handle<ArgumentException>()
.Fallback(() =>
{
Console.WriteLine("Error occured");
});
policy.Execute(() =>
{
Console.WriteLine("Job Start");
throw new ArgumentException("Hello Polly!");
Console.WriteLine("Job End");
});
}
运行这个方法,我们将得到下图:
这个很好理解。
1.2 Polly中的重试
所谓重试就是当我们指定的代码运行失败后,我们再让他重复运行几次。
看下面实例:
/// <summary>
/// 重试
/// </summary>
public static void Case2()
{
ISyncPolicy policy = Policy.Handle<Exception>().Retry(3);
try
{
policy.Execute(() =>
{
Console.WriteLine("Job Start");
throw new Exception("Special error occured");
Console.WriteLine("Job End");
});
}
catch (Exception ex)
{
Console.WriteLine("There's one unhandled exception : " + ex.Message);
}
}
运行后如下图所示:
上面的也很好理解,我们先运行一次,失败后运行我们指定的重试次数(3),然后又失败了,抛出异常结束。
1.3 Polly中的熔断
所谓熔断就是:我们指定的代码连续运行多次都失败,那么就让这块代码进入
熔断状态
并持续一会,之后所有再次尝试调用这块代码都将直接抛出异常。当这块代码度过熔断状态后,会立刻进入半熔断状态
,之后这块代码运行的第一次会被特殊观察,如果运行成功则进入正常状态
,否则重新触发熔断。
看下面实例:
/// <summary>
/// 熔断
/// </summary>
public static void Case3()
{
// Stop for 3s after retry 3 times
ISyncPolicy policy = Policy.Handle<Exception>()
.CircuitBreaker(3, TimeSpan.FromSeconds(3));
while (true)
{
try
{
policy.Execute(() =>
{
Console.WriteLine("Job Start");
throw new Exception("Special error occured");
Console.WriteLine("Job End");
});
}
catch (Exception ex)
{
Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}\tThere's one unhandled exception : " + ex.Message);
}
Thread.Sleep(500);
}
}
运行上面代码,输出如下:
可以看到,一开始连续运行了三次都失败后触发熔断,经过3秒后,再运行一次,发现失败后就立刻触发熔断,经过3秒后,。。。
1.4 Polly中的超时
所谓超时,就是我们指定一段代码的最大运行时间,如果超过这段时间还没有完成,就直接抛出异常。
这里判断超时有两种策略:一个是悲观策略(Pessimistic),一个是乐观策略(Optimistic)。一般我们用悲观策略。需要注意的是,虽然超时抛除了异常,但这段代码的运行并没有停止!
看下面实例代码:
/// <summary>
/// 超时
/// </summary>
public static void Case4()
{
try
{
ISyncPolicy policyTimeout = Policy.Timeout(3, Polly.Timeout.TimeoutStrategy.Pessimistic);
policyTimeout.Execute(() =>
{
Console.WriteLine("Job Start...");
Thread.Sleep(5000);
Console.WriteLine("Job End...");
});
}
catch (Exception ex)
{
Console.WriteLine($"Unhandled exception : {ex.GetType()} : {ex.Message}");
}
}
运行后输出如下:
这个不难理解。
1.5 Polly中组合超时和降级
所谓组合超时和降级就是Polly发现代码超时后就运行我们指定的备选代码。
直接看下面代码:
/// <summary>
/// 超时后降级
/// </summary>
public static void Case5()
{
try
{
ISyncPolicy policyException = Policy.Handle<TimeoutRejectedException>()
.Fallback(() =>
{
Console.WriteLine("Fallback");
});
ISyncPolicy policyTimeout = Policy.Timeout(3, Polly.Timeout.TimeoutStrategy.Pessimistic);
ISyncPolicy mainPolicy = Policy.Wrap(policyException, policyTimeout);
mainPolicy.Execute(() =>
{
Console.WriteLine("Job Start...");
Thread.Sleep(5000);
Console.WriteLine("Job End...");
});
}
catch (Exception ex)
{
Console.WriteLine($"Unhandled exception : {ex.GetType()} : {ex.Message}");
}
}
运行后输出如下:
这个也很好理解。
1.6 Polly中组合超时和熔断
所谓组合超时和熔断就是指定的代码连续运行超时后抛出异常,被熔断捕捉后达到阈值,从而触发熔断。
直接看下面代码:
/// <summary>
/// 超时后熔断
/// </summary>
public static void Case6()
{
ISyncPolicy policyTimeout = Policy.Timeout(3, Polly.Timeout.TimeoutStrategy.Pessimistic);
ISyncPolicy policyCircuitBreaker = Policy.Handle<Exception>()
.CircuitBreaker(3, TimeSpan.FromSeconds(3));
ISyncPolicy mainPolicy = Policy.Wrap(policyCircuitBreaker, policyTimeout);
while (true)
{
try
{
mainPolicy.Execute(() =>
{
Console.WriteLine("Job Start...");
Thread.Sleep(5000);
//Console.WriteLine("Job End...");
});
}
catch (Exception ex)
{
Console.WriteLine($"Unhandled exception : {ex.GetType()} : {ex.Message}");
}
Thread.Sleep(500);
}
}
运行后输出如下:
这个也不难理解。
二、分析Ocelot.Provider.Polly中的熔断机制
Ocelot.Provider.Polly
中的熔断机制其实就是用Polly组合超时和熔断
实现的。
可以看下源代码:
里面的代码不多,我们看关键的PollyQoSProvider.cs
:
这下,我们应该清楚的知道熔断的原理了!!!