一. 簡介
1. Polly是什么?
Polly是 .Net Core 中有一個被.Net 基金會認可的庫 ,可以用來簡化熔斷降級的處理。主要功能:失敗處理-即降級(FallBack)、斷路器-即熔斷(CircuitBreaker)、重試(Retry)、超時檢測(Timeout)、緩存(Cache)。java中的同類框架是著名的Hystrix。
2. 相關地址
(1). 官網:http://www.thepollyproject.org/
(2). GitHub:https://github.com/App-vNext/Polly
(3). 兩個程序集:
官方的:【Polly 7.2.1】
微軟封裝的:【Microsoft.Extensions.Http.Polly 3.1.5】
3. 如何理解熔斷和降級
調用端:指發送請求的端. 服務(Server)端:指提供Api接口的端。
首先我們要明確的是熔斷和降級都是作用在調用端上的,與Server端沒關系。
(1).熔斷:是指當Server端出現宕機或超時情況,調用端所采用的一種策略應對機制,從而防止調用端不斷地長時間執行可能會失敗的操作,從而造成系統的“雪崩”, 或者大量的超時等待導致系統卡死等情況,很多地方也將其稱為“過載保護”。
PS:在Polly中熔斷指 CircuitBreaker,即連續n次失敗,就熔斷一段時間,在這段時間內,不發送請求,走的是polly拋出的異常(報錯:The circuit is now open and is not allowing calls.)。
(2).降級:是指當Server端發生故障,調用端這里返回一個替代方案或者錯誤響應。比如:短信服務,假設最佳的是調用聯通接口,但聯通調用失敗,我們退而求其次,降級調用移動的,移動的也失敗,那么我們就返回失敗響應了.
PS:在Polly中降級指FallBack,走fallback中的業務,原策略業務 拋異常處 后面的代碼不再執行了。
二. 基於控制台用法
前提:通過Nuget安裝 【polly 7.2.1】
1.降級(Fallback)
{ Policy policy = Policy.Handle<ArgumentException>() //故障1 .Or<ArgumentOutOfRangeException>() //故障2 .Or<IndexOutOfRangeException>() //故障3 .Fallback(() => { //降級執行的動作 Console.WriteLine("我是降級后的執行的操作"); }); policy.Execute(() => { //執行業務代碼 Console.WriteLine("開始任務"); throw new ArgumentException("類型轉換失敗"); Console.WriteLine("結束任務"); }); }
運行結果:
2.降級-獲取異常
{ Policy policy = Policy.Handle<ArgumentException>() //故障1 .Or<ArgumentOutOfRangeException>() //故障2 .Or<IndexOutOfRangeException>() //故障3 .Fallback(() => { //降級執行的動作 Console.WriteLine("我是降級后的執行的操作"); }, ex => { Console.WriteLine($"業務報錯信息為:{ex.Message}"); }); policy.Execute(() => { //執行業務代碼 Console.WriteLine("開始任務"); throw new ArgumentException("類型轉換失敗"); Console.WriteLine("結束任務"); }); }
運行結果:
3.降級-獲取返回值
{ Policy<string> policy = Policy<string>.Handle<ArgumentException>() //故障 .Fallback(() => { //降級執行的動作 Console.WriteLine("我是降級后的執行的操作"); return "我是降級業務中的返回值"; }); string value = policy.Execute(() => { //執行業務代碼 Console.WriteLine("開始任務"); throw new ArgumentException("類型轉換失敗"); Console.WriteLine("結束任務"); return "我是正常業務中的返回值"; }); Console.WriteLine($"最終結果為:{value}"); }
運行結果:
4.熔斷機制
//下面設置的是連續出錯3次之后熔斷10秒,意思是:連續出錯3次后,熔斷10s,在這10s內,再次訪問,不再執行Execute中的代碼,直接報錯, //10s熔斷時間過后,繼續訪問,如果還是出錯(出一次即可),直接熔斷10s, 再次重復這個過程 { Policy policy = Policy .Handle<Exception>() .CircuitBreaker(3, TimeSpan.FromSeconds(10)); //連續出錯3次之后熔斷10秒(不會再去嘗試執行業務代碼)。 while (true) { Console.WriteLine("開始Execute"); try { policy.Execute(() => { Console.WriteLine("-------------------------------------開始任務---------------------------------------"); throw new Exception(); Console.WriteLine("完成任務"); }); } catch (Exception ex) { Console.WriteLine("execute出錯" + ex.Message); } Thread.Sleep(2000); } }
運行結果:
5.重試機制
指業務執行出錯后,重新執行n次(總共執行了n+1次),這期間如果成功了,則后面不再執行,如果不成功,重試n次后,會把異常拋出來. 或者一直重復,直到成功。
(1).Retry:出錯后重新執行n次,期間成功則停止后續重試; 期間不成功,最后可以捕獲異常.
(2).RetryForever:出錯后一直重試,直到成功才停止.
(3).WaitAndRetry:出錯后重新執行n次,每次間隔m秒.
{ try { Policy policy = Policy .Handle<Exception>() .Retry(3); //出錯后,連續執行3次 //.RetryForever();//出錯后,連續執行,直到成功為止 //.WaitAndRetry(5, i => TimeSpan.FromSeconds(2)); //重試5次,每次間隔2s int g = 0; policy.Execute(() => { Console.WriteLine($"開始任務,g={g}"); if (g < 10) { g++; throw new Exception("業務出錯了"); } Console.WriteLine("完成任務"); }); } catch (Exception ex) { Console.WriteLine($"捕獲異常:{ex.Message}"); } }
運行結果
6.組合機制
使用Wrap包裹,eg:policy6=Policy.Wrap(policy1, policy2)
注意:Wrap是有包裹順序的,內層的故障如果沒有被處理則會拋出到外層.
(1).超時3秒降級:超時相關的 Policy.Timeout(3, TimeoutStrategy.Pessimistic);
{ //1.1 超時3秒 Policy policytimeout = Policy.Timeout(3, TimeoutStrategy.Pessimistic); //1.2 降級 Policy policyFallBack = Policy.Handle<TimeoutRejectedException>() .Fallback(() => { //降級執行的動作 Console.WriteLine("我是降級后的執行的操作"); }, ex => { //捕獲業務中的出錯信息 Console.WriteLine(ex.Message); }); //1.3 將超時和降級操作進行組合 Policy policy = policyFallBack.Wrap(policytimeout); //1.4 執行業務代碼 policy.Execute(() => { Console.WriteLine("開始任務"); Thread.Sleep(5000); Console.WriteLine("完成任務"); }); }
運行結果:
(2).重試+降級:重試3次,期間成功,則繼續執行后面業務;期間失敗,則走外層的降級操作
{ //2.1 遇到異常重試3次 Policy policyRetry = Policy.Handle<Exception>().Retry(3); //2.2 降級操作 Policy policyFallback = Policy.Handle<Exception>() .Fallback(() => { //降級執行的動作 Console.WriteLine("我是降級后的執行的操作"); }, ex => { //捕獲業務中的出錯信息 Console.WriteLine(ex.Message); }); //Wrap:包裹。policyRetry在里面,policyFallback在外面,如果里面出現了故障,則把故障拋出來給外面 //2.3 進行包裹(出現錯誤,先重試3次,期間成功,則繼續執行后面業務;期間失敗,則走外層的降級操作) Policy policy = policyFallback.Wrap(policyRetry); int g = 0; //2.4 執行業務代碼 policy.Execute(() => { Console.WriteLine($"開始任務,g={g}"); if (g < 10) { g++; throw new Exception("業務出錯了"); } Console.WriteLine("完成任務"); }); }
運行結果:
(3).熔斷+降級:Execute執行業務代碼無須再用Try-catch包裹,否則不拋異常,則無法降級,我們這里演示的是降級,並在降級中拿到業務代碼的異常信息
{ //3.1 熔斷 Policy policyCBreaker = Policy.Handle<Exception>() .CircuitBreaker(3, TimeSpan.FromSeconds(10)); //連續出錯3次之后熔斷10秒(不會再去嘗試執行業務代碼)。 //3.2 降級 Policy policyFallback = Policy.Handle<Exception>() .Fallback(() => { //降級執行的動作 Console.WriteLine("我是降級后的執行的操作"); }, ex => { //這里是捕獲業務代碼中的錯誤,業務代碼中就不要再寫try-catch,否則不拋異常,則無法降級 Console.WriteLine($"業務報錯信息為:{ex.Message}"); }); //3.4 包裹 Policy policy = policyFallback.Wrap(policyCBreaker); //3.4 執行業務 while (true) { Console.WriteLine("開始Execute"); //try //{ policy.Execute(() => { Console.WriteLine("-------------------------------------開始任務---------------------------------------"); throw new Exception(); Console.WriteLine("完成任務"); }); //} // 不要再寫try-catch,否則不拋異常,則無法降級 //catch (Exception ex) //{ // Console.WriteLine("execute出錯" + ex.Message); //} Thread.Sleep(2000); } }
運行結果:
三. 基於Web端用法
后續補充。。
!
- 作 者 : Yaopengfei(姚鵬飛)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 如有錯誤,歡迎討論,請勿謾罵^_^。
- 聲 明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。