.NET8中的Microsoft.Extensions.Http.Resilience庫

接上一篇,https://www.cnblogs.com/vipwan/p/18129361 藉助Aspire中新增的Microsoft.Extensions.ServiceDiscovery庫,我們可以很容易的做到服務發現,那麼服務節點的熔斷限流以及重試等彈性機制.NET是怎麼處理的呢?
比如下圖的微服務場景:

image

這裏就不得不提到 Microsoft.Extensions.Http.Polly這個Polly的封裝庫了,這個庫是從NETCore2.1增加的,我們可以很容易的對IHttpClientBuilder擴展彈性機制,比如下面的代碼:

builder.Services.AddHttpClient("qrcode", client =>
{
    client.BaseAddress = new("http://qrcode");
})
.AddTransientHttpErrorPolicy((builder) =>
{
    // 重試3次,每次間隔5秒
    var retryPolicy = builder.WaitAndRetryAsync(3, retryCount => TimeSpan.FromSeconds(5d));
    // 熔斷器,失敗3次後,30秒內不再請求
    var circuitBreakerPolicy = builder.CircuitBreakerAsync(3, TimeSpan.FromSeconds(30));
    // 重試策略包裝熔斷器
    return retryPolicy.WrapAsync(circuitBreakerPolicy);
});

然鵝Microsoft.Extensions.Http.Polly庫是早些年就存在的產物了,針對Polly V8及後續的版本巨硬在 NET8後增加了 Microsoft.Extensions.Http.Resilience庫作爲替代方案.

下面是巨硬給出的兩個版本的性能差異:

Method Mean Error StdDev Ratio Gen0 Allocated Alloc Ratio
StandardPipeline_Polly_V7 3.236 us 0.0130 us 0.0187 us 1.00 0.1488 3816 B 1.00
StandardPipeline_Polly_V8 3.104 us 0.0237 us 0.0317 us 0.96 0.0381 1008 B 0.26

速度較快的同時,基於 Polly v8 構建的Microsoft.Extensions.Http.Resilience使用的內存減少了4倍之多。
所以至NET8+以後我推薦使用Microsoft.Extensions.Http.Resilience替代Microsoft.Extensions.Http.Polly

下面我們使用新庫實現模擬的策略:


builder.Services.AddHttpClient("qrcode", client =>
{
    client.BaseAddress = new("http://qrcode");
})

// Microsoft.Extensions.Http.Polly實現的代碼:
.AddTransientHttpErrorPolicy((builder) =>
{
    // 重試3次,每次間隔5秒
    var retryPolicy = builder.WaitAndRetryAsync(3, retryCount => TimeSpan.FromSeconds(5d));
    // 熔斷器,失敗3次後,30秒內不再請求
    var circuitBreakerPolicy = builder.CircuitBreakerAsync(3, TimeSpan.FromSeconds(30));

    // 重試策略包裝熔斷器
    return retryPolicy.WrapAsync(circuitBreakerPolicy);
})
// Microsoft.Extensions.Http.Resilience實現代碼:
.AddStandardResilienceHandler(options =>
{
    options.Retry.MaxRetryAttempts = 3;
    options.TotalRequestTimeout.Timeout = TimeSpan.FromSeconds(30);// 總的超時時間
    options.AttemptTimeout.Timeout = TimeSpan.FromSeconds(5);//每次重試的超時時間
    options.CircuitBreaker.BreakDuration = TimeSpan.FromSeconds(30);//熔斷時間
})
;

當然大多數情況彈性機制是放到配置文件或者其他持久層的這個時候我們可以使用Configure(IConfigurationSection) 或者 Configure(Action<HttpStandardResilienceOptions, IServiceProvider>)


.AddStandardResilienceHandler(options =>
{
    options.Retry.MaxRetryAttempts = 3;
    options.TotalRequestTimeout.Timeout = TimeSpan.FromSeconds(5);// 超時時間
    options.AttemptTimeout.Timeout = TimeSpan.FromSeconds(5);//每次重試的超時時間
    options.CircuitBreaker.BreakDuration = TimeSpan.FromSeconds(30);//熔斷時間
})
.Configure((options, sp) =>
{
    // 配置來自自定義的Provider
    var myResiliencePolicy = sp.GetRequiredService<IResiliencePolicyProvider>().GetResiliencePolicy("MyPolicy");
    options.Retry.MaxRetryAttempts = myResiliencePolicy.Retry.MaxRetryAttempts;
});

從代碼上來說也優雅了一些

當然也可以使用AddResilienceHandler擴展方法實現一些比較個性化的配置需求,這個就比較類似於Microsoft.Extensions.Http.Polly:

builder.Services.AddHttpClient("qrcode", client =>
{
    client.BaseAddress = new("http://qrcode");
})
.AddResilienceHandler("MyPolicy", builder =>
{
    builder.AddTimeout(TimeSpan.FromSeconds(5));
    builder.AddRetry(new HttpRetryStrategyOptions
    {
        MaxRetryAttempts = 3,
        Delay = TimeSpan.FromSeconds(2),
        MaxDelay = TimeSpan.FromSeconds(10),
    });
    //其他的機制....
});

參考文檔 https://github.com/dotnet/docs/blob/main/docs/core/resilience/http-resilience.md

https://devblogs.microsoft.com/dotnet/building-resilient-cloud-services-with-dotnet-8/

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