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

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

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

在Startup中添加如下代码:

  1. public static class ServiceCollectionExtensions
  2. {
  3. public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
  4. {
    //依赖注入
  5. services.AddSingleton<IApiHelperService, ApiHelperService>();
  6. services.AddSingleton<IAccountService, AccountService>();
  7. services.AddSingleton<IPictureService, PictureService>();
  8.  
  9. services.AddOptions();
  10. services.AddMvc(options =>
  11. {
  12. options.Filters.Add<HttpGlobalExceptionFilter>();
  13. });
  14. services.AddMemoryCache();
  15.  
  16. services.AddCors(options =>
  17. {
  18. options.AddPolicy("CorsPolicy",
  19. builder => builder.AllowAnyOrigin()
  20. .AllowAnyMethod()
  21. .AllowAnyHeader()
  22. .AllowCredentials());
  23. });
  24.  
  25. return services;
  26. }
  27.  
  28. public static IServiceCollection AddHttpServices(this IServiceCollection services)
  29. {//注册http服务
  30. //services.AddHttpClient();
  31.  
  32. services.AddHttpClient("MI")
  33. .AddPolicyHandler(GetRetryPolicy())
  34. .AddPolicyHandler(GetCircuiBreakerPolicy());
  35.  
  36. return services;
  37. }
  38.  
  39. /// <summary>
  40. /// 重试策略
  41. /// </summary>
  42. public static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
  43. {
  44. return HttpPolicyExtensions
  45. .HandleTransientHttpError()
  46. .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
  47. .WaitAndRetryAsync(, retryAttempt => TimeSpan.FromSeconds(Math.Pow(, retryAttempt)));
  48. }
  49.  
  50. /// <summary>
  51. /// 熔断策略
  52. /// </summary>
  53. private static IAsyncPolicy<HttpResponseMessage> GetCircuiBreakerPolicy()
  54. {
  55. return HttpPolicyExtensions
  56. .HandleTransientHttpError()
  57. .CircuitBreakerAsync(, TimeSpan.FromSeconds());
  58. }
  59. }

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

  1. services.AddHttpClient("MI")
  2. .AddPolicyHandler(GetRetryPolicy())
  3. .AddPolicyHandler(GetCircuiBreakerPolicy());

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

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

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddCustomMvc(Configuration).AddHttpServices();
  4. }

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

  1. public interface IApiHelperService
  2. {
  3. Task<T> PostAsync<T>(string url, IRequest request);
  4. Task<T> GetAsync<T>(string url);
  5. }
  1. public class ApiHelperService : IApiHelperService
  2. {
  3. private readonly IHttpClientFactory _httpClientFactory;
  4. private readonly IMemoryCache cache;
  5. private readonly ILogger<ApiHelperService> _logger;
  6.  
  7. public ApiHelperService(IMemoryCache cache, ILogger<ApiHelperService> _logger, IHttpClientFactory _httpClientFactory)
  8. {
  9. this._httpClientFactory = _httpClientFactory;
  10. this.cache = cache;
  11. this._logger = _logger;
  12. }
  13.  
  14. /// <summary>
  15. /// HttpClient实现Post请求
  16. /// </summary>
  17. public async Task<T> PostAsync<T>(string url, IRequest request)
  18. {
  19. var http = _httpClientFactory.CreateClient("MI");
  20. //添加Token
  21. var token = await GetToken();
  22. http.SetBearerToken(token);
  23. //使用FormUrlEncodedContent做HttpContent
  24. var httpContent = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
  25. //await异步等待回应
  26. var response = await http.PostAsync(url, httpContent);
  27.  
  28. //确保HTTP成功状态值
  29. response.EnsureSuccessStatusCode();
  30.  
  31. //await异步读取
  32. string Result = await response.Content.ReadAsStringAsync();
  33.  
  34. var Item = JsonConvert.DeserializeObject<T>(Result);
  35.  
  36. return Item;
  37. }
  38. }

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

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

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

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

  1.  

.Net Core 商城微服务项目系列(五):使用Polly处理服务错误的更多相关文章

  1. .Net Core 商城微服务项目系列(一):使用IdentityServer4构建基础登录验证

    这里第一次搭建,所以IdentityServer端比较简单,后期再进行完善. 1.新建API项目MI.Service.Identity,NuGet引用IdentityServer4,添加类InMemo ...

  2. .Net Core 商城微服务项目系列(六):搭建自己的Nuget包服务器

    当我们使用微服务架构之后,紧接而来的问题便是服务之间的程序集引用问题,可能没接触过的同学不太理解这句话,都已经微服务化了为什么还要互相引用程序集,当然可以不引用.但是我们会有这样一种情况,我们的每个接 ...

  3. .Net Core 商城微服务项目系列(十):使用SkyWalking构建调用链监控(2019-02-13 13:25)

    SkyWalking的安装和简单使用已经在前面一篇介绍过了,本篇我们将在商城中添加SkyWalking构建调用链监控. 顺带一下怎么把ES设置为Windows服务,cd到ES的bin文件夹,运行ela ...

  4. .Net Core 商城微服务项目系列(二):使用Ocelot + Consul构建具备服务注册和发现功能的网关

    1.服务注册 在上一篇的鉴权和登录服务中分别通过NuGet引用Consul这个包,同时新增AppBuilderExtensions类: public static class AppBuilderEx ...

  5. .Net Core 商城微服务项目系列(十一):MQ消费端独立为Window服务+消息处理服务

    之前使用MQ的时候是通过封装成dll发布Nuget包来使用,消息的发布和消费都耦合在使用的站点和服务里,这样会造成两个问题: 1.增加服务和站点的压力,因为每次消息的消费就意味着接口的调用,这部分的压 ...

  6. 微服务项目开发学成在线_day01_CMS服务端开发

    05-CMS需求分析-什么是CMS 什么是CMS?CMS (Content Management System)即内容管理系统,不同的项目对CMS的定位不同.CMS有哪些类型? 每个公司对每个项目的C ...

  7. Windows服务项目打包成安装包(Windows服务)-----------VS2017项目程序打包成.msi或者.exe

    VS2017项目程序打包成.msi或者.exe Windows服务项目使用VS2017项目程序打包成.msi或者.exe安装包 项目打包成安装包(Windows服务) 1.安装打包插件:Microso ...

  8. .Net Core 商城微服务项目系列(十五): 构建定时任务调度和消息队列管理系统

    一.系统描述 嗨,好久不见各位老哥,最近有点懒,技术博客写的太少了,因为最近在写小说,写的顺利的话说不定就转行了,哈哈哈哈哈哈哈哈哈. 今天要介绍的是基于.Net Core的定时任务调度和消息队列管理 ...

  9. .Net Core 商城微服务项目系列(十四):分布式部署携程Apollo构建配置中心

    一.开场白 在系统设计里我们有很多配置希望独立于系统之外,而又能够被系统实时读取.但是在传统的系统设计里,配置信息通常是耦合在系统内的,比如.net里通常会放在App.config或者web.conf ...

随机推荐

  1. POJ-1062 昂贵的聘礼( 最短路 )

    题目链接:http://poj.org/problem?id=1062 Description 年轻的探险家来到了一个印 第安部落里.在那里他和酋长的女儿相爱了,于是便向酋长去求亲.酋长要他用1000 ...

  2. http gzip压缩功能记录

    版权声明:本文为博主原创文章,转载请附上原文出处链接. 本文链接:https://www.cnblogs.com/shaoshuai95928/articles/Tomcat.html 最近在spri ...

  3. uwsgi基本介绍安装和测试--使用Django建立你的第一个网站

    一 基本介绍 对像我这样不是专业做网络的人来说,uuwsgi是一个陌生的东西.它是谁?它可以做什么?谁会用到它?其实,在不知道一个东西是什么的情况下,能够快速的了解并使用它,是一门很有艺术性的事情.最 ...

  4. js生成玫瑰图

    html: <canvas id="c" height="600" width="600"></canvas> js ...

  5. webpack多页应用架构系列(一):一步一步解决架构痛点

    这系列文章讲什么? 前些时间,写过一个项目,前后端分离,没有借助任何框架,项目页面特别的多,页面都是html直接写的,许多公共html,写了好多处,有一个地方需要改就得改好多地方,js也是随意写,每个 ...

  6. 【Offer】[36] 【二叉搜索树与双向链表】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的节点,只能调整树中节点指针的指向.比如,输入下图中左边的 ...

  7. web scraper 抓取数据并做简单数据分析

    其实 web scraper 说到底就是那点儿东西,所有的网站都是大同小异,但是都还不同.这也是好多同学总是遇到问题的原因.因为没有统一的模板可用,需要理解了 web scraper 的原理并且对目标 ...

  8. mysql 复制表结构和表数据

    CREATE TABLE a1 ( id INT NOT NULL AUTO_INCREMENT COMMENT '编号', txt VARCHAR(20) NOT NULL DEFAULT '' C ...

  9. Newtonsoft.Json 序列化

    当我们对一个json数组进行反序列化用Newtonsoft.Json.JsonConvert.DeserializeObject<T>() 通常会报此错误 Newtonsoft.Json. ...

  10. oracle用imp导入dmp文件

    oracle命令行登录 sqlplus 用户名/密码 创建用户 create user 用户 identified by 密码 ; 创建表空间 create tablespace 表空间名 dataf ...