上篇讲了net5+consul:

.Net5+Consul服务注册发现_二后生的博客-CSDN博客

这篇主要是consul结合ocelot的实现

自己简单理解概念:

虽然consul实现了服务注册的服务与发现,当然自身也有不错的负载均衡机制与路由转发,但是针对于上下游服务的调用不是那么牛逼,他在微服务中仅做服务注册与发现工作,下面网关的作用就是弥补他缺少的这些功能。

那ocelot网关的作用就是实现了:配置实现路由、请求聚合、服务发现、认证、鉴权、限流、熔断、并内置了负载均衡器等等功能。

简单画了个图:

一、Ocelot+Consul结合:

1、新建一个网关的 .netcorewebapi的项目:

 2、nuget安装

第一个主要是ocelot的类包

第二个主要是ocelot与consul相关联的类包

3、可以看到第一步截图内新建的configuration.json文件,我们用它来配置网关。

新建了之后,需要在Program.cs文件内项目启动时使用这个文件,如下(我这是net5框架):

4、startup文件内注册ocelot和consul

使用ocelot中间件

 5、配置configuration.json文件内容

//*****************************Ocelot+Consul********************************
{
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/{url}", //下游服务地址--url变量
      "DownstreamScheme": "http",
      "UpstreamPathTemplate": "/GateWayTest/{url}", //上游请求路径,网关地址--url变量
      "UpstreamHttpMethod": [ "Get", "Post" ],
      //consul
      "UseServiceDiscovery": true, //使用服务发现
      "ServiceName": "Cbf.Oscar.Service", //consul服务名称
      "LoadBalancerOptions": {
        "Type": "RoundRobin" //轮询      LeastConnection-最少连接数的服务器   NoLoadBalance不负载均衡
      },
      "GlobalConfiguration": {
        //"BaseUrl":"http://198.12.168.55",  //网关对外地址
        //配置consul地址
        "ServiceDiscoveryProvider": {
          "Host": "127.0.0.1",
          "Port": 8500,
          "Type": "Consul" //由consul提供服务发现,ocelot也支持etc等
        }
      }
    }
  ]
}

根据上面注释制定好自己下游的url,还有自己网关的地址,还有配置consul的地址就好了。

6、最后启动后的效果就是:

(1)我的consul列表:注册了俩实例

(2)切换到网关目录cmd启动自己的网关服务:dotnet run --urls http://localhost:2000

然后请求自己本地网关地址(网关实现了轮循负载均衡和路由转发):

http://localhost:2000/GateWayTest/Index/getDetails

二、网关加缓存(可选项,按照自己业务设计)

简单说一下:缓存能有效提升程序性能。

缓存是针对下游地址缓存的,同一个地址请求返回相同数据,例如针对一些不变的数据才能做缓存,所以根据用户登录信息不同返回不同数据的就不适合用了。

1、首先要给网关类库安装nuget包:Ocelot.Cache.CacheManager

2、然后在ConfigureServices 注册这个方法:

 3、然后在配置文件配置缓存

 4、测试一下

可以接口返回一个当前时间,因为上面配置的过期时间是10秒,所以刷新的时候观察这个时间,十秒钟就会过期,并返回新的数据

三、限流

为什么要限流呢,防止请求过多把程序搞宕机了,也可以有效防止爬虫和ddos攻击,预估出服务的处理能力,然后设置限流,可以限制单位时间内的访问量(失败一部分请求比整个服务挂掉强)。

实现步骤:

配置中心新增一些限流的配置:

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/{url}", //下游服务地址--url变量
      "DownstreamScheme": "http",
      "UpstreamPathTemplate": "/GateWayTest/{url}", //上游请求路径,网关地址--url变量
      "UpstreamHttpMethod": [ "Get", "Post" ],
      //consul
      "UseServiceDiscovery": true, //使用服务发现
      "ServiceName": "Cbf.Oscar.Service", //consul服务名称
      "LoadBalancerOptions": {
        "Type": "RoundRobin" //轮询      LeastConnection-最少连接数的服务器   NoLoadBalance不负载均衡
      },
      //限流操作
      "RateLimitOptions": {
        "ClientWhitelist": [ "eleven", "seven" ], //设置白名单:ClientId=eleven(http请求传header,ClientId区分大小写,白名单不受限流)
        "EnableRateLimiting": true, //开启,默认true
        "Period": "5m", //1s, 5m, 1h, 1d
        "PeriodTimespan": 30, //多少秒之后客户端可以重试
        "Limit": 5 //统计时间段内允许的最大请求数量
        //简述上面限流条件:5分钟之内最多请求5次,失败了(超出五次也算),30秒之后客户端才可以重新请求
      }
      //网关缓存,这里表示缓存10秒,10秒后过期。另外,貌似只支持get方式,只要请求的URL不变,就会缓存。
      //"FileCacheOptions": {
      //  "TtlSeconds": 10, //second 过期时间
      //  "Region": "UserCache" //
      //},

    }
  ],
  "GlobalConfiguration": {
    //"BaseUrl":"http://0.0.0.1",  //网关对外地址
    //配置consul地址
    "ServiceDiscoveryProvider": {
      "Host": "127.0.0.1",
      "Port": 8500,
      "Type": "Consul" //由consul提供服务发现,ocelot也支持etc等
    },
    //网关限流 超出限制 可以自定义返回消息
    "RateLimitOptions": {
      "DisableRateLimitHeaders": false, // Http头  X-Rate-Limit 和 Retry-After 是否禁用
      "QuotaExceededMessage": "Fuck U,You can only ask five times in five fucking minutes!", //当请求过载被截断时返回的消息(不支持中文)
      "HttpStatuCode": 666 //错误码 自定义
      //"ClientIdHeader": "client_id" // 用来自定义客户端的请求头,默认是 ClientId
    }
  }
}

可以看到上面的配置,在以前的基础上加了:

1、routes内新加的限流配置2、注:这里把GlobalConfiguration拿到Rotes同级,这里配置是限流返回的一些信息。

 3、看效果

请求网关地址返回数据了:

 

 但是在5分钟之内我刷新了五次,第六次的时候就会超出限定数量,出现下图:

当然,ClientWhitelist 定义的白名单不限流,白名单刷新多少次都行

ok限流就到这里了

四、熔断

熔断的意思是停止将请求转发到下游服务。当下游服务已经出现故障的时候再请求也是无功而返,并且还会增加下游服务器和API网关的负担。这个功能是用的ocelot结合Pollly来实现的,我们只需要为路由做一些简单配置即可

1、nuget安装   Ocelot.Provider.Polly

Ocelot.Provider.Polly的熔断机制是一个超时和熔断的组合,(Polly有超时策略,熔断策略,这里是2个策略的结合使用),所以如果是单单是服务报500异常是触发不了的。

接口超过多长时间进入半熔断状态,返回服务不可用, 连续超过多少次进入熔断状态就直接停掉该请求返回,多长时间再恢复。

2、依赖注入polly

3、配置文件添加红框的内容:

配置就完成了

4、在service中添加一个接口用于测试

        private static int _count;

        /// <summary>
        /// 测试熔断效果
        /// </summary>
        /// <returns></returns>
        [HttpGet("GetQoS")]
        public IEnumerable<string> GetQoS()
        {
            _count++;
            Console.WriteLine($"Get...{_count}");
            if (_count <= 3)
            {
                System.Threading.Thread.Sleep(5000);  //因为timeout设置的是3秒,这里设置让其超时5秒触发ocelot熔断保护机制,就会返回失败,不会走下面的return
            }

            //如果_count超出三个就说明正常,主要是测试熔断
            return new string[] { $"请求成功,ClinetService: {DateTime.Now.ToString()} {Environment.MachineName} " +
                $"OS: {Environment.OSVersion.VersionString}" };
        }

建议起一个线程即可。然后刷新自己读秒观察

            //测试结果:
            //1、刷新运行三秒失败返回503   Get...1  (第1次异常)
            //2、刷新运行三秒失败返回503   Get...2  (第2次异常)
            //3、熔断5秒(因配置只允许两次异常,上面两次异常,则触发本次熔断机制)
            //4、刷新运行三秒失败返回503   Get...3  (第二轮的第一次异常)
            //5、熔断5秒 (不清楚这里为什么会熔断5秒,按理说第二轮的第二次异常还没出现,可能是最大2次异常,之后异常一次就触发会熔断吧)
            //6、直接成功  Get...4
            //7、直接成功  Get...5、Get...6、Get...7。。。。   后面都成功

五、降级

其实熔断和限流也算是一种降级,降级就是当我们指定的代码处理失败时就执行我们备用的代码,但是这个好像没跟ocelot相关联,需要单独使用polly包,也不用配置啥的安装即用。

实现步骤:

1、安装NuGet包    Polly  (安装在各个服务类库上)

2、

startup注册这个接口类为单例模式

第一种方法:使用构造函数,实例一定要以单例模式注入,因为如果是每次都执行构造函数给_policy赋一次值,那_policy每次都是全新的,下面的熔断策畋会不生效。

 然后在构造函数中注入polly

 第二种方法:在接口中使用polly

上面这种是这个接口类统一使用一个降级策略,需要注入ioc。

下面这个方案不同的是一个方法一个降级策略,可以自己根据业务设计合适策略

 3、那上面两种方案的Execute就是polly监控的代码块,如果polly监控到错误则Fallback进行降级策略。下面就是个测试结果。

六、Ocelot动态路由

因为我们上面的例子都是写死在Routes中的,网关只能转发Cbf.Oscar.ServiceInstance一个服务。客户端请求微服务时,不可能只请求一个服务,所以客户端的请求网关地址是不可能写死的,我们一般会通过服务名称来请求不同的服务接口,动态路由就是ocelot通过服务名称去consul找到对应的服务再返回并转发出去。

具体实现就是只改配置文件的 Routes 就行了,如下配置

 图中,因为需要动态请求,所以routes不再使用,把之前的那些静态路由都拿到了全局中。

然后如果想每个服务都设置自己的限流的话可以使用DynamicRoutes(与GlobalConfiguration同级),如图:

配置完之后客户端请求网关就可以通过服务名称了,如下

既然各服务都有各自的限流,我就想到了各服务是不是也有各自的熔断、各自的限流异常信息提示、但是经过搜索和尝试,好像是没有这个功能。。。

动态路由就讲完了

总文参考资料:

Consul+Ocelot+Polly缓存、限流、熔断、降级 - 走看看

微服务之Ocelot网关实战 - 墨天轮

Ocelot简易教程(四)之请求聚合以及服务发现 - 依乐祝 - 博客园

还有一堆,找不到链接了。。

over

Logo

鸿蒙生态一站式服务平台。

更多推荐