第四節:Polly基於控制台和Web端用法(熔斷、降級、重試、超時處理等)


一. 簡介

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 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM