.NET Core微服务之基于Ocelot实现API网关服务(续)

一、负载均衡与请求缓存

1.1 负载均衡

  为了验证负载均衡,这里我们配置了两个Consul Client节点,其中ClientService分别部署于这两个节点内(192.168.80.70与192.168.80.71)。

  为了更好的展示API Repsonse来自哪个节点,我们更改一下返回值:

    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        // GET api/values
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { $"ClinetService: {DateTime.Now.ToString()} {Environment.MachineName} " +
                $"OS: {Environment.OSVersion.VersionString}" };
        }

        ......
    }

  Ocelot的配置文件中确保有负载均衡的设置:

{
  "ReRoutes": [
      ......
      "LoadBalancerOptions": {
        "Type": "RoundRobin"
      },
      ......
}

  接下来发布并部署到这两个节点上去,之后启动我们的API网关,这里我用命令行启动:

  

  然后就可以测试负载均衡了,在浏览器中输入URL并连续刷新:可以通过主机名看到的确是根据轮询来进行的负载均衡。

  

负载均衡LoadBalance可选值:

  • RoundRobin - 轮询,挨着来,雨露均沾
  • LeastConnection - 最小连接数,谁的任务最少谁来接客
  • NoLoadBalance - 不要负载均衡,让我一个人累死吧  

1.2 请求缓存

  Ocelot目前支持对下游服务的URL进行缓存,并可以设置一个以秒为单位的TTL使缓存过期。我们也可以通过调用Ocelot的管理API来清除某个Region的缓存。

为了在路由中使用缓存,需要在ReRoute中加上如下设置:

"FileCacheOptions": { "TtlSeconds": 10, "Region": "somename" }

  这里表示缓存10秒,10秒后过期。另外,貌似只支持get方式,只要请求的URL不变,就会缓存。

  这里我们仍以上面的demo为例,在增加了FileCacheOptions配置之后,进行一个小测试:因为我们设置的10s过期,所以在10s内拿到的都是缓存,否则就会触发负载均衡去不同节点拿数据。

  

二、限流与熔断器(QoS)

2.1 限流 (RateLimit)

  对请求进行限流可以防止下游服务器因为访问过载而崩溃,我们只需要在路由下加一些简单的配置即可以完成。另外,看文档发现,这个功能是张善友大队长贡献的,真是666。同时也看到一个园友catcherwong,已经实践许久了,真棒。

  对于限流,我们可以对每个服务进行如下配置:

    "RateLimitOptions": {
        "ClientWhitelist": [ "admin" ], // 白名单
        "EnableRateLimiting": true, // 是否启用限流
        "Period": "1m", // 统计时间段:1s, 5m, 1h, 1d
        "PeriodTimespan": 15, // 多少秒之后客户端可以重试
        "Limit": 5 // 在统计时间段内允许的最大请求数量
      }

  同时,我们可以做一些全局配置:

    "RateLimitOptions": {
      "DisableRateLimitHeaders": false, // Http头  X-Rate-Limit 和 Retry-After 是否禁用
      "QuotaExceededMessage": "Too many requests, are you OK?", // 当请求过载被截断时返回的消息
      "HttpStatusCode": 999, // 当请求过载被截断时返回的http status
      "ClientIdHeader": "client_id" // 用来识别客户端的请求头,默认是 ClientId
    }

  这里每个字段都有注释,不再解释。下面我们来测试一下:

  Scenario 1:不带header地访问clientservice,1分钟之内超过5次,便会被截断,直接返回截断后的消息提示,HttpStatusCode:999

  

  可以通过查看Repsonse的详细信息,验证是否返回了999的状态码:

  

  Scenario 2:带header(client_id:admin)访问clientservice,1分钟之内可以不受限制地访问API

  

2.2 熔断器(QoS)

  熔断的意思是停止将请求转发到下游服务。当下游服务已经出现故障的时候再请求也是无功而返,并且还会增加下游服务器和API网关的负担。这个功能是用的Pollly来实现的,我们只需要为路由做一些简单配置即可。如果你对Polly不熟悉,可以阅读我之前的一篇文章《.NET Core微服务之基于Polly+AspectCore实现熔断与降级机制

    "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 2, // 允许多少个异常请求
        "DurationOfBreak": 5000, // 熔断的时间,单位为毫秒
        "TimeoutValue": 3000 // 如果下游请求的处理时间超过多少则视如该请求超时
      },

  *.这里针对DurationOfBreak,官方文档中说明的单位是秒,但我在测试中发现应该是毫秒。不知道是我用的版本不对,还是怎么的。anyway,这不是实验的重点。OK,这里我们的设置就是:如果Service Server的执行时间超过3秒,则会抛出Timeout Exception。如果Service Server抛出了第二次Timeout Exception,那么停止服务访问5s钟。

  现在我们来改造一下Service,使其手动超时以使得Ocelot触发熔断保护机制。Ocelot中设置的TimeOutValue为3秒,那我们这儿简单粗暴地让其延时5秒(只针对前3次请求)。

    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        ......

        private static int _count = 0;
        // GET api/values
        [HttpGet]
        public IEnumerable<string> Get()
        {
            _count++;
            Console.WriteLine($"Get...{_count}");
            if (_count <= 3)
            {
                System.Threading.Thread.Sleep(5000);
            }

            return new string[] { $"ClinetService: {DateTime.Now.ToString()} {Environment.MachineName} " +
                $"OS: {Environment.OSVersion.VersionString}" };
        }

        ......
    }

  下面我们就来测试一下:可以看到异常之后,便进入了5秒中的服务不可访问期(直接返回了503 Service Unavaliable),而5s之后又可以正常访问该接口了(这时不会再进入hard-code的延时代码)

  

  通过日志,也可以确认Ocelot触发了熔断保护:

  

三、动态路由(Dynamic Routing)

  记得上一篇中一位园友评论说他有500个API服务,如果一一地配置到配置文件,将会是一个巨大的工程,虽然都是copy,但是会增加出错的机会,并且很难排查。这时,我们可以牺牲一些特殊性来求通用性,Ocelot给我们提供了Dynamic Routing功能。这个功能是在issue 340后增加的(见下图官方文档),目的是在使用服务发现之后,直接通过服务发现去定位从而减少配置文件中的ReRoutes配置项。

Example:http://api.edc.com/productservice/api/products => Ocelot会将productservice作为key调用Consul服务发现API去得到IP和Port,然后加上后续的请求URL部分(api/products)进行最终URL的访问:http://ip:port/api/products。

  这里仍然采用下图所示的实验节点结构:一个API网关节点,三个Consul Server节点以及一个Consul Client节点。

  由于不再需要配置ReRoutes,所以我们需要做一些“通用性”的改造,详见下面的GlobalConfiguration:

{
  "ReRoutes": [],
  "Aggregates": [],
  "GlobalConfiguration": {
    "RequestIdKey": null,
    "ServiceDiscoveryProvider": {
      "Host": "192.168.80.100", // Consul Service IP
      "Port": 8500 // Consul Service Port
    },
    "RateLimitOptions": {
      "DisableRateLimitHeaders": false, // Http头  X-Rate-Limit 和 Retry-After 是否禁用
      "QuotaExceededMessage": "Too many requests, are you OK?", // 当请求过载被截断时返回的消息
      "HttpStatusCode": 999, // 当请求过载被截断时返回的http status
      "ClientIdHeader": "client_id" // 用来识别客户端的请求头,默认是 ClientId
    },
    "QoSOptions": {
      "ExceptionsAllowedBeforeBreaking": 3,
      "DurationOfBreak": 10000,
      "TimeoutValue": 5000
    },
    "BaseUrl": null,
    "LoadBalancerOptions": {
      "Type": "LeastConnection",
      "Key": null,
      "Expiry": 0
    },
    "DownstreamScheme": "http",
    "HttpHandlerOptions": {
      "AllowAutoRedirect": false,
      "UseCookieContainer": false,
      "UseTracing": false
    }
  }
}

  详细信息请浏览:http://ocelot.readthedocs.io/en/latest/features/servicediscovery.html#dynamic-routing

  下面我们来做一个小测试,分别访问clientservice和productservice,看看是否能成功地访问到。

  (1)访问clientservice

  

  (2)访问productservice

  

  可以看出,只要我们正确地输入请求URL,基于服务发现之后是可以正常访问到的。只是这里我们需要输入正确的service name,这个service name是在consul中注册的名字,如下高亮部分所示:

{
    "services":[
        {
            "id": "EDC_DNC_MSAD_CLIENT_SERVICE_01",
            "name" : "CAS.ClientService",
            "tags": [
                "urlprefix-/ClientService01"
            ],
            "address": "192.168.80.71",
            "port": 8810,
            "checks": [
                {
                    "name": "clientservice_check",
                    "http": "http://192.168.80.71:8810/api/health",
                    "interval": "10s",
                    "timeout": "5s"
                }
            ]
        }
     ]
}

四、小结

  本篇基于Ocelot官方文档,学习了一下Ocelot的一些有用的功能:负载均衡(虽然只提供了两种基本的算法策略)、缓存、限流、QoS以及动态路由(Dynamic Routing),并通过一些简单的Demo进行了验证。通过查看Ocelot官方文档,可以知道Ocelot还支持许多其他有用的功能,而那些功能这里暂不做介绍(或许有些会在后续其他部分(如验证、授权、Trace等)中加入)。此外,一些朋友找我要demo的源码,我会在后续一齐上传到github。而这几篇中的内容,完全可以通过分享出来的code和配置自行构建,因此就不贴出来了。

参考资料

jesse(腾飞),《.NET Core开源网关 - Ocelot 中文文档

catcher wong,《Building API Gateway Using Ocelot In ASP.NET Core - QoS (Quality of Service)

Ocelot官方文档:http://ocelot.readthedocs.io/en/latest/index.html

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

原文地址:https://www.cnblogs.com/edisonchou/p/api_gateway_ocelot_foundation_02.html

时间: 2024-10-11 07:00:02

.NET Core微服务之基于Ocelot实现API网关服务(续)的相关文章

Ocelot实现API网关服务

NET Core微服务之基于Ocelot实现API网关服务 https://www.cnblogs.com/edisonchou/p/api_gateway_ocelot_foundation_01.html 一.啥是API网关? API 网关一般放到微服务的最前端,并且要让API 网关变成由应用所发起的每个请求的入口.这样就可以明显的简化客户端实现和微服务应用程序之间的沟通方式.以前的话,客户端不得不去请求微服务A(假设为Customers),然后再到微服务B(假设为Orders),然后是微服

.net core 3.1 基于ocelot实现API网关

Ocelot是一个用.NET Core实现的开源API网关,它功能强大,包括了:路由.请求聚合.服务发现.认证.鉴权.限流熔断,缓存等. 接下来,会使用ocelot 结合consul ,polly ,cachemanager 实现负载均衡,服务发现,限流熔断和缓存功能.(本文只做记录,就直接贴完整代码,不分别测试了) 新建ApiGateWay项目,nuget安装Ocelot,Ocelot.Provider.Consul,Ocelot.Provider.Polly,Ocelot.Cache.Cac

Spring Cloud学习系列第五篇【API网关服务】

这篇随笔接着学习微服务中一个比较重要的组件API网关服务.当我们微服务架构完成后最终是要提供给外部访问的,于是我们需要一个统一的访问入口,能隐藏我们内部服务URL细节,这就有点像局域网里那个网关的概念了,这是API网关服务就应运而生了.API网关作用有能为实现请求路由.负载均衡.校验过滤等基础功能,还能实现请求转发的熔断机制.服务集合等高级功能.补充下通常我们对外服务统一入口可以采用F5.Nginx等方式也能实现前面的请求路由与负载均衡,但是要实现后面功能了F5.Nginx就无能为力了吧,这就是

springCloud学习05之api网关服务zuul过滤器filter

前面学习了zuul的反向代理.负载均衡.fallback回退.这张学习写过滤器filter,做java web开发的对filter都不陌生,那就是客户端(如浏览器)发起请求的时候,都先经过过滤器filter做一些相关的校验或业务判断(如登录.权限等),zuul也同样提供了过滤器功能.只要继承ZuulFilter类即可. 通过前文的介绍,我们对于Zuul的第一印象通常是这样的:它包含了对请求的路由和过滤两个功能,其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础:而过

Spring Cloud(五):API网关服务——Spring Cloud Zuul

通过前面的介绍,我们可以使用Spring Boot进行微服务开发,使用Spring Cloud Eureka实现注册中心以及微服务的注册和发现,使用Spring Cloud Ribbon实现服务间的负载均衡,使用Spring Cloud Hystrix实现线程隔离以及断路器功能.但是实际应用中这样的架构无疑增加了开发成本以及运维难度,而且后期重构难度也很大.为了解决以上各种问题,需要使用API 网关的方式.API 网关是一个服务器,它是进入一个系统的唯一节点,封装了内部系统的架构,并且提供了AP

基于.NET CORE微服务框架 -Api网关服务管理

1.前言 经过10多天的努力,surging 网关已经有了大致的雏形,后面还会持续更新完善,请大家持续关注研发的动态 最近也更新了surging新的版本 更新内容: 1. 扩展Zookeeper封装2. 增加服务元数据3. 增加API网关 开源地址:https://github.com/dotnetcore/surging 2.软件环境 IDE:Visual Studio 2017 15.3 Preview ,vscode 框架:.NET core 2.0 依赖程序:Zookeepe.Rabbi

基于Ocelot的gRpcHttp网关

什么是gRpcHttp网关 通俗的讲就是将gRpc提供的服务以rest api的形式提供出去,不需要再单独的写一个webapi去做这件事. gRpcHttp网关好处 减少不必要代码,减少中间层提高通讯效率. 以前可能是这样 用了gRpc网关后是这样 gRpcHttp网关提供哪些功能 可以直接加载proto生成的dll文件 可以只需要proto文件,自动解析出proto文件所提供的model和service 支持header转发 支持gRpc的四种模式 支持gRpc中间件 支持swagger(开发

干货分享微服务spring-cloud(6.Api网关服务zuul)

Spring cloud zuul对Netflix zuul进行了封装实现 新建spring boot项目demo-springcloud-api-gateway,创建启动类ZuulApplication,@EnableZuulProxy启动网关代理的配置,它也是组合注解,启用了服务注册发现和熔断器 项目关键依赖spring-cloud-starter-zuul对网关支持 配置文件application.properties,路由配置主要有传统路由和服务路由,传统路由就是ip和端口这种,服务路由

apisix 基于openresty 的api 网关

apisix 是由openresty 团队开发并开源的微服务api gateway,还不错,官方文档也比较全,同时这个也是一个不错的学习openresty 的项目 以下为来自官方的架构图 插件加载 插件结构 参考资料 https://github.com/iresty/apisix 原文地址:https://www.cnblogs.com/rongfengliang/p/10987625.html