Ocelot简易教程(四)之请求聚合以及服务发现

简介:

Ocelot简易教程(四)之请求聚合以及服务发现

上篇文章给大家讲解了Ocelot的一些特性并对路由进行了详细的介绍,今天呢就大家一起来学习下Ocelot的请求聚合以及服务发现功能。希望能对大家有所帮助。

作者:依乐祝
原文地址:https://www.cnblogs.com/yilezhu/p/9695639.html

请求聚合

Ocelot允许你声明聚合路由,这样你可以把多个正常的ReRoutes打包并映射到一个对象来对客户端的请求进行响应。比如,你请求订单信息,订单中又包含商品信息,这里就设计到两个微服务,一个是商品服务,一个是订单服务。如果不运用聚合路由的话,对于一个订单信息,客户端可能需要请求两次服务端。实际上这会造成服务端额外的开销。这时候有了聚合路由后,你只需要请求一次聚合路由,然后聚合路由会合并订单跟商品的结果都一个对象中,并把这个对象响应给客户端。使用Ocelot的此特性可以让你很容易的实现前后端分离的架构。
为了实现Ocelot的请求功能,你需要在ocelot.json中进行如下的配置。这里我们指定了了两个正常的ReRoutes,然后给每个ReRoute设置一个Key属性。最后我们再Aggregates节点中的ReRouteKeys属性中加入我们刚刚指定的两个Key从而组成了两个ReRoutes的聚合。当然我们还需要设置UpstreamPathTemplate匹配上游的用户请求,它的工作方式与正常的ReRoute类似。

注意:不要把Aggregates中UpstreamPathTemplate设置的跟ReRoutes中的UpstreamPathTemplate设置成一样。

下面我们先上个实例例子先!演示代码已经同步更新Github上。有兴趣的朋友可以查看源码:https://github.com/yilezhu/OcelotDemo

在开始实例前先把我们的ocelot Nuget包升级到最新的12.0.0版本,当然你也可以不进行升级。这里需要注意一下,如果你升级到12.0.0的版本的话,那么你config.AddOcelot()的用法会发生改变,需要传入参数config.AddOcelot(hostingContext.HostingEnvironment)

1.为了演示的需要这里我们新增一个类库项目,分别新建两个类,一个是商品Good类,一个是订单Order类(这里只是为了演示的需要,所以代码很简陋)如下所示:

 public class Goods
    {
        public int Id { get; set; }
        public string Content { get; set; }
    }

public class Orders
    {
        public int Id { get; set; }
        public string Content { get; set; }
    }
  1. 接下来我们给OrderApi以及GoodApi分别新建一个控制器,并返回相应的实体。如下所示:

    //GoodApi项目中
    [Route("api/[controller]")]
    [ApiController]
    public class GoodController : ControllerBase
    {
     // GET api/Good/5
     [HttpGet("{id}")]
     public ActionResult<string> Get(int id)
     {
         var item = new Goods
         {
             Id = id,
             Content = $"{id}的关联的商品明细",
         };
         return JsonConvert.SerializeObject(item);
     }
    }
      //OrderApi项目中  
    [Route("api/[controller]")]
    [ApiController]
    public class OrderController : ControllerBase
    {
     // GET api/Order/5
     [HttpGet("{id}")]
     public ActionResult<string> Get(int id)
     {
         var item = new Orders {
             Id=id,
             Content=$"{id}的订单明细",
         };
         return JsonConvert.SerializeObject(item);
     }
    }
  1. 接下来我们分别在ocelot.good.json以及ocelot.order.json中新增一个路由,并给出Keys.如下所示:

这里注意,跟上篇文章中的路由不同的是,这里多了一个Key属性。

//ocelot.good.json
{
      "DownstreamPathTemplate": "/api/Good/{id}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 1001
        }
      ],
      "UpstreamPathTemplate": "/good/{id}",
      "UpstreamHttpMethod": [ "Get", "Post" ],
      "Key": "Good",
      "Priority": 2
    }
//ocelot.order.json
{
      "DownstreamPathTemplate": "/api/Order/{id}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 1002
        }
      ],
      "UpstreamPathTemplate": "/order/{id}",
      "UpstreamHttpMethod": [ "Get", "Post" ],
      "Key": "Order",
      "Priority": 2
    }
  1. 在ocelot.all.json中加入聚合配置,如下所示:

      "Aggregates": [
        {
          "ReRouteKeys": [
            "Good",
            "Order"
          ],
          "UpstreamPathTemplate": "/GetOrderDetail/{id}"
        }
      ]

注意:这里AggregatesReRoutes同级,ReRouteKeys中填写的数组就是上面步骤3中设置的Key属性对应的值。

  1. 我们分别运行起来三个项目,然后访问接口地址:http://localhost:1000/GetOrderDetail/1 会得到如下的聚合响应内容:

1537715634581
格式化后代码如下:

{
    "Good":{
        "Id":1,
        "Content":"1的关联的商品明细"
    },
    "Order":{
        "Id":1,
        "Content":"1的订单明细"
    }
}
  1. 眼尖的朋友可能已经猜到了。聚合路由返回的内容就是json串。json串由ReRouteKeys组成,每个Key的内容就是具体下游响应的内容了!实例代码已经同步更新到Github上,地址:https://github.com/yilezhu/OcelotDemo

Ocelot将始终使用聚合请求返回内容类型application/json。还有需要注意的是聚合请求不会返回404请求。如果两个下游都返回404状态码的话,这里聚合后的响应也不会返回404,只会返回空的json串,拿上面的实例,如果两个下游都返回404的话,那么他的响应代码类似下面这样:

{
    "Good": ,
    "Order":
}

如果下游服务返回404,则聚合将仅为该下游服务返回任何内容。即使所有下游都返回404,它也不会将聚合响应更改为404。

服务发现

Ocelot允许您指定服务发现提供程序,并将使用它来查找Ocelot将请求转发到的下游服务的主机和端口。目前,这仅在GlobalConfiguration部分中受支持,这意味着相同的服务发现提供程序将用于为ReRoute级别指定ServiceName的所有ReRoutes。

Consul

在使用Consul前你首先要做的就是安装在Ocelot中提供Consul支持的NuGet包
Install-Package Ocelot.Provider.Consul
然后将下面的内容添加在ConfigureServices方法中

services.AddOcelot()//注入Ocelot服务
                    .AddConsul(); 

GlobalConfiguration中需要加入以下内容。如果您未指定主机和端口,则将使用Consul默认值。

"ServiceDiscoveryProvider": {
    "Host": "localhost",
    "Port": 8500,
    "Type": "Consul"
}

注意:如果你采用AddOcelot()这种方式来自动加载ocelot配置文件的方式,那么你需要新建一个ocelot.global.json文件,然后加入上面的配置:如下所示:

{
"GlobalConfiguration": {
  "ServiceDiscoveryProvider": {
    "Host": "localhost",
    "Port": 8500,
    "Type": "Consul"
  }
}
}
然后重新运行dotnet run命令会自动合并配置信息到Ocelot.json中,生成的对应内容如下:
​```C#
"ServiceDiscoveryProvider": {
      "Host": "localhost",
      "Port": 8500,
      "Type": "Consul",
      "Token": null,
      "ConfigurationKey": null,
      "PollingInterval": 0
    }

这个上篇文章中已经进行了相关的介绍。

为了告诉Ocelot ReRoute是为其主机和端口使用服务发现提供程序,您必须在下游请求时添加要使用的ServiceName和负载均衡器。目前,Ocelot可以使用RoundRobin和LeastConnection算法。如果未指定负载均衡器,则Ocelot将不会对请求进行负载均衡。

{
    "DownstreamPathTemplate": "/api/posts/{postId}",
    "DownstreamScheme": "https",
    "UpstreamPathTemplate": "/posts/{postId}",
    "UpstreamHttpMethod": [ "Put" ],
    "ServiceName": "product",
    "LoadBalancerOptions": {
        "Type": "LeastConnection"
    },
}

设置此项后,Ocelot将从服务发现提供程序中查找下游主机和端口,并跨任何可用服务进行负载平衡请求。

动态路由

作者的想法是在使用服务发现提供程序时启用动态路由。在此模式下,Ocelot将使用上游路径的第一个段来与服务发现提供程序一起查找下游服务。

例如,使用https://api.yilezhu.cn/product/products 等网址调用ocelot 。Ocelot将采用产品路径的第一部分product,并将其用作在Consul中查找服务的Key。如果consul返回一个服务,Ocelot将使用从consul返回的主机和端口以及剩余路径段组合后的Url来进行请求的响应。,如:http:// hostfromconsul:portfromconsul/products。Ocelot将正常向下游URL转发查询字符串。即query

要启用动态路由,您需要在配置中保留0个ReRoutes。目前您无法混合动态和配置ReRoutes。除此之外,您还需要指定上面概述的Service Discovery提供程序详细信息和下游http / https方案作为DownstreamScheme。

除此之外,您还可以设置RateLimitOptions,QoSOptions,LoadBalancerOptions和HttpHandlerOptions,DownstreamScheme(您可能希望在https上调用Ocelot,但可以通过http与私有服务进行通信),这些将应用于所有动态ReRoutes。

配置可能看起来像:

{
    "ReRoutes": [],
    "Aggregates": [],
    "GlobalConfiguration": {
        "RequestIdKey": null,
        "ServiceDiscoveryProvider": {
            "Host": "localhost",
            "Port": 8500,
            "Type": "Consul",
            "Token": null,
            "ConfigurationKey": null
        },
        "RateLimitOptions": {
            "ClientIdHeader": "ClientId",
            "QuotaExceededMessage": null,
            "RateLimitCounterPrefix": "ocelot",
            "DisableRateLimitHeaders": false,
            "HttpStatusCode": 429
        },
        "QoSOptions": {
            "ExceptionsAllowedBeforeBreaking": 0,
            "DurationOfBreak": 0,
            "TimeoutValue": 0
        },
        "BaseUrl": null,
            "LoadBalancerOptions": {
            "Type": "LeastConnection",
            "Key": null,
            "Expiry": 0
        },
        "DownstreamScheme": "http",
        "HttpHandlerOptions": {
            "AllowAutoRedirect": false,
            "UseCookieContainer": false,
            "UseTracing": false
        }
    }
}

Ocelot还允许您设置DynamicReRoutes,允许您为每个下游服务设置速率限制规则。如果您有一个产品和搜索服务,并且您希望对另一个进行速率限制,则此功能非常有用。这方面的一个例子如下。

{
    "DynamicReRoutes": [
        {
        "ServiceName": "product",
        "RateLimitRule": {
                "ClientWhitelist": [],
                "EnableRateLimiting": true,
                "Period": "1s",
                "PeriodTimespan": 1000.0,
                "Limit": 3
            }
        }
    ],
    "GlobalConfiguration": {
        "RequestIdKey": null,
        "ServiceDiscoveryProvider": {
            "Host": "localhost",
            "Port": 8523,
            "Type": "Consul"
        },
        "RateLimitOptions": {
            "ClientIdHeader": "ClientId",
            "QuotaExceededMessage": "",
            "RateLimitCounterPrefix": "",
            "DisableRateLimitHeaders": false,
            "HttpStatusCode": 428
        }
        "DownstreamScheme": "http",
    }
}

此配置意味着如果您在/product/上进入Ocelot请求,则动态路由将启动,并且ocelot将使用针对DynamicReRoutes部分中的产品服务的速率限制设置。

GitHub地址

https://github.com/yilezhu/OcelotDemo

Ocelot简易教程目录

  1. Ocelot简易教程(一)之Ocelot是什么
  2. Ocelot简易教程(二)之快速开始1
  3. Ocelot简易教程(二)之快速开始2
  4. Ocelot简易教程(三)之主要特性及路由详解
  5. Ocelot简易教程(四)之请求聚合以及服务发现

总结

本文接着上篇文章进行了Ocelot请求聚合功能以及服务发现功能的介绍,并且对Ocelot动态路由功能也进行了简单的阐述。对于请求聚合这块进行了相关实例代码的演示,并已经更新到Github上面了!希望能对大家有所帮助!

相关实践学习
部署高可用架构
本场景主要介绍如何使用云服务器ECS、负载均衡SLB、云数据库RDS和数据传输服务产品来部署多可用区高可用架构。
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
2月前
|
XML Dubbo Java
【Dubbo3高级特性】「框架与服务」 Nacos作为注册中心-服务分组及服务分组聚合实现
【Dubbo3高级特性】「框架与服务」 Nacos作为注册中心-服务分组及服务分组聚合实现
63 0
|
2月前
|
负载均衡 算法 Java
SpringCloud负载均衡源码解析 | 带你从表层一步步剖析Ribbon组件如何实现负载均衡功能
SpringCloud负载均衡源码解析 | 带你从表层一步步剖析Ribbon组件如何实现负载均衡功能
|
4月前
|
负载均衡 前端开发 Java
字节后端面试题(前端发送请求到后端的过程(MVC),网关gateway作用,怎么解决跨域,各微服务组件作用)
字节后端面试题(前端发送请求到后端的过程(MVC),网关gateway作用,怎么解决跨域,各微服务组件作用)
142 0
|
12月前
|
存储 负载均衡 容灾
Nacos多级服务存储模型, NacosRule负载均衡规则入门
下面来简单认识一下今天的主角Nacos吧.Nacos给我们提供了一个这样的服务分级存储模型:1级是服务, 2级是集群, 3级是实例. Nacos提供了权重配置来控制访问频率, 权重越大访问频率越高;Nacos同一集群的默认权重是1:1的;Nacos控制台可以设置实例的权重值0~1之间
309 0
|
12月前
|
Dubbo 应用服务中间件 测试技术
带你读《Apache Dubbo微服务开发从入门到精通》—— 三、 标签路由规则
带你读《Apache Dubbo微服务开发从入门到精通》—— 三、 标签路由规则
199 1
|
12月前
|
负载均衡 Dubbo JavaScript
带你读《Apache Dubbo微服务开发从入门到精通》—— 四、 脚本路由规则
带你读《Apache Dubbo微服务开发从入门到精通》—— 四、 脚本路由规则
160 0
|
12月前
|
前端开发 安全 JavaScript
给微服务项目引入GateWay处理跨域和统一路由
给微服务项目引入GateWay处理跨域和统一路由
439 0
|
负载均衡 网络协议 Java
Ribbon简化负载均衡调用服务端实战
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。它是一个基于HTTP和TCP的客户端负载均衡器。它可以通过在客户端中配置ribbonServerList来设置服务端列表去轮询访问以达到均衡负载的作用。
|
JSON NoSQL JavaScript
如何使用 Gateway 搭建网关服务及实现动态路由?
如何使用 Gateway 搭建网关服务及实现动态路由?
SpringCloud学习(十七):Gateway网关的自定义全局GlobalFilter
虽然官方为Gateway提供了很多filter,但其实并不使用,我们更多的还是使用自己的配置。 在9527网关模块中新建一个filter包,在里面写一个类来实现自定义filter
161 0
SpringCloud学习(十七):Gateway网关的自定义全局GlobalFilter