Polly 故障處理(二): 熔斷策略

熔斷策略(Circuit-breaker)

如果調(diào)用某個(gè)目標(biāo)服務(wù)出現(xiàn)過(guò)多超時(shí)、異常等情況,可以采取一定時(shí)間內(nèi)熔斷該服務(wù)的調(diào)用,熔斷期間的請(qǐng)求將不再繼續(xù)調(diào)用目標(biāo)服務(wù),而是直接返回,節(jié)約資源,提高服務(wù)的穩(wěn)定性,熔斷周期結(jié)束后如果目標(biāo)服務(wù)情況好轉(zhuǎn)則恢復(fù)調(diào)用。

注意:為了服務(wù)的穩(wěn)定性,在執(zhí)行需要多次 Retry(重試策略)的情況下,最好組合熔斷策略,預(yù)防可能存在的風(fēng)險(xiǎn)。

熔斷狀態(tài)

熔斷狀態(tài)切換流程
  1. 打開(kāi)(Open)

    熔斷器打開(kāi)狀態(tài),此時(shí)對(duì)目標(biāo)服務(wù)的調(diào)用都直接返回錯(cuò)誤,熔斷周期內(nèi)不會(huì)走網(wǎng)絡(luò)請(qǐng)求,當(dāng)熔斷周期結(jié)束時(shí)進(jìn)入半開(kāi)狀態(tài);

  2. 關(guān)閉(Closed)

    關(guān)閉狀態(tài)下正常發(fā)生網(wǎng)絡(luò)請(qǐng)求,但會(huì)記錄符合熔斷條件的連續(xù)執(zhí)行次數(shù),如果錯(cuò)誤數(shù)量達(dá)到設(shè)定的閾值(如果在沒(méi)有達(dá)到閾值之前恢復(fù)正常,之前的累積次數(shù)將會(huì)歸零),熔斷狀態(tài)進(jìn)入到打開(kāi)狀態(tài);

  3. 半開(kāi)(Half-Open)

    半開(kāi)狀態(tài)下允許定量的服務(wù)請(qǐng)求,如果調(diào)用都成功則認(rèn)為恢復(fù)了,關(guān)閉熔斷器,否則認(rèn)為還沒(méi)好,又回到熔斷器打開(kāi)狀態(tài);

熔斷使用說(shuō)明

// 在連續(xù)3次異常后熔斷,并保持1分鐘的熔斷狀態(tài),調(diào)用者將收到斷路保護(hù)的異常信息
Policy
    .Handle<SomeExceptionType>()
    .CircuitBreaker(3, TimeSpan.FromMinutes(1));

熔斷代碼測(cè)試

private static int times = 0;
public static void TestPolicy()
{
  var circuitBreakerPolicy = Policy
      .Handle<Exception>()
      .CircuitBreaker(
        exceptionsAllowedBeforeBreaking: 4,             // 連續(xù)4次異常
        durationOfBreak: TimeSpan.FromMinutes(1),       // 斷開(kāi)1分鐘
        onBreak: (exception, breakDelay) =>             // 斷路器打開(kāi)時(shí)
          Console.WriteLine($"熔斷: {breakDelay.TotalMilliseconds } ms, 異常: " + exception.Message),
        onReset: () =>                                  // 熔斷器關(guān)閉時(shí)
          Console.WriteLine("熔斷器關(guān)閉了"),
        onHalfOpen: () =>                               // 熔斷時(shí)間結(jié)束時(shí),從斷開(kāi)狀態(tài)進(jìn)入半開(kāi)狀態(tài)
          Console.WriteLine("熔斷時(shí)間到,進(jìn)入半開(kāi)狀態(tài)")
      );

  for (int i = 0; i < 12; i++)  // 模擬多次調(diào)用,觸發(fā)熔斷
  {
    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) // 模仿某些錯(cuò)誤情況下拋異常
  {
    throw new Exception("exception message");
  }
  return "success";
}
Circuit breaker

熔斷高級(jí)配置

根據(jù)時(shí)間段內(nèi)總請(qǐng)求數(shù)中的異常比例觸發(fā)熔斷:

var advancedCircuitBreakerPolicy = Policy
  .Handle<Exception>()
  .AdvancedCircuitBreaker(
    failureThreshold: 0.5,                          // 至少50%有異常則熔斷
    samplingDuration: TimeSpan.FromSeconds(10),     // 10秒內(nèi)
    minimumThroughput: 8,                           // 最少共有多少次調(diào)用
    durationOfBreak: TimeSpan.FromSeconds(30),
    onBreak: (exception, breakDelay) =>             // 斷路器打開(kāi)時(shí)
      Console.WriteLine($"熔斷: {breakDelay.TotalMilliseconds } ms, 異常: " + exception.Message),  
    onReset: () =>                                  // 熔斷器關(guān)閉時(shí)
      Console.WriteLine("熔斷器關(guān)閉了"),                                                            
    onHalfOpen: () =>                               // 熔斷時(shí)間結(jié)束時(shí),從斷開(kāi)狀態(tài)進(jìn)入半開(kāi)狀態(tài)
      Console.WriteLine("熔斷時(shí)間到,進(jìn)入半開(kāi)狀態(tài)")                                                   
    );

參考鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容