熔断策略(Circuit-breaker)
如果调用某个目标服务出现过多超时、异常等情况,可以采取一定时间内熔断该服务的调用,熔断期间的请求将不再继续调用目标服务,而是直接返回,节约资源,提高服务的稳定性,熔断周期结束后如果目标服务情况好转则恢复调用。
注意:为了服务的稳定性,在执行需要多次 Retry(重试策略)的情况下,最好组合熔断策略,预防可能存在的风险。
熔断状态
- 打开(Open)
熔断器打开状态,此时对目标服务的调用都直接返回错误,熔断周期内不会走网络请求,当熔断周期结束时进入半开状态;
- 关闭(Closed)
关闭状态下正常发生网络请求,但会记录符合熔断条件的连续执行次数,如果错误数量达到设定的阈值(如果在没有达到阈值之前恢复正常,之前的累积次数将会归零),熔断状态进入到打开状态;
- 半开(Half-Open)
半开状态下允许定量的服务请求,如果调用都成功则认为恢复了,关闭熔断器,否则认为还没好,又回到熔断器打开状态;
熔断使用说明
// 在连续3次异常后熔断,并保持1分钟的熔断状态,调用者将收到断路保护的异常信息
Policy
.Handle<SomeExceptionType>()
.CircuitBreaker(3, TimeSpan.FromMinutes(1));
熔断代码测试
private static int times = 0;
public static void TestPolicy()
{
var circuitBreakerPolicy = Policy
.Handle<Exception>()
.CircuitBreaker(
exceptionsAllowedBeforeBreaking: 4, // 连续4次异常
durationOfBreak: TimeSpan.FromMinutes(1), // 断开1分钟
onBreak: (exception, breakDelay) => // 断路器打开时
Console.WriteLine($"熔断: {breakDelay.TotalMilliseconds } ms, 异常: " + exception.Message),
onReset: () => // 熔断器关闭时
Console.WriteLine("熔断器关闭了"),
onHalfOpen: () => // 熔断时间结束时,从断开状态进入半开状态
Console.WriteLine("熔断时间到,进入半开状态")
);
for (int i = 0; i < 12; i++) // 模拟多次调用,触发熔断
{
try
{
var result = circuitBreakerPolicy.Execute(Test);
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine("try-catch:" + ex.Message);
}
Thread.Sleep(500);
}
}
private static string Test()
{
times++;
if (times % 5 != 0) // 模仿某些错误情况下抛异常
{
throw new Exception("exception message");
}
return "success";
}
熔断高级配置
根据时间段内总请求数中的异常比例触发熔断:
var advancedCircuitBreakerPolicy = Policy
.Handle<Exception>()
.AdvancedCircuitBreaker(
failureThreshold: 0.5, // 至少50%有异常则熔断
samplingDuration: TimeSpan.FromSeconds(10), // 10秒内
minimumThroughput: 8, // 最少共有多少次调用
durationOfBreak: TimeSpan.FromSeconds(30),
onBreak: (exception, breakDelay) => // 断路器打开时
Console.WriteLine($"熔断: {breakDelay.TotalMilliseconds } ms, 异常: " + exception.Message),
onReset: () => // 熔断器关闭时
Console.WriteLine("熔断器关闭了"),
onHalfOpen: () => // 熔断时间结束时,从断开状态进入半开状态
Console.WriteLine("熔断时间到,进入半开状态")
);