熔斷策略(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("熔斷時間到,進入半開狀態")
);