Polly熔斷降級快速入門

一、什麼是熔斷降級

熔斷一詞我們可以聯想到保險絲的熔斷,保險絲也是一種應急機制,當我們線路中某處發生短路造成瞬間的電流過大,保險絲就會熔斷以保護我們的線路和其他用電器。微服務中的熔斷和保險絲的熔斷起到的是類似這作用

我們之前講解了使用了Consul做服務治理和健康檢查。即使有健康檢查,如果某個服務器或者服務掛掉,會在指定時間內對該服務進行清理。但是也無法做到100%正在這個壞掉的服務杯清理之前還被繼續的訪問。還有一個場景就是,我們的服務器並沒有掛,consul健康檢查的時候也是正常響應的,可能是業務邏輯問題造成的響應時間太長等等問題,在高併發場景下,一但某個服務一直超時最終肯定也會導致服務崩潰然後波及其他服務。

那什麼是降級呢?舉個例子,高考後的擇校,選擇大學肯定是優先考慮清華北大等985/211等重點大學,但是我們的分數達不到這個層次的時候只能降低等級選擇一二本學校,分數再達不到,我們只能再次降低標準就讀專科學校。總之雖然不能滿足最高期望,但還是能夠有大學上的,除非交白卷那沒法子。在我們的系統中也是如此,我們當然希望給用戶最好的體驗和服務,再舉個例子,查詢最新的數據。最新最權威的數據肯定是在數據庫中,緩存中的數據可能存在延遲。但是如果我們的數據庫服務器宕機了,不應立馬告訴用戶查詢失敗,而是降級到緩存中查找,如果緩存也沒了實在沒辦了,再返回查找失敗。這樣無形就提升了用戶體驗。

二、Polly 簡介

Polly是一個被.Net基金會認可的庫,可以用來簡化熔斷降級的處理。主要功能包括:

重試(Retry)

斷路器(Circuit-breaker)

超時檢測(Timeout)

緩存(Cache)

降級(FallBack)

官網:http://www.thepollyproject.org/

安裝:通過Nuget安裝

2.1Polly策略

polly的策略由“問題故障”和“應對動作”兩個部分組成 。故障包括:異常、超時等情況,動作包括:重試(Retry)、斷路器(Circuit-breaker)、超時檢測(Timeout)、緩存(Cache)、降級(FallBack)。

三、Polly的使用

3.1降級

        static void Main(string[] args)
        {
            //聲明Policy處理ArgumentException異常
            Policy policy = Policy.Handle<ArgumentException>()
                //出現異常時的動作
                .Fallback(() =>
                {
                    Console.WriteLine("出錯了");
                });
            //沒有異常時正常正常的業務邏輯
            policy.Execute(() =>
            {
                Console.WriteLine("正常情況下:開始執行");
                Console.WriteLine("正常情況下:執行結束");
            });
        }

以上代碼聲明Policy處理ArgumentException異常,處理異常大動作爲降級,policy.Execute()方法是指沒有發生異常時,我們的業務邏輯。

運行代碼

手動拋出ArgumentException異常 

policy.Execute(() =>
            {
                Console.WriteLine("正常情況下:開始執行");
                throw new ArgumentException();
                Console.WriteLine("正常情況下:執行結束");
            });

可以看到,出現 ArgumentException異常後程序執行了Fallback(),我們上面定義的Policy監控的是ArgumentException異常,如果拋出的不是ArgumentException異常,還會執行Fallback()嗎?

            policy.Execute(() =>
            {
                Console.WriteLine("正常情況下:開始執行");
                throw new Exception();
                Console.WriteLine("正常情況下:執行結束");
            });

顯然 當異常類型與定義監控異常類型不匹配的情況下是不會執行Fallback()的

3.2重試

  • RetryForever()一直重試,不建議使用
  • Retry()只重試一次
  • Retry(N)至多重試N次
  • WaitAndRetry()

這裏以 Retry(N)爲例子

            Policy policy = Policy.Handle<Exception>()
        .Retry(5);
            policy.Execute(() =>
            {
                Console.WriteLine("正常情況下:開始執行");
                throw new Exception();
                Console.WriteLine("正常情況下:執行結束");
            });

運行結果可以看到重試5次加上第一次一共執行了6次。

3.3熔斷

出現N次連續錯誤,則將服務熔斷,等待一段時間,等待這段時間內如果在再Execute()則會直接拋出BrokenCircuitException異常。等待時間過後,再執行Execute()的時候還是錯誤的話,那麼繼續熔斷一段時間,如果正確則回覆正常。我們可以聯想一下類似場景,登錄的時候如果密碼錯誤超過三次,將需要等待一段時間纔可以繼續執行登錄,在這段時間內點擊登錄按鈕,直接告知當前不可以登錄。等待時間後進行登錄,如果還是錯誤那麼又得繼續等待。如果這一次正確了,那就回復正常登錄,並且重新獲得3次錯誤機會。這樣避免了一個服務已經不可用了,還不斷接受請求給系統造成更大壓力。

 Policy policy = Policy.Handle<Exception>()
        .CircuitBreaker(3, TimeSpan.FromSeconds(10));

            policy.Execute(() =>
            {
                Console.WriteLine("正常情況下:開始執行");
                throw new Exception();
                Console.WriteLine("正常情況下:執行結束");
            }); 

3.4策略封裝

策略封裝就是把多個ISyncPolicy合併一起執行,

policy3=policy1.Wrap(policy2);

policy3會把policy1和policy2封裝一起執行。

這樣說可能比較抽象,舉個例子,要實現“出現異常則重試3次,如果還錯那就進行降級”。

            //重試3次
            Policy policyRetry = Policy.Handle<Exception>()
                .Retry(3);
            //降級
            Policy policyFallback = Policy.Handle<Exception>()
               .Fallback(() =>
               {
                   Console.WriteLine("降級了");
               });
            //重試三次後降級
            Policy policyWarp = policyFallback.Wrap(policyRetry);
            policyWarp.Execute(() =>
            {
                Console.WriteLine("開始執行");
                for (int i = 0; i < 100; i++)
                {
                    if (i % 2 == 0)
                        throw new Exception("出錯了");
                }
                Console.WriteLine("執行結束");
            }); 

3.5超時 

上面說的都是業務邏輯錯誤拋出異常的處理,但實際上還有一種場景就是,程序並沒有報錯,只是執行時間過長,這種沒有具體的異常的超時場景,Polly提供了超時策略。但是超時策略得配合其他策略使用。

            //超時
            Policy policyTimeout = Policy.Timeout(3, TimeoutStrategy.Pessimistic);
            //降級
            Policy policyFallback = Policy.Handle<Exception>()
                .Fallback(() =>
                {
                    Console.WriteLine("降級");
                });
            Policy policy = policyFallback.Wrap(policyTimeout);
            policy.Execute(() =>
            {
                Console.WriteLine("開始執行");
                Thread.Sleep(5000);//阻塞5秒鐘,模擬超時
                Console.WriteLine("執行結束");
            });

我們人爲的讓線程阻塞5秒鐘,模擬超時。程序最終會去執行降級操作。

Polly提供的遠不止這些,每種策略都有着很多重載。限於篇幅,無法一一列舉,我們可以在工作中根據業務需求再根據文檔選擇合適的重載實現。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章