第五节:基于Ocelot网关简介、路由功能、集成Consul使用

一. 基础说明

1. API网关剖析

(1).什么是Api

 API是Application Programming Interface缩写,翻译成中文就是应用程序接口。在实际微服务中可以理解一个个功能方法。就比如你一个商品服务的微服务, 可以对外提供 API 接口为,获取商品目录、获取商品详情等。

(2).什么是网关(Gateway)

 它是一个服务器,用来转发其他服务器通信数据的, 它接收从客户端发送来的请求时,它就像自己拥有资源的源服务器一样对请求进行处理。

(3).什么是Api网关

 通俗的来说就是用来限制客户端访问服务端api一道门槛。

2. 微服务架构中为什么要用网关?

(1).在这之前,我们的技术栈中只引入了Consul,客户端访问Consul拿到对应的IP+Port,最终还是要访问业务服务器的,但很多情况我们并不想让业务服务器直接对外开放,所以这个时候就需要引入网关进行转发了.

(2).现在的微服务还没有加权限校验,如果将权限校验加个每个微服务的业务服务器上,开发量很大,这个时候引入网关,可以在网关层校验.

(3).没有网关,很难做限流,而且各个业务的负责人员不能独立负责自己的服务器器。

3. 网关都有哪些作用?

 路由、负载均衡、限流、认证、授权、链路监控、熔断降级、Service Fabric

4. Ocelot相关信息

(1).依赖程序集:通过Nuget安装 【Ocelot 16.0.1】

  GitHub地址:https://github.com/ThreeMammals/Ocelot

(2).参考文档:

  官网:https://ocelot.readthedocs.io/en/latest/

  ocelot 中文文档:https://blog.csdn.net/sD7O95O/article/details/79623654

  资料:http://www.csharpkit.com/apigateway.html

(3).其他网关框架:

  A. Netflix Zuul +java实现

  B. Kong nginx +lua脚本实现

  C. Tyk go语言开发,收费版本

  D. Ocelot aspnetcore开发的

5. Ocelot的原理

  Ocelot是一堆的asp.net core middleware组成的一个管道。当它拿到请求之后会用一个request builder来构造一个HttpRequestMessage发到下游的真实服务器,等下游的服务返回response之后再由一个middleware将它返回的HttpResponseMessage映射到HttpResponse上。

(1).上游是什么:Ocelot自身就是上游(Upstream)

(2).下游是什么:Ocelot转发给的(业务)服务器就是下游(Downstream)

 

二. 路由功能

架构图:

 

 

 

1.路由的含义

  Ocelot(即上游)按照匹配规则接收客户端发送的请求 将客户端请求转换成业务服务器(即下游)的地址 → 调用下游服务,返回结果  →  Ocelot再将下游服务的结果返回给客户端.

2. 参数介绍

  - Downstream 下游服务配置

  - UpStream 上游服务配置

  - Aggregates 服务聚合配置

  - ServiceName, LoadBalancer, UseServiceDiscovery 配置服务发现

  - AuthenticationOptions 配置服务认证

  - RouteClaimsRequirement 配置Claims鉴权

  - RateLimitOptions 限流配置

  - FileCacheOptions 缓存配置

  - QosOptions 服务质量与熔断

  - DownstreamHeaderTransform 头信息转发

3. 路由直接转发指定的地址

(1).业务场景:

  客户端访问网关 → 网关把请求直接转发给"指定ip+端口"业务服务器 (该场景网关本身不配置Consul,直接转发)

(2).业务编写与测试:

 A. 新建网关项目OcelotGateWay,通过Nuget安装【Ocelot 16.0.1】程序集

 B. 新建一个OcelotConfig.json的配置文件,属性改为"始终复制",用于存放Ocelot的配置。

代码如下:

