1、熔斷降級的概念:
熔斷:我這里有一根長度一米的鋼鐵,鋼鐵的熔點1000度(假設),現在我想用力把這根鋼鐵折彎,但是人的力有限達不到折彎的點,然后我使用火給鋼鐵加熱,每隔一段時間我就會嘗試一下是否能折彎,在這個過程中我發現,隨着不斷的煅燒,折彎鋼鐵是花費的力氣越小,在這個過程出現了意外因為我的疏忽,溫度超過了鋼鐵的熔點了,導致一根變成的兩根,和我最初的目的相違背了,早知道當初我裝個報警的裝置了還可以提想我。
如果在這個例子中我們把一根鋼鐵換成我們程序中的接口(接口能同時承受1000的訪問),然后把火替換成我們的接口調用者,當接口的並發超過1000這個點的時候接口將會掛掉,作為調用者並不能控制這個點,當並發量上來的時候導致接口蹦了,為了防止我們的接口發生崩潰的情況,我們做一個報警的設置,當發生這個情況的時候占時切斷服務,防止服務崩潰。
降級:接着上一個例子:既然這個鋼鐵因為一個意外導致變成兩個,不能進行使用了,我變找了一個繩子替代一下。
當我們的服務接口發生錯誤的時候,我們可以找到一個替代方法進行使用。這個方法可能是啟用另一台服務器的接口,也可能是只返回“”服務器繁忙請重試的提示“”。總之不會把一個系統級別的問題暴露給用戶,讓使用者的程序也出現問題。
2、Polly的7中策略
處理熔斷降級的框架本人所知 有NetFlix的Hystrix框架和Polly框架我們將使用Polly進行熔斷降級處理。
Polly的概念:Polly是一個被.net基金會支持認可的框架,Polly是一個.NET彈性和瞬態故障處理庫,允許開發人員以流暢和線程安全的方式表達策略,如重試、斷路器、超時、艙壁隔離和回退。
Polly的7種策略:官方文檔是這么說的:
1、重試(Retry):當程序發生短暫的故障、並且故障在延遲后,可以自動糾正的,前期是暫時的我們可以配置自動重試。
2、斷路器(Circuit-Breaker):當一個系統陷入嚴重的問題時,讓系統快速的失敗,比讓用戶一直等待着要好的多,保護一個系統不受過載的影響,可以幫助它快速的恢復。
3、超時(Timeout):在等待一定的時間后,沒有返回相應的結果,保證程序不會一直等待下去,使調用者不必一直的等待下去。
4、隔離(Bulkhead Isolation):當進程出現故障的時,一台主機中的多個失敗的進程,對資源(例如線程/CPU)的一直占用,當下游的系統發生故障的時候,也可能導致上游對資源的調用失敗、這兩種風險的出現都將導致更大范圍的影響、隔離策略是為了防止“一個點的失敗導致整盤的失敗”把受到管理的操作固定在某個資源中,避免影響到其他的資源。
5、緩存(Cache):針對相同的請求,在第一次訪問的時候將響應的數據進行緩存,再次訪問的時候直接在緩存中提供響應的數據。
6、回退(FallBack):當程序發生失敗的情況的時候,我們將做些什么,定義一個在程序發生失敗的時候要執行的動作。
7、策略組合(PolicyWrap):Polly針對不同的故障有不同的策略,我們可以靈活的組合策略,上述的六種策略可以靈活組合使用。
3、Polly的基本用法
因為Polly對NetCore的友好支持,下面我們將使用Core的控制台對Polly的幾種策略進行簡單的演示
首先創建控制台程序
在Nuget的控制台中使用 Install-Package Polly 命令進行安裝
注意:在創建項目的時候命名盡量不要使用Polly命名
Polly 每個版本的介紹 https://www.nuget.org/packages/Polly/
執行命令進行安裝如下圖所示
首先我們要學會並且指定希望Policy 處理的異常:
1 /* 2 *指定Policy希望策略處理的異常/錯誤 3 * 這里只是制定Policy 處理異常的方案不做任何的處理 4 */ 5 6 //單個不加對異常加條件 7 Policy.Handle<Exception>(); 8 9 //單個對處理的異常加上條件 這里的條件指明了當異常的 HResult 值為 -2146233088 時處理異常 10 Policy.Handle<Exception>(ex => ex.HResult == -2146233088); 11 12 //多個使用Or即可 多個不加條件 13 Policy.Handle<HttpRequestException>(). 14 Or<OperationCanceledException>(); 15 16 //多個加條件 17 Policy.Handle<HttpRequestException>(ex => ex.HResult == 00000000). 18 Or<OperationCanceledException>(ex => ex.HResult == 00000000); 19 20 //多個混合加條件 21 Policy.Handle<HttpRequestException>(). 22 Or<OperationCanceledException>(ex => ex.HResult == 00000000). 23 Or<ArgumentException>(ex => ex.HResult == 00000000). 24 Or<ArgumentException>();
下面我們指定一個希望Policy處理的異常,並且完成調用
1 /* 2 *指定Policy 處理的異常/錯誤為 錯誤的基類 Exception 並且給異常加上條件 3 *如果條件不滿足則不做任何處理 4 * 不作處理程序將會報錯 5 6 var PolicyExecute = Policy.Handle<Exception>(ex => ex.HResult == -2146233088).Fallback(() =>//動作 7 { 8 Console.WriteLine($"執行出錯監控的異常為:Exception 異常 HResult值為:-2146233088 "); 9 //Console.WriteLine($"執行出錯監控的異常為:ArgumentException 異常 HResult值為:-2147024809 "); 10 }); 11 12 //執行 13 PolicyExecute.Execute(() => 14 { 15 Console.WriteLine("********************開始執行程序**************************"); 16 //直接拋出異常(Exception) HResult值為 -2146233088 17 throw new Exception(); 18 //throw new ArgumentException(); 19 } 20 ); 21 */
因為throw new Exception();的 HResult 的值為
如圖所示
執行結果為:
當我們使用throw new ArgumentException(); 時 它的HResult 的值為
如圖所示:
執行結果為:
因為我們沒有做任何的處理所以程序直接報錯
上面演示了Policy的基本用法
4、Polly7種策略的使用
1、重試策略(Retry):
1 /* Policy的重試策略 Retry 2 * 如果程序發生錯誤將重新執行 3 次 3 int Count = 0; 4 var PolicyExecutes = 5 Policy<object>.Handle<Exception>(ex => ex.HResult == -2146233088) 6 .Retry(3, (ex, Index) => { 7 Console.WriteLine($"執行出錯監控的異常為:Exception 異常 HResult值為:-2146233088 "); 8 Console.WriteLine($"第{Index}次 Retry(重試)"); 9 } 10 ).Execute(() => 11 { 12 Console.WriteLine("********************開始執行程序**************************"); 13 Count = Count + 1; 14 if (Count > 3) 15 { 16 Console.WriteLine("執行成功"); 17 Console.WriteLine("********************結束執行程序**************************"); 18 return ""; 19 } 20 else 21 { 22 throw new Exception(); 23 } 24 25 }); 26 */
執行結果:
2、斷路器(Circuit-Breaker)
1 /*******************************************************************************************************/ 2 /* Policy的斷路器策略 Circuit-Breaker 3 * 程序首次被訪問如果連續出現三次錯誤后,將暫停3秒,三秒結束后 可以被繼續訪問 4 * 繼續訪問時 如果第一次就出現錯誤 繼續熔斷 5 6 7 var PolicyExecutes = 8 Policy<object>.Handle<Exception>() 9 .CircuitBreaker(3, TimeSpan.FromSeconds(3)); 10 11 //模擬訪問十次 12 for (int i = 0; i < 10; i++) 13 { 14 try 15 { 16 PolicyExecutes.Execute(() => 17 { 18 Console.WriteLine("********************開始執行程序**************************"); 19 throw new Exception("異常"); 20 }); 21 } 22 catch (Exception ex) 23 { 24 Console.WriteLine($"Exception信息{i}" + ex.Message); 25 } 26 //一秒運行一次 27 Thread.Sleep(1000); 28 } 29 */
執行結果:
3、 超時策略(Timeout)
1 /*Policy的超時策略(Timeout) 2 * 程序本身沒有錯誤就是執行的時間超過了我們制定的超時策略的時間然后程序就抓捕到超時的異常 3 4 try 5 { 6 //超時策略 7 Policy policy = Policy.Timeout(3, TimeoutStrategy.Pessimistic); 8 9 policy.Execute(() => 10 { 11 Console.WriteLine("********************開始執行程序**************************"); 12 Thread.Sleep(5000); 13 }); 14 } 15 catch (Exception ex) 16 { 17 Console.WriteLine(ex.Message); 18 } 19 */
執行結果:
4、隔離策略(Bulkhead Isolation)
1 /*Policy的隔離策略(Bulkhead Isolation) 2 * 3 //制定策略最大的並發數為5 4 Policy PolicyExecutes = Policy.Bulkhead(5); 5 //程序運行6次 總會有一個失敗的,但是這個失敗的不會影響其他5個的執行結果 6 for (int i = 0; i < 6; i++) 7 { 8 Task.Factory.StartNew(() => 9 { 10 try 11 { 12 PolicyExecutes.Execute(() => 13 { 14 Console.WriteLine($"********************開始執行程序**************************"); 15 }); 16 } 17 catch (Exception ex) 18 { 19 Console.WriteLine(ex.Message); 20 } 21 }); 22 } 23 */
執行結果:
5、緩存策略(Cache):
1 /*Policy 緩存策略(Cache) 2 * 控制台不方便演示 3 * Policy.Cache 可以指定 過期時間,絕對過期時間,滑動過期時間等 4 5 //Policy 的緩存策略的制定 6 MemoryCache memoryCache = null; 7 var PolicyExecutes = Policy.Cache(memoryCache, TimeSpan.FromMinutes(5)); 8 */
6、 回退(FallBack)
1 /*Pollcy 的回退策略(FallBack) 2 * FallBack 當主程序發生錯誤是我們啟動備用的程序進行程序處理 3 4 var PolicyExecute = Policy.Handle<Exception>().Fallback(() => 5 { 6 Console.WriteLine($"你的程序報錯了,我是替代程序!"); 7 8 }); 9 10 //執行 11 PolicyExecute.Execute(() => 12 { 13 Console.WriteLine("********************開始執行程序**************************"); 14 throw new Exception(); 15 } 16 ); 17 */
執行結果:
7、策略組合(PolicyWrap)
PolicyWrap的上面六種策略可以任意的組合起來使用:我們將超時策略(Timeout)加上回退(FallBack)策略組合使用
1 //Fallback策略 2 Policy PolicyExecute = Policy.Handle<Exception>().Fallback(() => 3 { 4 Console.WriteLine($"你的程序超時了,我是替代程序!"); 5 6 }); 7 //超時策略 8 PolicyExecute = PolicyExecute.Wrap(Policy.Timeout(3, TimeoutStrategy.Pessimistic)); 9 //執行 10 PolicyExecute.Execute(() => 11 { 12 Thread.Sleep(5000); 13 } 14 );
執行結果:
OK
這些只是簡單的演示,官方文檔更加詳細。
下一篇我們是使用 Aop 基於 AspNetCore 的過濾器 實現一下Policy 的使用。
有不足之處 希望大家指出相互學習,
本文原創:轉載請注明出處 謝謝!