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

限流

我们先来看限流的配置

Reroute节点中的配置如下:

  1. {
  2. "DownstreamPathTemplate": "/api/orders",
  3. "DownstreamScheme": "http",
  4. "DownstreamHostAndPorts": [
  5. {
  6. "Host": "localhost",
  7. "Port": 5001
  8. }
  9. ],
  10. "UpstreamPathTemplate": "/api/orders",
  11. "UpstreamHttpMethod": [ "Get" ],
  12. "RateLimitOptions": {
  13. "ClientWhitelist": [],
  14. "EnableRateLimiting": true,
  15. "Period": "10m",
  16. "PeriodTimespan": 3,
  17. "Limit": 1
  18. }
  19. }

GlobalConfiguration中的配置如下:

  1. "GlobalConfiguration": {
  2. "BaseUrl": "http://localhost:5000",
  3. //限流
  4. "RateLimitOptions": {
  5. "QuotaExceededMessage": "您的请求量超过了配额1/10分钟",
  6. "HttpStatusCode": 999
  7. }
  8. }

配置说明

在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

  1. services
  2. .AddOcelot()
  3. .AddPolly();

修改配置

  1. {
  2. "DownstreamPathTemplate": "/api/orders",
  3. "DownstreamScheme": "http",
  4. "DownstreamHostAndPorts": [
  5. {
  6. "Host": "localhost",
  7. "Port": 5001
  8. }
  9. ],
  10. "UpstreamPathTemplate": "/api/orders",
  11. "UpstreamHttpMethod": [ "Get" ],
  12. "QoSOptions": {
  13. "ExceptionsAllowedBeforeBreaking": 2,
  14. "DurationOfBreak": 5000,
  15. "TimeoutValue": 2000
  16. }
  17. }

配置说明

在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秒

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

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

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


    修改配置


    修改api/orders代码,抛出异常
  1. // GET: api/orders
  2. [Route("api/orders")]
  3. [HttpGet]
  4. public IEnumerable<string> Get()
  5. {
  6. throw new Exception("获取所有订单出错");
  7. }

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

缓存

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

  1. Install-Package Ocelot.Cache.CacheManager

注入缓存组件

  1. services.AddOcelot()
  2. .AddCacheManager(x =>
  3. {
  4. x.WithDictionaryHandle();
  5. });

Ocelot.json配置文件修改

  1. {
  2. "DownstreamPathTemplate": "/api/orders",
  3. "DownstreamScheme": "http",
  4. "DownstreamHostAndPorts": [
  5. {
  6. "Host": "localhost",
  7. "Port": 5001
  8. }
  9. ],
  10. "UpstreamPathTemplate": "/api/orders",
  11. "UpstreamHttpMethod": [ "Get" ],
  12. "FileCacheOptions": {
  13. "TtlSeconds": 60,
  14. "Region": "orders"
  15. }
  16. }

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

配置说明

在Reroute节点中添加了FileCacheOptions节点

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

示例说明

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

验证

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

因为结果被缓存了

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

因为缓存有效期已经过了

Header转化

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

配置如下:

  1. {
  2. "DownstreamPathTemplate": "/api/shopping-carts",
  3. "DownstreamScheme": "http",
  4. "DownstreamHostAndPorts": [
  5. {
  6. "Host": "localhost",
  7. "Port": 5001
  8. }
  9. ],
  10. "DownstreamHeaderTransform": {
  11. "devops": "rdc"
  12. },
  13. "UpstreamPathTemplate": "/api/shopping-carts",
  14. "UpstreamHttpMethod": [ "Get" ],
  15. "UpstreamHeaderTransform": {
  16. "lakin": "rdc",
  17. "CI": "msbuild, jenkins",
  18. "Location": "http://localhost:5001, {BaseUrl}"
  19. }
  20. }

配置说明

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

  1. "DownstreamHeaderTransform": {
  2. "devops": "rdc"
  3. }

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

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

HTTP方法转换

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

  1. {
  2. "DownstreamPathTemplate": "/api/shopping-carts",
  3. "DownstreamScheme": "http",
  4. "DownstreamHttpMethod": "POST",
  5. "DownstreamHostAndPorts": [
  6. {
  7. "Host": "localhost",
  8. "Port": 5001
  9. }
  10. ],
  11. "UpstreamPathTemplate": "/api/shopping-carts",
  12. "UpstreamHttpMethod": [ "Get" ]
  13. }

示例说明

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

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

验证

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

负载均衡

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

  1. {
  2. "DownstreamPathTemplate": "/api/orders",
  3. "DownstreamScheme": "http",
  4. "DownstreamHostAndPorts": [
  5. {
  6. "Host": "localhost",
  7. "Port": 5001
  8. },
  9. {
  10. "Host": "localhost",
  11. "Port": 6001
  12. }
  13. ],
  14. "UpstreamPathTemplate": "/api/orders",
  15. "UpstreamHttpMethod": [ "Get" ],
  16. "LoadBalancerOptions": {
  17. "Type": "RoundRobin"
  18. }
  19. }

配置说明


在DownstreamHostAndPorts指指定多个服务地址


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

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

验证

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

第一次的结果是

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

第二次的结果是

  1. "帅的订单", "我的订单"

第三次的结果是

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

注入/重写中间件

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

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

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

  1. //注入中间件
  2. var configuration = new OcelotPipelineConfiguration
  3. {
  4. PreErrorResponderMiddleware = async (ctx, next) =>
  5. {
  6. ctx.HttpContext.Request.Headers.Add("myreq", "ocelot-request");
  7. await next.Invoke();
  8. }
  9. };
  10. 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的集成.Net微服务实践(五)[服务发现]:Consul介绍和环境搭建

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

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

  1. BeetleX服务网关之限流和缓存

    限流和缓存相关是网关中两个非常重要的功能,前者是保障服务更可靠地运行,后者则可以大大提高应用的吞吐能力.Beetlex.Bumblebee微服务网关提供了两个扩展插件来实现这两个功能,分别是Beetl ...

  2. spring cloud微服务实践四

    spring cloud的hystrix还有一个配搭的库hystrix-dashboard,它是hystrix的一款监控工具,能直观的显示hystrix响应信息,请求成功率等.但是hystrix-da ...

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

    目录 配置 路由 基本配置 占位符 万能模板 优先级 查询参数 请求聚合 默认聚合 自定义聚合 最后 在上篇.Net微服务实践(二):Ocelot介绍和快速开始中我们介绍了Ocelot,创建了一个Oc ...

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

    目录 介绍 服务发现 健康检查.键值存储和数据中心 架构 Consul模式 环境安装 HTTP API 和Command CLI 示例API介绍 最后 在上篇.Net微服务实践(四)[网关]:Ocel ...

  5. .Net微服务实践(二):Ocelot介绍和快速开始

    目录 介绍 基本原理 集成方式 快速开始 创建订单服务 创建产品服务 创建网关 运行验证 最后 上篇.Net微服务实践(一):微服务框架选型 我们对微服务框架整体做了介绍,接下来我们从网关Ocelot ...

  6. .net 微服务实践

    l  前言 本文记录了我的一次.net core 微服务架构实践经验,以及所用到的技术 l  优点 每个服务聚焦于一块业务,无论在开发阶段或是部署阶段都是独立的,更适合被各个小团队开发维护,团队对服务 ...

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

    Kong是Mashape开源的高性能高可用API网关和API服务管理层.它基于OpenResty,进行API管理,并提供了插件实现API的AOP.Kong在Mashape 管理了超过15,000 个A ...

  8. QCon技术干货:个推基于Docker和Kubernetes的微服务实践

    2016年伊始,Docker无比兴盛,如今Kubernetes万人瞩目.在这个无比需要创新与速度的时代,由容器.微服务.DevOps构成的云原生席卷整个IT界.在近期举办的QCon全球软件开发大会上, ...

  9. 微服务实践(七):从单体式架构迁移到微服务架构 - DockOne.io

    原文:微服务实践(七):从单体式架构迁移到微服务架构 - DockOne.io [编者的话]这是用微服务开发应用系列博客的第七篇也是最后一篇.第一篇中介绍了微服务架构模式,并且讨论了微服架构的优缺点: ...

随机推荐

  1. 简单的猜数字小游戏--Python

    猜数字小游戏: #coding=utf-8 import random   answer =random.randint(1,100) #生成随机数 n=int (input("Please ...

  2. Git的使用流程及常用命令汇总

    Git是一个很好用的版本控制系统,本文对于常用的一些命令进行了汇总. 创建一个存储仓库(repository) https://github.com/右上角点击"+"号,New r ...

  3. 微信小程序用setData修改数组或对象中的一个属性值,超好用,最简单的实现方法,不容错过!大神们 都 在 看 的方法!!!

    在page中 data: { info: [{ name: "yuki", tou: "../img/head.jpg", zGong: 130, gMoney ...

  4. SpringBoot WebSocket STOMP 广播配置

    目录 1. 前言 2. STOMP协议 3. SpringBoot WebSocket集成 3.1 导入websocket包 3.2 配置WebSocket 3.3 对外暴露接口 4. 前端对接测试 ...

  5. MongoDB TTL索引的使用

    目录 一.TTL索引介绍 二.TTL索引运行逻辑 三.TTL索引的限制 四.TTL索引的使用场景 1. 指定具体的过期时间属性 2. 插入一个具体的过期时间 3. TTL属性的修改(collMod) ...

  6. ant-design-pro 如何打包成 本地html,双击即可查看

    由于 ant-design-pro 的 mock 是一个单独的服务,所以没有办法整合到一起打包.暂时我是没有找到. 所以解决方案就是不用 mock . 由于 系统有异步调取,所以一旦有异步调取就会失败 ...

  7. 「踩坑记」Android API 判断权限申请结果的闪退问题

    这几天尝试着用Android Studio写一个小工具的时候遇到了一个动态权限申请的问题.权限的申请使用的语句为: ActivityCompat.requestPermissions(this, ne ...

  8. Java多线程并发04——合理使用线程池

    在此之前,我们已经了解了关于线程的基本知识,今天将为各位带来,线程池这一技术.关注我的公众号「Java面典」了解更多 Java 相关知识点. 为什么使用线程池?线程池做的工作主要是控制运行的线程的数量 ...

  9. Java 垃圾收集技术

    前言 在计算机科学中,垃圾收回(GC: garbage collection)是内存自动管理的一种方式,它并不是同 Java 语言一起诞生的,实际上,早在 1959 年为了简化 Lisp 语言的手动内 ...

  10. ERP系统定价模型及费用组成

    很多人选择ERP系统的时候最关心的就是费用问题,因为很多中小企业资金都是比较缺乏的,如果需要使用大量的金钱来购买ERP系统这是不现实的.你知道ERP系统的定价模型有哪些吗?你知道影响ERP系统价格的因 ...