.Net微服务实践(四)[网关]:Ocelot限流熔断、缓存以及负载均衡

目录

  • 限流
  • 熔断
  • 缓存
  • Header转化
  • HTTP方法转换
  • 负载均衡
  • 注入/重写中间件
  • 后台管理
  • 最后

在上篇.Net微服务实践(三)[网关]:Ocelot配置路由和请求聚合中我们介绍了Ocelot的配置,主要特性路由以及服务聚合。接下来,我们会介绍Ocelot的限流、熔断、缓存以及负载均衡。

限流

我们先来看限流的配置

Reroute节点中的配置如下:

{
      "DownstreamPathTemplate": "/api/orders",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 5001
        }
      ],
      "UpstreamPathTemplate": "/api/orders",
      "UpstreamHttpMethod": [ "Get" ],
      "RateLimitOptions": {
        "ClientWhitelist": [],
        "EnableRateLimiting": true,
        "Period": "10m",
        "PeriodTimespan": 3,
        "Limit": 1
      }
    }

GlobalConfiguration中的配置如下:

"GlobalConfiguration": {
    "BaseUrl": "http://localhost:5000",
    //限流
    "RateLimitOptions": {
      "QuotaExceededMessage": "您的请求量超过了配额1/10分钟",
      "HttpStatusCode": 999
    }
}

配置说明

在Reroute和GlobalConfiguration节点中添加了RateLimitOptions节点

  • ClientWhitelist - 白名单,也就是不受限流控制的客户端
  • EnableRateLimiting - 是否开启限流
  • Period & Limit - 在一段时间内允许的请求次数
  • PeriodTimespan - 客户端的重试间隔数,也就是客户端间隔多长时间可以重试
  • QuotaExceededMessage - 限流以后的提示信息
  • HttpStatusCode - 超出配额时,返回的http状态码

示例说明

客户端在10分钟之内只允许请求一次http://localhost:5000/api/orders,在请求之后3秒钟之后可以重试

验证

修改配置,运行示例程序,

访问http://localhost:5000/api/orders,第一次可以正常获取返回结果,再次访时,显示"您的请求量超过了配额1/10分钟, 并且response状态码是999

PeriodTimespan的验证

修改Period为1s, 修改PeriodTimespan为10,这样当前的配置是1秒中允许一个请求,10秒后才能重试。 再次运行示例程序。

访问http://localhost:5000/api/orders,第一次可以正常获取返回结果, 等待两秒,再次访问,大家想一下,这个时候,会不会返回正常结果(已经过了两秒)。这时还是返回999,为什么? 因为尽管配额上是允许的,但是因为配置是客户端10秒以后才能重试,而这时只等待了2秒,所以还是返回999.

熔断

Ocelot的熔断使用了Polly来实现,在OcelotGateway项目添加Polly包

注入Polly

services
        .AddOcelot()
        .AddPolly();

修改配置

{
     "DownstreamPathTemplate": "/api/orders",
     "DownstreamScheme": "http",
     "DownstreamHostAndPorts": [
       {
         "Host": "localhost",
         "Port": 5001
       }
     ],
     "UpstreamPathTemplate": "/api/orders",
     "UpstreamHttpMethod": [ "Get" ],
     "QoSOptions": {
       "ExceptionsAllowedBeforeBreaking": 2,
       "DurationOfBreak": 5000,
       "TimeoutValue": 2000
     }
   }

配置说明

在Reroute节点中添加了QoSOptions节点

  • ExceptionsAllowedBeforeBreaking - 在熔断之前允许的异常次数
  • DurationOfBreak - 熔断时长 ,单位毫秒
  • TimeoutValue - 请求超时设置, 单位毫秒

示例说明

当访问http://localhost:5000/api/orders出现2次异常后,服务熔断5秒,如果服务响应超过2秒,也触发熔断条件

验证

  • 场景一:服务宕机


    修改配置,只启动网关,不启动oder api,访问http://localhost:5000/api/orders,第一次有响应耗时,返回500,第二次也有响应耗时,返回500. 第三次则快速返回503 Service Unavalible, 服务熔断了。

  • 场景二:超时


    修改配置


    修改api/orders代码,等待3秒

// GET: api/orders
[Route("api/orders")]
[HttpGet]
public  IEnumerable<string> Get()
{
    Task.Delay(3000).Wait();
    return new string[] { "刘明的订单", "王天的订单" };
}

启动网关,启动order-api,访问http://localhost:5000/api/orders,返回503

  • 场景三:服务正常响应,但是服务500 内部错误


    修改配置


    修改api/orders代码,抛出异常

// GET: api/orders
[Route("api/orders")]
[HttpGet]
public  IEnumerable<string> Get()
{
    throw new Exception("获取所有订单出错");
}

启动网关,启动order-api,访问http://localhost:5000/api/orders, 不触发熔断

缓存

缓存使用了CacheManageer来实现,添加CacheManager包

Install-Package Ocelot.Cache.CacheManager

注入缓存组件

services.AddOcelot()
        .AddCacheManager(x =>
        {
            x.WithDictionaryHandle();
        });

Ocelot.json配置文件修改

{
  "DownstreamPathTemplate": "/api/orders",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "localhost",
      "Port": 5001
    }
  ],
  "UpstreamPathTemplate": "/api/orders",
  "UpstreamHttpMethod": [ "Get" ],
  "FileCacheOptions": {
    "TtlSeconds": 60,
    "Region": "orders"
  }
}

缓存是根据 downstream service 的URL来缓存的

配置说明

在Reroute节点中添加了FileCacheOptions节点

  • TtlSeconds - 缓存有效期,单位是秒
  • Region - 缓存分区, 可以通过调用后台Api 来清空一个region下的缓存

示例说明

当访问http://localhost:5000/api/orders后,结果会缓存60秒,在缓存有效期内即使原始的order api的返回结果发生变化,通过网关请求时,还是会返回缓存的结果。

验证

  • 修改配置,只启动网关,启动oder api,访问http://localhost:5000/api/orders,返回的结果如下
"刘明的订单", "王天的订单"
  • 修改api/orders, 重新启动api/orders
[Route("api/orders")]
[HttpGet]
public  IEnumerable<string> Get()
{
    return new string[] { "帅的订单", "我的订单" };
}
  • 再次访问http://localhost:5000/api/orders, 这个时候是会返回什么结果呢?, 验证显示还是返回
"刘明的订单", "王天的订单"

因为结果被缓存了

  • 等待2分钟,再访问http://localhost:5000/api/orders,这个时候是会返回什么结果呢?, 验证显示返回了新的结果
"帅的订单", "我的订单"

因为缓存有效期已经过了

Header转化

Ocelot允许在上游服务的request和下游服务的response的header中添加、替换信息

配置如下:

{
  "DownstreamPathTemplate": "/api/shopping-carts",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "localhost",
      "Port": 5001
    }
  ],
  "DownstreamHeaderTransform": {
    "devops": "rdc"
  },
  "UpstreamPathTemplate": "/api/shopping-carts",
  "UpstreamHttpMethod": [ "Get" ],
  "UpstreamHeaderTransform": {
    "lakin": "rdc",
    "CI": "msbuild, jenkins",
    "Location": "http://localhost:5001, {BaseUrl}"
  }

}

配置说明

在Reroute节点中添加了DownstreamHeaderTransform节点和UpstreamHeaderTransform节点

"DownstreamHeaderTransform": {
    "devops": "rdc"
  }

说明:在下游服务的response中添加一个header, key是devops, value是rdc

"UpstreamHeaderTransform": {
    "lakin": "rdc",
    "CI": "msbuild, jenkins",
    "Location": "http://localhost:5001, {BaseUrl}"
  }
  • 添加header信息


    在上游服务的request中添加一个header, key是lakin, value是rdc

  • 替换header信息


    在上游服务的request中, 将key是CI的header, 其值由msbuild替换为jenkins

  • 替换时使用placeholder


    在上游服务的request中, 将key是Location的header, 其值由http://localhost:5001替换为{BaseUrl} placehokder

示例说明

当访问http://localhost:5000/api/orders后,结果会缓存60秒,在缓存有效期内即使原始的order api的返回结果发生变化,通过网关请求时,还是会返回缓存的结果。

验证

  • 修改Order Service, 添加一个ShoppingCart api, 代码如下
// GET: api/shopping-carts
[Route("api/shopping-carts")]
[HttpGet]
public IEnumerable<string> Get()
{
    Console.WriteLine($"开始打印header信息");
    foreach (var item in this.Request.Headers)
    {
        Console.WriteLine($"{item.Key} - {item.Value}");
    }
    Console.WriteLine($"打印header信息完成");
    return new string[] { "洗发水", "无人机" };
}
  • 启动网关、启动Order Service
  • 使用Postman调用http://localhost:5000/api/shopping-carts, 在request中添加两个header项
    "CI": "msbuild",
    "Location": "http://localhost:5001"
  • 发起请求
  • 在Order Service的控制台,可以看到如下输出, 添加一个header项,替换两个header项的值
开始打印header信息CI
lakin - rdc
CI - jenkins
Location - http://localhost:5000
打印header信息完成
  • 检查Postman中response的header信息,会发现添加了如下的header项
devops - rdc

HTTP方法转换

Ocelot允许在路由时转化HTTP方法

{
  "DownstreamPathTemplate": "/api/shopping-carts",
  "DownstreamScheme": "http",
  "DownstreamHttpMethod": "POST",
  "DownstreamHostAndPorts": [
    {
      "Host": "localhost",
      "Port": 5001
    }
  ],
  "UpstreamPathTemplate": "/api/shopping-carts",
  "UpstreamHttpMethod": [ "Get" ]
}

示例说明

上述示例中,将GET /api/shopping-carts 路由到 POST /api/shopping-carts, 将GET转换成了POST

适用场景:例如有些已经存在的的API,因为某些历史原因都是用POST,在通过网关对外提供服务时,就可以按照标准API进行转换

验证

  • 当前GET /api/shopping-carts返回如下结果
"洗发水", "无人机"
  • 我们在ShoppingCartController中添加一个新的POST API
[Route("api/shopping-carts")]
[HttpPost]
public string Post()
{
    return "添加商品到购物车成功";
}
添加商品到购物车成功

负载均衡

Ocelot内置了负载均衡,我们先来看配置

{
     "DownstreamPathTemplate": "/api/orders",
     "DownstreamScheme": "http",
     "DownstreamHostAndPorts": [
       {
         "Host": "localhost",
         "Port": 5001
       },
       {
         "Host": "localhost",
         "Port": 6001
       }
     ],
     "UpstreamPathTemplate": "/api/orders",
     "UpstreamHttpMethod": [ "Get" ],
     "LoadBalancerOptions": {
       "Type": "RoundRobin"
     }
}

配置说明


在DownstreamHostAndPorts指指定多个服务地址


在Reroute节点中添加LoadBalancerOptions,这是负载均衡的配置节点,其中Type属性指定了负载均衡的算法, 它有如下几个值:

  • LeastConnection – 将请求发往最空闲的那个服务器
  • RoundRobin – 轮流发送
  • NoLoadBalance – 总是发往第一个请求(如果配置了服务发现,则总是发往发现的第一个服务地址)

验证

  • 启动网关
  • 修改api/orders的代码,并启动Order Service
[Route("api/orders")]
[HttpGet]
public  IEnumerable<string> Get()
{
    return new string[] { "刘明的订单", "王天的订单" };
}
  • 拷贝一份Order Service的副本,修改api/orders的代码,修改副本的启动端口为6001, 并启动Order Service
[Route("api/orders")]
[HttpGet]
public  IEnumerable<string> Get()
{
    return new string[] { "帅的订单", "我的订单" };
}

第一次的结果是

"刘明的订单", "王天的订单"

第二次的结果是

"帅的订单", "我的订单"

第三次的结果是

"刘明的订单", "王天的订单"

注入/重写中间件

Ocelot本身是一组中间件,它也提供了方式来注入和重写其中的某些中间件:

  • PreErrorResponderMiddleware - 在所有Ocelot中间件之前运行, 允许用户在Ocelot管道运行之前和运行之后提供任何行为。
  • PreAuthenticationMiddleware - 提供预身份认证逻辑,在身份认证中间件之前运行
  • AuthenticationMiddleware - 覆写Ocelot中间件提供的身份认证逻辑
  • PreAuthorisationMiddleware - 提供预授权逻辑,在授权中间件之前运行
  • AuthorisationMiddleware - 覆写Ocelot中间件提供的授权逻辑
  • PreQueryStringBuilderMiddleware - 在QueryString转换之前,提供预处理逻辑

下面是注入PreErrorResponderMiddleware中间件的代码示例:

//注入中间件
var configuration = new OcelotPipelineConfiguration
{
    PreErrorResponderMiddleware = async (ctx, next) =>
    {
        ctx.HttpContext.Request.Headers.Add("myreq", "ocelot-request");
        await next.Invoke();
    }
};
app.UseOcelot(configuration).Wait();

注意: Ocelot也是一组中间件,所以可以在Ocelot中间件之前,按常规方式添加任何中间件, 但是不能在Ocelot中间件之后添加,因为Ocelot没有调用 next

后台管理

Ocelot提供了一组后台管理的API, 从前三篇文章可以看出,Ocelot主要也就是配置文件的管理,所以API主要也就是管理配置

  • 获取管理后台的token


    POST {adminPath}/connect/token

  • 获取配置


    GET {adminPath}/configuration

  • 创建/修改配置


    POST {adminPath}/configuration

  • 删除缓存


    DELETE {adminPath}/outputcache/{region}

最后

本篇我们介绍了Ocelot的限流、熔断、缓存、负载均衡以及其他一些特性。到目前为止,Ocelot的基本配置和功能都已经介绍完了。接下里我们会结合consul来介绍服务发现,以及Ocelot和Consul的集成

示例代码下载地址: https://github.com/lcyhjx/ocelot-demo/tree/master

原文地址:https://www.cnblogs.com/lcyhjx/p/12687152.html

时间: 2024-10-03 00:46:09

.Net微服务实践(四)[网关]:Ocelot限流熔断、缓存以及负载均衡的相关文章

微服务架构下的分布式限流方案思考

1.微服务限流 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.缓存.降级和限流是保护微服务系统运行稳定性的三大利器.缓存的目的是提升系统访问速度和增大系统能处理的容量,而降级是当服务出问题或者影响到核心流程的性能则需要暂时屏蔽掉,待高峰或者问题解决后再打开,而有些场景并不能用缓存和降级来解决,比如稀缺资源.数据库的写操作.频繁的复杂查询,因此需有一种手段来限制这些场景的请求量,即限流. 比如当我们设计了一个函数,准备上线,这时候这个函数会消耗一些资源,处理上限是1秒服务3000个QPS

第六篇 网关ocelot,搭配consul。达到负载均衡的效果

首先nuget Ocelot版本5.6.0-unstable0028 Consul版本0.7.2.6 根目录新建一个 Ocelot.json { "ReRoutes": [ { "DownstreamPathTemplate": "/{url}",//任意的url "DownstreamScheme": "http",// "UpstreamPathTemplate": "/V

spring cloud微服务实践四

spring cloud的hystrix还有一个配搭的库hystrix-dashboard,它是hystrix的一款监控工具,能直观的显示hystrix响应信息,请求成功率等.但是hystrix-dashboard只能查看单机和集群的信息,如果需要将多台的信息汇总起来的话就需要使用turbine. 注:这一个系列的开发环境版本为 java1.8, spring boot2.x, spring cloud Greenwich.SR2, IDE为 Intelli IDEA hystrix-dashb

.Net微服务实践(五)[服务发现]:Consul介绍和环境搭建

目录 介绍 服务发现 健康检查.键值存储和数据中心 架构 Consul模式 环境安装 HTTP API 和Command CLI 示例API介绍 最后 在上篇.Net微服务实践(四)[网关]:Ocelot限流熔断.缓存以及负载均衡中介绍Ocelot的限流.熔断.缓存.负载均衡以及其他一些特性,Ocelot的基本配置和功能都已经介绍完了.本篇我们会介绍服务发现Consul. 介绍 Consul是一款简单.易用.可伸缩性强的服务治理系统.主要核心功能有:服务发现.健康检查.键值存储和多数据中心. 服

.Net微服务实践(三):Ocelot配置路由和请求聚合

目录 配置 路由 基本配置 占位符 万能模板 优先级 查询参数 请求聚合 默认聚合 自定义聚合 最后 在上篇.Net微服务实践(二):Ocelot介绍和快速开始中我们介绍了Ocelot,创建了一个Ocelot Hello World程序,接下来,我们会介绍Oclot的主要特性路由和另外一个特性请求聚合.这些特性都是通过配置来实现的. 配置 { "ReRoutes": [], "GlobalConfiguration": {} } Ocelot的配置文件包含两个节点:

京东、宅急送的微服务实践分享(下)| 架构师小组交流会

架构师小组交流会是由国内知名公司技术专家参与的技术交流会,每期选择一个时下最热门的技术话题进行实践经验分享. 第一期:来自沪江.滴滴.蘑菇街.扇贝架构师的 Docker 实践分享 第二期:来自滴滴.微博.唯品会.魅族.点评关于高可用架构的实践分享 第三期:京东.宅急送的微服务实践分享(上)第三期小组交流会邀请到了国内电商领头羊京东.宅急送技术负责人,在上篇京东.宅急送的微服务实践分享(上)中他们介绍了各自产品的微服务实践,本次他们就 API 网关的设计.服务的 Docker 化.服务测试.持续集

买单侠微服务的API网关演化之路

伴随着买单侠业务的快速发展,能够支持独立开发.独立部署.独立扩展的微服务在秦苍得到了广泛应用和蓬勃发展,短短3年左右时间,已经发展到了300+个微服务,并且还在快速增长中. 研发逐渐意识到伴随着微服务规模化的增长,必需要重视微服务的基础设施建设(API网关.服务注册中心.调用链跟踪等)才能保持开发效率和产品的质量. API网关作为访问微服务的大门, 是访问后台服务的入口,作为最常用的基础服务之一,其重要性不言而喻.在买单侠微服务的发展道路上,经过了以下摸索发展阶段,希望能给规模化应用微服务的攻城

微服务实践(总)-原文

本系列文章为 dockone.io 首发,转载请标明出处,以示尊重!! http://dockone.io/people/hokingyang   希望读者通过本系列文章对微服务优缺点有一个比较好的理解,以及何时使用这种架构.也许微服务架构比较适合你的应用.也许你正在开发一个大型.复杂单体式应用,日常开发和部署经验非常缓慢和痛苦,而微服务看起来是远方一个极乐世界.幸运的是,有可以参考的脱离苦海的策略,本篇文章中,我将描述如何逐步将单体式应用迁移到微服务架构. 本系列七篇文章列表如下: 微服务实战

AspNetCore微服务下的网关-Kong(一)

Kong是Mashape开源的高性能高可用API网关和API服务管理层.它基于OpenResty,进行API管理,并提供了插件实现API的AOP.Kong在Mashape 管理了超过15,000 个API,为200,000开发者提供了每月数十亿的请求支持.本文将从架构.API管理.插件三个层面介绍Kong. 架构 按照康威定律,我们系统架构会拆的很散,系统由一堆服务组成,如下图所示: 库存服务.优惠券服务.价格服务时之前都会做一些特殊处理,如限流.黑白名单,日志.请求统计.而这些处理几乎是所有服