zoukankan      html  css  js  c++  java
  • .Net Core 商城微服务项目系列(五):使用Polly处理服务错误

    项目进行微服务化之后,随之而来的问题就是服务调用过程中发生错误、超时等问题的时候我们该怎么处理,比如因为网络的瞬时问题导致服务超时,这在我本人所在公司的项目里是很常见的问题,当发生请求超时问题的时候,我们希望能够自动重试,或者是在发生服务错误时采取一定的策略,比如限流熔断等等。

    本篇将会使用Polly处理服务调用过程中发生的超时问题。

    打开我们的MI.Web项目,通过NuGet引用 Microsoft.Extensions.Http 和 Microsoft.Extensions.Http.Polly。

    在Startup中添加如下代码:

        public static class ServiceCollectionExtensions
        {
            public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
            {
    //依赖注入 services.AddSingleton
    <IApiHelperService, ApiHelperService>(); services.AddSingleton<IAccountService, AccountService>(); services.AddSingleton<IPictureService, PictureService>(); services.AddOptions(); services.AddMvc(options => { options.Filters.Add<HttpGlobalExceptionFilter>(); }); services.AddMemoryCache(); services.AddCors(options => { options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials()); }); return services; } public static IServiceCollection AddHttpServices(this IServiceCollection services) {//注册http服务 //services.AddHttpClient(); services.AddHttpClient("MI") .AddPolicyHandler(GetRetryPolicy()) .AddPolicyHandler(GetCircuiBreakerPolicy()); return services; } /// <summary> /// 重试策略 /// </summary> public static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() { return HttpPolicyExtensions .HandleTransientHttpError() .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); } /// <summary> /// 熔断策略 /// </summary> private static IAsyncPolicy<HttpResponseMessage> GetCircuiBreakerPolicy() { return HttpPolicyExtensions .HandleTransientHttpError() .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)); } }

    这里我们通过Polly分别配置了重试和熔断的策略,当发生404、500、408(超时)问题的时候会重试6次,间隔时间2秒;熔断策略是如果有5个请求发生500或者超时则开启熔断,时间是30秒,Polly可以配置非常详细的策略,以后有时间再专门介绍(其实是我现在不会。。。对不起)。因为这里Polly是结合HttpClientFactory来使用的,所以我们需要使用上面的代码:

    services.AddHttpClient("MI")
                    .AddPolicyHandler(GetRetryPolicy())
                    .AddPolicyHandler(GetCircuiBreakerPolicy());

    这里可以理解为我们创建了一个名称为“MI”的HttpClientFactory,然后为其配置了重试和熔断策略,这里顺带提一句是,HttpClientFactory是在.net core 2.1中加入的,它解决了之前HttpClient的资源释放不及时的痛点,之前使用HttpClient时我们需要使用using或者创建静态变量,前者的问题是频繁的创建和销毁带来的资源损耗,不仅仅和对象资源,因为HttpClient还涉及到网络资源,后者则会导致资源释放不及时,静态资源如果不进行处理会一直存在,而HttpClientFactory内部会缓存连接资源,同时会在不使用后的一段间隔时间后进行销毁,同时内存会维护一个队列,单例。

    添加完上面这些后我们还需要在ConfigureServices方法中进行注册:

            public void ConfigureServices(IServiceCollection services)
            {
                services.AddCustomMvc(Configuration).AddHttpServices();
            }

    我为API的调用封装了一个接口层:

        public interface IApiHelperService
        {
            Task<T> PostAsync<T>(string url, IRequest request);
            Task<T> GetAsync<T>(string url);
        }
    public class ApiHelperService : IApiHelperService
        {
            private readonly IHttpClientFactory _httpClientFactory;
            private readonly IMemoryCache cache;
            private readonly ILogger<ApiHelperService> _logger;
    
            public ApiHelperService(IMemoryCache cache, ILogger<ApiHelperService> _logger, IHttpClientFactory _httpClientFactory)
            {
                this._httpClientFactory = _httpClientFactory;
                this.cache = cache;
                this._logger = _logger;
            }
    
    
            /// <summary>
            /// HttpClient实现Post请求
            /// </summary>
            public async Task<T> PostAsync<T>(string url, IRequest request)
            {
                var http = _httpClientFactory.CreateClient("MI");
                //添加Token
                var token = await GetToken();
                http.SetBearerToken(token);
                //使用FormUrlEncodedContent做HttpContent
                var httpContent = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
                //await异步等待回应
                var response = await http.PostAsync(url, httpContent);
    
                //确保HTTP成功状态值
                response.EnsureSuccessStatusCode();
    
                //await异步读取
                string Result = await response.Content.ReadAsStringAsync();
    
                var Item = JsonConvert.DeserializeObject<T>(Result);
    
                return Item;
            }
    }

    图中标红的部分就是使用带有Polly策略的IHttpClientFactory来创建HttpClient,然后进行Post调用,Get调用也是同样的。

    然后我们启动Web项目,开启控制台模式进行日志查看,访问登录功能:

    我们可以看到,一共访问了登录方法两次,第一次发生了404错误,接着自动又请求了一次,成功。

    这里只是做一次演示,接下来会在Ocelot网关中接入Polly,这样可以避免在每个项目里都进行这样的配置,当然如果项目里有功能需要进行特许的策略配置,是可以采用这种方式的。

     
  • 相关阅读:
    OpenGL编程 基础篇(七)对象的变换——用实心体绘制3D场景
    mysql在查询结果列表前添加一列递增的序号列(最简)
    将中文字符串分割为数组 解决str_split中文乱码php
    file_get_contents 抓取网页乱码。
    js下的sleep实现
    js获取当前时间(昨天、今天、明天)
    JPA为字段设置默认值
    js实现点击按钮弹出上传文件的窗口
    Bootstrap使用模态框modal实现表单提交弹出框
    springboot使用Freemarker继承
  • 原文地址:https://www.cnblogs.com/weiBlog/p/9906294.html
Copyright © 2011-2022 走看看