Polly:提升服务可用性
Polly是.NET生態非常著名的組件包
一 介紹
Polly?的能力
??失敗重試:當我們服務調用失敗時,能夠自動的重試
??服務熔斷:當我們服務部分不可用時,我們的應用可以快速響應一個熔斷結果,避免持續的請求這些不可用的服務而導致整個應用程序出現問題
??超時處理:我們為服務的請求設置一個超時時間,當超過超時時間可以按照我們預定的操作進行處理,比如返回一個緩存的結果。
??艙壁隔離:實際上是一個限流的功能,我們可以為服務定義最大的流量和隊列,這樣可以避免我們的服務因為請求量過大而被壓崩。
??緩存策略:可以讓我與類似于AOP方式為應用嵌入緩存的機制,當緩存命中時,我們可以快速地響應緩存,而不是持續的請求服務。
??失敗降級:當我們的服務不可用時,我們可以響應一個更友好的結果而不是報錯。
??組合策略:可以讓我們將上面的 策略組合在一起,按照一定的順序,我們可以對不同的場景組合不同的策略類,實現我們的應用程序。
Polly?使用步驟
??定義要處理的異常類型或返回值
??定義要處理動作(重試、熔斷、降級響應等)
??使用定義的策略來執行代碼
適合失敗重試的場景
??服務“失敗”是短暫的,可自愈的
在失敗的場景里,我們可以非常有效的避免這種網絡閃斷這種情況
??服務是冪等的,重復調用不會有副作用
在失敗重試情況下,有可能會造成多次調用的情況,因為有些失敗,可能是你的命令已經發出了,但是你沒收到響應,它會重試。
場景舉例
??網絡閃斷
??部分服務節點異常
重試的過程可能就可以命中到正常的節點
最佳實踐
??設置失敗重試次數
??設置帶有步長策略的失敗等待間隔
??設置降級響應
??設置斷路器
盡量設置重試的次數,盡量設置不同的間隔,否則會造成類似于DDOS的情況,當我們的重試的次數達到上限以后,我們應該為服務提供一個降級的響應,更友好的響應結果。(DDOS 全稱Distributed Denial of Service,中文意思為“分布式拒絕服務”,就是利用大量合法的分布式服務器對目標發送請求,從而導致正常合法用戶無法獲得服務)
策略的類型
??被動策略(異常處理、結果處理)
??主動策略(超時處理、斷路器、艙壁隔離、緩存)
組合策略
??降級響應
??失敗重試
??斷路器
??艙壁隔離
策略與狀態共享
| Policy類型 | 狀態 | 說明 |
| CircuitBreaker(斷路器) | 有狀態 | 共享成功失敗率,以決定是否熔斷 |
| Bulkhead(艙壁隔離) | 有狀態 | 共享容量使用情況,以決定是否執行動作 |
| Cache(緩存) | 有狀態 | 共享緩存的對象,以決定是否命中 |
| 其它策略 | 無狀態 | - |
有狀態:時間參數、次數參數等計數實例來承載的,對不同的服務進行定義不同的策略
二? 應用
我們本次使用的組件包如下:
Polly?
Polly.Extensions.Http?
Microsoft.Extensions.Http.Polly
瞬時Http錯誤重試策略
錯誤規則
網絡故障(HttpRequestException)
HTTP 5XX 狀態代碼(服務器錯誤)
HTTP 408 狀態代碼(請求超時)
有關配置策略的指南,請參閱有關 PolicyHttpMessageHandler 的備注。
使用自定義的Http錯誤重試策略
可以根據HttpResponseMessage定義自己的重試條件
public void ConfigureServices(IServiceCollection services) {//定義自己的策略 var reg = services.AddPolicyRegistry();//根據返回的狀態碼自定義自己的返回策略 reg.Add("retryforever", Policy.HandleResult<HttpResponseMessage>(message => {return message.StatusCode == System.Net.HttpStatusCode.Created;}).RetryForeverAsync());//配置httpclient使用retryforever 的策略 services.AddHttpClient("myClient2"). AddPolicyHandlerFromRegistry("retryforever");//根據HttpRequestMessage 來定義策略 services.AddHttpClient("myClient3"). AddPolicyHandlerFromRegistry((registry, message) => { return message.Method == HttpMethod.Get ?registry.Get<IAsyncPolicy<HttpResponseMessage>>("retryforever") :Policy.NoOpAsync<HttpResponseMessage>();});} });}熔斷策略
public void ConfigureServices(IServiceCollection services) {//熔斷services.AddHttpClient("myClient4").AddPolicyHandler(Policy<HttpResponseMessage>.Handle<HttpRequestException>().CircuitBreakerAsync( //報錯10次后盡行熔斷 handledEventsAllowedBeforeBreaking: 10, //熔斷的時間 10秒 durationOfBreak: TimeSpan.FromSeconds(10), //當我們熔斷時觸發的一個事件 onBreak: (r, t) => { },//當我們熔斷恢復時的事件 onReset: () => { }, //在我們恢復之前進行驗證服務是否可用? //打一部分的流量去驗證我們的服務是否可用的事件 onHalfOpen: () => { })); }高級熔斷策略
public void ConfigureServices(IServiceCollection services) { //高級熔斷策略 services.AddHttpClient("myClient4"). AddPolicyHandler(Policy<HttpResponseMessage>. Handle<HttpRequestException>(). AdvancedCircuitBreakerAsync( //比例0.8服務出錯進行熔斷 failureThreshold: 0.8, //10秒以內 請求出錯比例0.8 進行熔斷 samplingDuration: TimeSpan.FromSeconds(10), //最小的吞吐量100? //當我們請求量比較小的時候 //比如說我們十秒采樣范圍內? //當我們的請求數超過100個時才會進行熔斷? //當請求量比較小的時候是不需要熔斷 minimumThroughput: 100, //熔斷的時長 20秒 durationOfBreak: TimeSpan.FromSeconds(20), //當我們熔斷時觸發的一個事件 onBreak: (r, t) => { }, //當我們熔斷恢復時的事件 onReset: () => { }, //在我們恢復之前進行驗證服務是否可用? //打一部分的流量去驗證我們的服務是否可用的事件 onHalfOpen: () => { }));}服務降級策略
publicvoid ConfigureServices(IServiceCollection services)
{//定義服務降級的策略//當我們遇到熔斷時 我們響應一個異常的友好結果//定義我們的熔斷 var breakPolicy = Policy<HttpResponseMessage>.Handle<HttpRequestException>().AdvancedCircuitBreakerAsync(//百分之八十的服務出錯進行熔斷failureThreshold: 0.8, //10秒以內 請求出錯比例0.8 進行熔斷 samplingDuration: TimeSpan.FromSeconds(10), //最小的吞吐量100 //當我們請求量比較小的時候,比如說我們十秒采樣范圍內 //當我們的請求數超過00個時才會進行熔斷 //當請求量比較小的時候是不需要熔斷 minimumThroughput: 100, //熔斷的時長 20秒 durationOfBreak: TimeSpan.FromSeconds(20), //當我們熔斷時觸發的一個事件 onBreak: (r, t) => { }, //當我們熔斷恢復時的事件onReset: () => { }, //在我們恢復之前進行驗證服務是否可用 //打一部分的流量去驗證我們的服務是否可用的事件 onHalfOpen: () => { } ); //定義返回結果 var message2 = new HttpResponseMessage() { Content = new StringContent("{\"IsError\":true,\"ErrorMsg\":\"服務異常\"}") }; };//定義降級策略 var fallback = Policy<HttpResponseMessage>.Handle<BrokenCircuitException>().FallbackAsync(message2);//定義重試 var retry = Policy<HttpResponseMessage>. Handle<Exception>(). WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(1)); //定義請求策略組合 var fallbackBreak = Policy.WrapAsync(fallback, retry, breakPolicy); //注入HttpClient定義策略 services.AddHttpClient("myClient5"). AddPolicyHandler(fallbackBreak); }}限流策略
public void ConfigureServices(IServiceCollection services) {//限流//定義請求的并發是多少var bulk = Policy.BulkheadAsync<HttpResponseMessage>(??//最大請求并發數????maxParallelization: 30,// 當我們請求超過30的并發數時//?剩下的請求怎么處理的問題// 如果我們不定義我們的隊列數// 它就會拋出異常//?如果定義了隊列數// 可以有20個請求在隊列里排隊// 只有超出隊列的請求才會拋出異常// 讓多出來的請求不至于直接報錯maxQueuingActions: 20,//當我們的請求超出了并發數時怎么處理 這里可以定義自己的規則????onBulkheadRejectedAsync: context => Task.CompletedTask);var message3 = new HttpResponseMessage(){Content = new StringContent("{}")};//定義超出并發數策略 var fallback2 = Policy<HttpResponseMessage>.Handle<BulkheadRejectedException>().FallbackAsync(message3);//定義限流組合策略var fallbackBulk = Policy.WrapAsync(fallback2, bulk);//注入HttpClient定義策略 services.AddHttpClient("myClient6").AddPolicyHandler(fallbackBulk);} }?參考地址:
http://www.thepollyproject.org?
https://github.com/App-vNext/Polly.git?
https://github.com/App-vNext/Polly.Extensions.Http.git?
https://github.com/App-vNext/Polly-Samples.git?
總結
以上是生活随笔為你收集整理的Polly:提升服务可用性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用自定义DelegatingHandl
- 下一篇: 为自己而活,这很难吗?