熔斷、降級:
熔斷:熔斷就是我們常說的“保險絲”,意為當服務出現某些狀況時,切斷服務,從而防止應用程序不斷地常識執行可能會失敗的操作造成系統的“雪崩”,或者大量的超時等待導致系統卡死等情況,很多地方也將其成為“過載保護”。
降級:降級的目的就是當某個服務提供者發生故障的時候,向調用方返回一個替代響應或者錯誤響應。
介紹:
POLLY是一個.NET回彈和瞬態故障處理庫,它允許開發人員以流暢和線程安全的方式表達諸如重試、斷路器、超時、隔板隔離和回退等策略。github官方解釋嘿嘿。
Polly以.NET Standard 1.1(覆蓋范圍:.NET Framework 4.5-4.6.1,.NET Core 1.0,Mono,Xamarin,UWP,WP8.1 +)
.NET Standard 2.0+(覆蓋范圍:.NET Framework 4.6.1, .NET Core 2.0+以及后來的Mono,Xamarin和UWP目標)
安裝:
首先當然是創建一個控制台項目,然后通過NuGet安裝:
Install-Package Polly
出現以上界面就說明你已經安裝了最新的版本到你的項目;
策略介紹:
polly通過官方介紹我們可以知道有7種恢復策略,先不管會不會,先列出來再說哈哈:
重試策略(Retry):許多故障是短暫的,並且在短暫的延遲后可能會自我糾正。允許我們做的是能夠自動配置重試機制
斷路器(Circuit-breaker):當一個系統嚴重掙扎時,快速失敗優於讓用戶/呼叫者等待。 說白了就是應該優先直接返回失敗,而不是一直讓用戶等待。保護故障系統免受過載可以幫助恢復。
超時(Timeout):超時策略針對的前置條件是超過一定的等待時間,想要得到成功的結果是不可能的,保證調用者不必等待超時。
隔板隔離(Bulkhead Isolation):隔板隔離針對的前置條件是當進程出現故障時,多個失敗一直在主機中對資源(例如線程/ CPU)一直占用。下游系統故障也可能導致上游失敗。這兩個風險都將造成嚴重的后果。都說一粒老鼠子屎攪渾一鍋粥,而Polly則將受管制的操作限制在固定的資源池中,免其他資源受其影響。
緩存(Cache):就是一些請求,會把數據緩存起來,然后在持續一段時間內,直接從緩存中取。
回退(Fallback):操作仍然會失敗,也就是說當發生這樣的事情時我們打算做什么。也就是說定義失敗返回操作。我們在使用時就是所說的降級。
策略包裝(PolicyWrap):不同的故障需要不同的策略 彈性意味着使用組合。
使用步驟:
polly一般分為三步進行:
-
定義條件: 定義你要處理的 錯誤異常/返回結果
-
定義處理方式 : 重試,熔斷,回退
-
執行
定義條件:
.Handle<ExceptionType>():限定條件的單個異常Policy;
.Handle<ExceptionType>(ex => ex.Number == 10):具有條件的單個異常類型。
.Handle<HttpRequestException>() .Or<OperationCanceledException>():多個異常類型,當然他也可以變成具有條件的多個異常類型,類似於單個操作。
定義返回結果的條件:
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.NotFound):用條件處理返回值,處理單個返回值。
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError) .OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.BadGateway):處理多個返回值。
指定策略(重試):
.Retry():重試一次。
.Retry(3):重試三次,修改數值即可定義自己想使用的次數。
.Retry(3, (exception, retryCount) => { // do something }):重試多次,在每次重試都執行一個操作,參數為:當前異常和重試計數。
.Retry(3, (exception, retryCount, context) => { // do something }):重試多次,在每次重試都執行一個操作,參數為:當前異常,重試計數和上下文
.RetryForever():永遠重試直到成功,同時也也有重試的相同擴展,可以寫參數。
.WaitAndRetry(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3) }):等待並重試,就是在每個重試的時候需要等待指定的執行時間,同樣有相同擴展,可以在每個重試調用一個操作。
.WaitAndRetryForever(retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) ):等待和重試永遠(直到成功)
指定策略(熔斷):
.CircuitBreaker(2, TimeSpan.FromMinutes(1)):在指定數量的連續異常之后中斷開。這里就不做過多解釋了。
指定策略(降級):回退
.Fallback<UserAvatar>(UserAvatar.Blank):如果執行錯誤,則提供替代值,就是出現錯誤,定義一個返回值給他
.Fallback<UserAvatar>(() => UserAvatar.GetRandomAvatar()) :定義一個方法給他,該方法代替提供值。
執行:
.Execute(() => DoSomething()):執行一項方法
執行通過任意上下文數據的操作:
var policy = Policy .Handle<SomeExceptionType>() .Retry(3, (exception, retryCount, context) => { var methodThatRaisedException = context["methodName"]; Log(exception, methodThatRaisedException); }); policy.Execute( () => DoSomething(), new Dictionary<string, object>() {{ "methodName", "some method" }} );
使用示例:
降級的使用代碼:

#region 降級 public static void Downgrade() { //降級處理程序 ISyncPolicy policy = Policy.Handle<ArgumentException>() .Fallback(() => { Console.WriteLine("降級給的返回值結果"); }); //運行程序 policy.Execute(() => { Console.WriteLine("任務開始"); throw new ArgumentException("降級任務出錯,馬上要降級了"); Console.WriteLine("任務結束"); }); } #endregion
運行結果:
重試機制的代碼:
出錯后重復3次。

#region 重試機制 public static void Retry() { //配置重試次數 ISyncPolicy policy = Policy.Handle<Exception>().Retry(3); try { policy.Execute(() => { Console.WriteLine("任務開始"); if (DateTime.Now.Second % 10 != 0) { throw new Exception("任務出錯了,開始重試"); } Console.WriteLine("任務結束"); }); } catch (Exception ex) { Console.WriteLine("異常結果 : " + ex.Message); } } #endregion
運行結果:
熔斷機制代碼:
但出現錯誤連續三次后,等待20秒后進行

#region 熔斷機制 public static void Fusing() { Action<Exception, TimeSpan> onBreak = (exception, timespan) => { Console.WriteLine("1"); }; Action onReset = () => { Console.WriteLine("2"); }; ISyncPolicy policy = Policy.Handle<Exception>().CircuitBreaker(3, TimeSpan.FromSeconds(20), onBreak, onReset); while (true) { try { policy.Execute(() => { Console.WriteLine("任務開始"); throw new Exception("出錯了"); Console.WriteLine("任務結束"); }); } catch (Exception ex) { Console.WriteLine("---------------異常結果-------------- : " + ex.Message + "時間:" + DateTime.Now); } System.Threading.Thread.Sleep(5000); } } #endregion
運行結果:
混合示例(重試+降級)代碼:
出錯重試三次后第四次進行降級處理:主要是warp方法來實現的,特別說明warp方法是:最外面(在左邊)到最里面(右邊)的策略。也就是說從右向左執行方法;

#region 重試+降級 public static void RetryDowngrade() { try { //降級處理程序 ISyncPolicy policy = Policy.Handle<Exception>() .Fallback(() => { Console.WriteLine("降級成功"); }); //配置重試次數 ISyncPolicy policy2 = Policy.Handle<Exception>().Retry(3, (exception, retryCount, context) => { Console.WriteLine(retryCount); }); //合並 ISyncPolicy mainPolicy = Policy.Wrap(policy, policy2); mainPolicy.Execute(() => { Console.WriteLine("任務開始"); throw new Exception("出錯了"); Console.WriteLine("任務結束"); }); } catch (Exception ex) { Console.WriteLine("異常結果 : " + ex.Message); } } #endregion
運行結果:
源碼下載:PollyConsole.rar
系列目錄
微服務系列文章主要介紹微服務所使用到的一些技術和一些技術示例: