接著上一篇說,正好也是最近專案裡用到了,正好拿過來整理一下,園子裡也有一些文章介紹比我詳細。
簡單介紹一下紹輕量的故障處理庫 Polly Polly是一個.NET彈性和瞬態故障處理庫
允許我們以非常順暢和執行緒安全的方式來執行諸如重試、斷路器、超時、隔離、快取、後退等策略, 能為我們在微服務架構提供更穩定的服務。當然,目前的 Service Mesh 顯得更高大上,而且更強大,它更偏向從運維層面解決以上問題,不過這還是的看具體專案中怎麼去使用和決定了。
在微服務架構下,我們可能會遇到類似以下問題:
- 某些介面異常,最終造成應用程式池奔潰;
- 某些介面不穩定、偶爾超時,資料獲取異常;
- 某些服務不穩定,呼叫方連線不上;
- 某些服務異常,最終主服務掛掉(雪崩效應);
當然在實際情況下,我們可能只需要確保提供給使用者的服務是可用狀態,不出現 “Service Unavailable” 這樣的畫面就好。至於介面偶爾異常,可能對某些型別的專案來說並不太關鍵,使用者可能通過重新請求、重新整理頁面就可以解決,當然我們還可以在程式碼層面做相容,滿滿的try/catch、for/while 迴圈解決重試來保證更高的可靠性。
這個時候Polly就能很好的起來作用,Polly 的使用相對比較簡單,當然還是得看專案結構。我們的主專案在呼叫微服務介面時使用了AOP,類似這種情況下,所以呼叫微服務的介面都是統一入口,所以我們只需要在AOP內加上 Polly 的一些策略,其他程式碼不用做任何修改,就可以解決一些問題了。
安裝
Install-Package Polly
使用步驟說明
- 定義策略
- 執行方法
可以看一下程式碼,我們專案主要使用的是Grpc這個框架,其他的微服務框架,使用起來大致差不多
public void Intercept(IInvocation invocation) { // some code try { // 建立一個策略,如果 invocation.Proceed 的執行出現 Grpc.Core.RpcException 異常,並且 StatusCode == Grpc.Core.StatusCode.Unavailable,則重試一次 var policy = Policy .Handle<Grpc.Core.RpcException>(t => t.Status.StatusCode == Grpc.Core.StatusCode.Unavailable) .Retry(); // 預設一次 // 將策略應用到 invocation.Proceed 方法上 policy.Execute(invocation.Proceed); } catch (Exception ex) { // some code Console.WriteLine($"{ ex.Message},{ex.StackTrace}"); } }
策略條件定義
策略的執行需要依賴於條件,Polly 支援對異常與結果進行策略條件定義。
異常
// 指定某個異常 Policy .Handle<SomeExceptionType>(); // 指定某個異常條件 Policy .Handle<SomeExceptionType>(ex => ex.xxx == "xxx") // 指定多個異常 Policy .Handle<SomeExceptionType1>() .Or<SomeExceptionType2>() // 指定多個可能異常條件 Policy .Handle<SomeExceptionType1>(ex => ex.xxx1 == "xxx") .Or<SomeExceptionType2>(ex => ex.xxx2 == "xxx")
返回結果
// 指定某個結果 Policy .HandleResult<ResponseMessage>(r => r.xxx == "xxx") // 指定多個可能的結果 Policy .HandleResult<ResponseMessage>(r => r.xxx1 == "xxx") .OrResult<ResponseMessage>(r => r.xxx2 == "xxx")
重試策略(Retry )
// 指定異常下重試一次 Policy .Handle<SomeExceptionType>() .Retry(); // 指定異常下重試3次 Policy .Handle<SomeExceptionType>() .Retry(3); // 指定異常下無限重試 Policy .Handle<SomeExceptionType>() .RetryForever(); // 每次重試之間等待指定的時間間隔 Policy .Handle<SomeExceptionType>() .WaitAndRetry(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7) });
Retry 可以指定一個要執行的 Action。Action 引數:exception 當前異常資訊,retryCount 當前執行第幾次,context 當前執行上下文資訊。
測試一下:
private static int times = 0; public static void TestPolicy() { var policy = Policy .Handle<Exception>() .Retry(3, (exception, retryCount, context) => // 出異常會執行以下程式碼 { Console.WriteLine($"exception:{ exception.Message}, retryCount:{retryCount}, id:{context["id"]}, name:{context["name"]}"); }); try { // 通過 new Context 傳遞上下文資訊 var result = policy.Execute(Test, new Context("data", new Dictionary<string, object>() { { "id", "1" }, { "name", "beck" } })); Console.WriteLine($"result:{result}"); } catch (Exception ex) { Console.WriteLine(ex.Message); } } private static string Test() { // 每執行一次加1 times++; // 前2次都拋異常 if (times < 3) { throw new Exception("exception message"); } return "success"; }
測試結果:
可以看到得到了我們們想要的效果,具體專案可以具體去實施,下一篇我們們接著說Polly的熔斷策略。感興趣可以自行搜尋Polly的相關文件看看。
參考連結
沒有彩蛋