{
  "Routes": [
    {
      //转发下游(业务服务器)的匹配规则
      "DownstreamPathTemplate": "/api/{url}",
      //下游请求类型
      "DownstreamScheme": "http",
      //下游的ip和端口,和上面的DownstreamPathTemplate匹配起来
      "DownstreamHostAndPorts": [
        {
          "Host": "127.0.0.1",
          "Port": 7001
        }
      ],
      //上游(即Ocelot)接收规则
      "UpstreamPathTemplate": "/GoodsService/{url}",
      //上游接收请求类型
      "UpstreamHttpMethod": [ "Get", "Post" ]
    },
    {
      "DownstreamPathTemplate": "/api/{url}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "127.0.0.1",
          "Port": 7004
        }
      ],
      "UpstreamPathTemplate": "/OrderService/{url}",
      "UpstreamHttpMethod": [ "Get", "Post" ]
    }
  ]
}

剖析上述xml:

- DownstreamPathTemplate:下游路径模板

- DownstreamScheme:下游服务http schema

- DownstreamHostAndPorts:下游服务的地址,如果使用LoadBalancer的话这里可以填多项

- UpstreamPathTemplate: 上游也就是用户输入的请求Url模板,会将这个请求转发给下游,如上代码,客户端请求 :网关ip+端口/GoodsService/{url},会转发给下游:127.0.0.1:7001/api/{url}

- UpstreamHttpMethod: 上游请求http方法,可使用数组

 C. 在Program中通过AddJsonFile将上述json文件加载进来.

  public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                //配置相关
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    //1. 加载json文件 (配置后面两个参数为true,当配置文件发生变化的时候,会自动更新加载,而不必重启整个项目)
                    config.AddJsonFile("OcelotConfig.json", optional: true, reloadOnChange: true);
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    //添加命令行支持(写在上面的Main里也可以)
                    var config = new ConfigurationBuilder().AddCommandLine(args).Build();
                    webBuilder.UseStartup<Startup>();
                });

 D. 在Startup中进行注册和使用,services.AddOcelot(); app.UseOcelot().Wait();

   public void ConfigureServices(IServiceCollection services)
        {
            //1.注册Ocelot
            var ocelot = services.AddOcelot();
            services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            //1.使用Ocelot
            app.UseOcelot().Wait();    //这里不写异步用法了

            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

 E. 启动项目,7001端口启动GoodsService、7004端口启动OrderService、7020端口启动OcelotGateWay,指令如下:

  【dotnet GoodsService.dll --urls="http://*:7001" --ip="127.0.0.1" --port=7001】 业务服务器地址

  【dotnet OrderService.dll --urls="http://*:7004" --ip="127.0.0.1" --port=7004】   业务服务器地址

  【dotnet OcelotGateWay.dll --urls="http://*:7020" --ip="127.0.0.1" --port=7020】  网关地址

 F. PostMan测试

 (1). Get测试: http://127.0.0.1:7020/GoodsService/Catalog/GetGoodById1?id=123,会将请求地址转发给  http://127.0.0.1:7001/api/Catalog/GetGoodById1?id=123 ,请求成功。

 

 (2).  Post请求:http://127.0.0.1:7020/OrderService/Buy/pOrder1,会将请求地址转发给  http://127.0.0.1:7004/api/Buy/pOrder1,请求成功。

 

 

三. 集成Consul

  与Consul结合实现业务服务器的负载均衡(推荐用法)

架构图:

 

 

 

1.业务背景

  上述通过 Ocelot直接转发给指定的 ip+端口,只是为了演示,实际场景中,比如OrderService这个业务服务器,会部署在多台服务器上进行分摊请求压力,当然我可以利用Ocelot自身实现负载均衡,但不推荐,原因有二: ① Ocelot本身的负载均衡机制不完善 ② 每次增加或减少业务服务器,都需要改网关的配置文件,耦合性很强。

       解决方案:Ocelot与Consul结合,客户端访问网关→网关通过ServiceName去Consul中找一个地址进行匹配访问(Ocelot提供了多种算法去Consul中找地址)

2.业务编写与测试

 A. 通过Nuget安装【Ocelot 16.0.1】程序集 和 【Ocelot.Provider.Consul 16.0.1】程序集

 B. 新建一个OcelotConfig.json的配置文件,属性改为"始终复制",用于存放Ocelot的配置.

 配置分享:

//模式三:将Ocelot与consul结合处理,在consul中已经注册业务服务器地址,在Ocelot端不需要再注册了(推荐用法)
{
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/{url}",
      "DownstreamScheme": "http",
      "ServiceName": "GoodsService", //Consul中的服务名称
      "LoadBalancerOptions": {
        "Type": "RoundRobin" //轮询算法:依次调用在consul中注册的服务器
      },
      "UseServiceDiscovery": true, //启用服务发现(可以省略,因为会默认赋值)
      "UpstreamPathTemplate": "/GoodsService/{url}",
      "UpstreamHttpMethod": [ "Get", "Post" ]
    },
    {
      "DownstreamPathTemplate": "/api/{url}",
      "DownstreamScheme": "http",
      "ServiceName": "OrderService",
      "LoadBalancerOptions": {
        "Type": "LeastConnection" //最小连接数算法
      },
      "UseServiceDiscovery": true,
      "UpstreamPathTemplate": "/OrderService/{url}",
      "UpstreamHttpMethod": [ "Get", "Post" ]
    }
  ],
  //下面是配置Consul的地址和端口
  "GlobalConfiguration": {
    //对应Consul的ip和Port(可以省略,因为会默认赋值)
    "ServiceDiscoveryProvider": {
      "Host": "127.0.0.1",
      "Port": 8500
    }
  }
}

剖析配置:  

LoadBalancer将决定负载均衡的算法

- LeastConnection – 将请求发往最空闲的那个服务器

- RoundRobin – 轮流发送

- NoLoadBalance – 总是发往第一个请求或者是服务发现

ServiceName(对应服务名), UseServiceDiscovery 启用注册发现(可省略),ServiceDiscoveryProvider 配置Consul的ip和端口。

 C. 在Program中通过AddJsonFile将上述json文件加载进来. (代码同上)

 D. 在Startup中进行注册和使用,services.AddOcelot().AddConsul(); app.UseOcelot().Wait(); 

代码分享:

        public void ConfigureServices(IServiceCollection services)
        {
            //1.注册Ocelot和Consul
            services.AddOcelot().AddConsul();
            services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            //1.使用Ocelot
            app.UseOcelot().Wait();    //这里不写异步用法了

            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

 E. 启动项目

  7001,7002,7003 端口启动GoodsService、7004,7005,7006端口启动OrderService、7020端口启动OcelotGateWay

  【dotnet GoodsService.dll --urls="http://*:7001" --ip="127.0.0.1" --port=7001】 业务服务器1地址

  【dotnet GoodsService.dll --urls="http://*:7002" --ip="127.0.0.1" --port=7002】 业务服务器1地址

  【dotnet GoodsService.dll --urls="http://*:7003" --ip="127.0.0.1" --port=7003】 业务服务器1地址

  【dotnet OrderService.dll --urls="http://*:7004" --ip="127.0.0.1" --port=7004】   业务服务器2地址

  【dotnet OrderService.dll --urls="http://*:7005" --ip="127.0.0.1" --port=7005】   业务服务器2地址

  【dotnet OrderService.dll --urls="http://*:70046" --ip="127.0.0.1" --port=7006】   业务服务器2地址

  【dotnet OcelotGateWay.dll --urls="http://*:7020" --ip="127.0.0.1" --port=7020】  网关地址

 F. PostMan测试:

  (1).Get测试: http://127.0.0.1:7020/GoodsService/Catalog/GetGoodById1?id=123, 会按照轮询算法依次转发给 :http://127.0.0.1:7001/api/Catalog/GetGoodById1?id=123,http://127.0.0.1:7002/api/Catalog/GetGoodById1?id=123,http://127.0.0.1:7003/api/Catalog/GetGoodById1?id=123,请求成功。

  (2).Post请求:http://127.0.0.1:7020/OrderService/Buy/pOrder1 ,会根据最小连接数算法,转发给7004 7005 7006连接数最小的业务服务器。

测试结果同上述路由转发的图

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @ 2020-06-03 16:46  Yaopengfei  阅读(2125)  评论(9编辑  收藏  举报