34

Polly 故障处理(二): 熔断策略

 5 years ago
source link: http://beckjin.com/2018/06/30/polly-circuit-breaker/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

如果调用某个目标服务出现过多超时、异常等情况,可以采取一定时间内熔断该服务的调用,熔断期间的请求将不再继续调用目标服务,而是直接返回,节约资源,提高服务的稳定性,熔断周期结束后如果目标服务情况好转则恢复调用。

注意:为了服务的稳定性,在执行需要多次 Retry(重试策略)的情况下,最好组合熔断策略,预防可能存在的风险。

熔断状态

zeayEzQ.png!web

  1. 打开(Open)

    熔断器打开状态,此时对目标服务的调用都直接返回错误,熔断周期内不会走网络请求,当熔断周期结束时进入半开状态;

  2. 关闭(Closed)

    关闭状态下正常发生网络请求,但会记录符合熔断条件的连续执行次数,如果错误数量达到设定的阈值(如果在没有达到阈值之前恢复正常,之前的累积次数将会归零),熔断状态进入到打开状态;

  3. 半开(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";
}

rqm6NnJ.png!web

熔断高级配置

根据时间段内总请求数中的异常比例触发熔断:

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("熔断时间到,进入半开状态")                                                   
	);

参考链接


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK