【3分钟就会系列】使用Ocelot+Consul搭建微服务吧!

C#

浏览数:258

2019-7-2

一.什么Ocelot?

API网关是一个服务器,是系统的唯一入口。API 网关一般放到微服务的最前端,并且要让API 网关变成由应用所发起的每个请求的入口。这样就可以明显的简化客户端实现和微服务应用程序之间的沟通方式。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。

Ocelot 是一个使用在 .NET Core 平台上的一个 API Gateway,这个项目的目标是在 .NET 上面运行微服务架构。Ocelot 框架内部集成了 IdentityServer(身份验证)和 Consul(服务注册发现),还引入了 Polly 来处理进行故障处理。目前,腾讯和微软Ocelot 在官网贴出来的客户。

手把手搭建一个网关

在此之前你应该去学一学如何搭建服务集群,那么这将有效与你学习API网关服务,传送门,再此基础上再添加一个名为  MicroService.APIGetway 的ASP.NET WebApi项目。

在该项目中,我们通过Nuget安装Ocelot,或者通过m命令行进行安装。

注意:最新版的不建议使用,会出现一些内部错误,建议使用10.0.1以下的版本。

创建相关文件夹

 在其中应该创建服务注册以及网关文件夹,那么效果图如下:

添加网关配置文件

在项目中,添加一个配置文件 ocelot.json ,并将文件属性中 “赋值到输出目录” 的值修改为 “如果较新则复制”。

 

在ocelot.json文件夹中,加入以下内容。

{
  "ReRoutes": [
    {
      "UseServiceDiscovery": true,
      "DownstreamPathTemplate": "/api/values",
      "DownstreamScheme": "http",
      "ServiceName": "T169.OcelotConsul.Service",
      "LoadBalancerOptions": {
        "Type": "RoundRobin"
      },
      "UpstreamPathTemplate": "/ss",
      "UpstreamHttpMethod": [ "Get", "Post" ],
      "ReRoutesCaseSensitive": false // non case sensitive
    }
  ],
  "GlobalConfiguration": {
    "ServiceDiscoveryProvider": {
      "Host": "localhost", // Consul Service IP
      "Port": 8500 // Consul Service Port
    }
  }
}

以下是 Ocelot 官方给出的配置文件的节点说明

{
  //官⽅方⽂文档ReRoutes全节点示例例
  "ReRoutes": [
    {
      //Upstream表示上游请求,即客户端请求到API Gateway的请求
      "UpstreamPathTemplate": "/", //请求路路径模板
      "UpstreamHttpMethod": [ //请求⽅方法数组
        "Get",
        "POST",
        "PUT",
        "DELETE",
        "OPTIONS"
      ],
      //Downstreamb表示下游请求,即API Gateway转发的⽬目标服务地址
      "DownstreamScheme": "http", //请求协议,⽬目前应该是⽀支持http和https
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost", //请求服务地址,应该是可以是IP及域名
          "Port": 8081 //端⼝口号
        }
      ],
      "DownstreamPathTemplate": "/", //下游请求地址模板
      // 以下节点可选
      "RouteClaimsRequirement": { //标记该路路由是否需要认证
        "UserType": "registered" //示例例,K/V形式,授权声明,授权token中
        会包含⼀一些claim,如填写则会判断是否和token中的⼀一致,不不⼀一致则不不准访问
      },
      //以下三个是将access claims转为⽤用户的Header Claims,QueryString,该
      功能只有认证后可⽤用
      "AddHeadersToRequest": { //
        "UserType": "Claims[sub] > value[0] > |", //示例例
        "UserId": "Claims[sub] > value[1] > |" //示例例
      },
      "AddClaimsToRequest": {},
      "AddQueriesToRequest": {},
      "RequestIdKey": "", //设置客户端的请求标识key,此key在请求header中
      ,会转发到下游请求中
      "FileCacheOptions": { //缓存设置
        "TtlSeconds": 15, //ttl秒被设置为15,这意味着缓存将在15秒后过期
        。
        "Region": "" //缓存region,可以使⽤用administrator API清除
      },
      "ReRouteIsCaseSensitive": false, //路路由是否匹配⼤大⼩小写
      "ServiceName": "", //服务名称,服务发现时必填
      "QoSOptions": { //断路路器器配置,⽬目前Ocelot使⽤用的Polly
        "ExceptionsAllowedBeforeBreaking": 0, //打开断路路器器之前允许的例例
        外数量量。
        "DurationOfBreak": 0, //断路路器器复位之前,打开的时间(毫秒)
        "TimeoutValue": 0 //请求超时时间(毫秒)
      },
      "LoadBalancer": "", //负载均衡 RoundRobin(轮询)/LeastConnection(
      最少连接数)
      "RateLimitOptions": { //官⽅方⽂文档未说明
        "ClientWhitelist": [], // 客户端⽩白明代 ?
        "EnableRateLimiting": false, // 是否限流 ?
        "Period": "",
        "PeriodTimespan": 0,
        "Limit": 0
      },
      "AuthenticationOptions": { //认证配置
        "AuthenticationProviderKey": "", //这个key对应的是代码中.AddJW
        TBreark中的Key
        "AllowedScopes": [] //使⽤用范围
      },
      "HttpHandlerOptions": {
        "AllowAutoRedirect": true, //指示请求是否应该遵循重定向响应。
        如果请求应该⾃自动遵循来⾃自Downstream资源的重定向响应,则将其设置为true; 否则为假。
        默认值是true。
        "UseCookieContainer": true //该值指示处理理程序是否使⽤用CookieCon
        tainer属性来存储服务器器Cookie,并在发送请求时使⽤用这些Cookie。 默认值是true。
      },
      "UseServiceDiscovery": false //使⽤用服务发现,⽬目前Ocelot只⽀支持Consu
      l的服务发现
    }
  ],
  "GlobalConfiguration": {}
}

其中,我们需要了解一下微服务的上游服务器和下游服务器,以下是我个人的总结,下游服务器是提供Api接口,那么上游提供访问的规则,下游服务器配置就是我们刚才创建的json里面的,我们指定Host,port,以及PathTemplate。

通过配置文件,我们可以可以知道Ocelot是通过我们的json配置规则映射成了它自己可以识别的对象,转发给了后台的httpservice,从后端返回结果。

通过配置文件可以完成对 Ocelot 的功能配置: 路由、服务聚合、服务发现、认证、鉴权、限流、熔断、缓存、 Header 头传递 等。我们上面的配置说明都已经写好了,比较重要的就是如下,下面你可以多留意。

  • DownstreamPathTemplate:下游戏
  • DownstreamScheme:下游服务http schema
  • DownstreamHostAndPorts:下游服务的地址,如果使用LoadBalancer的话这里可以填多项
  • UpstreamPathTemplate: 上游也就是用户输入的请求Url模板
  • UpstreamHttpMethod: 上游请求http方法,可使用数组

修改启动文件

public class Program
    {
        public static void Main(string[] args)
        {

            IWebHostBuilder builder = new WebHostBuilder();

            builder.ConfigureServices(s => {
                s.AddSingleton(builder);
            });

            builder.UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .ConfigureAppConfiguration((hostingContext, cfg) => {
                    cfg.AddJsonFile("ocelot.json", false, true);
                })
                .UseStartup<Startup>();

            var host = builder.Build();

            host.Run();
        }
    }

这里需要引用一下包:

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

加载中间件

// This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddOcelot(Configuration);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc();
            app.UseOcelot().Wait();
        }

修改项目加载配置文件(launchsettings.json)

{
  "profiles": {
    "WebApplication1": {
      "commandName": "Project",
      "launchBrowser": false,
      "launchUrl": "api/values",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:5000/"
    }
  }
}

设置启动多个项目

因为我们需要启动服务,还有网关,我们就需要设置启动多个项目了。右击项目属性。

 

讲解

当然我们,还是要回顾以下服务器集群的服务发现是如何进行的。

这是一个很基本的json,如下图,节点与项目之间的关系。

{
  "services": [
    {
      "ID": "OcelotConsul1_service",
      "name": "T169.OcelotConsul.Service",
      "tags": [
        "urlprefix-/T169.Studeent.Service"
      ],
      "address": "localhost",
      "port": 8081,
      "checks": [
        {
          "name": "Student Service check",
          "http": "http://localhost:8081/api/health",
          "interval": "10s",
          "timeout": "5s"
        }
      ]
    },{
      "ID": "OcelotConsul2_service",
      "name": "T169.OcelotConsul.Service",
      "tags": [
        "urlprefix-/T169.Studeent.Service"
      ],
      "address": "localhost",
      "port": 8080,
      "checks": [
        {
          "name": "Student Service check",
          "http": "http://localhost:8080/api/health",
          "interval": "10s",
          "timeout": "5s"
        }
      ]
    }
  ]
}

大家都知道我们在我们的服务中写好了启动端口和和ip地址,如以下定义。

{
  "profiles": {
    "ConsulGoForProject": {
      "commandName": "Project",
      "applicationUrl": "http://localhost:8081",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

那么我们的配置文件就是通过address和port进行寻找的,寻找到之后,如果启动集群,那么就会将这些节点转换成对象,通过httpclient向集群进行映射,达到了一个这么一个功能,其中的ID应该是一个唯一的。那么name可以是相同的,可以让网关进行一个发现,那么网关是根据什么进行分发的呢?

那么我们的网关是如何找到我们的服务的呢?

 

其中的DownstreamPathTemplate是向下的模板路径,DownstreamScheme是访问的方式,有http和https,ServiceName是服务发现的路径,在此其中,你的配置文件中,如果和这个名字相同,那么就会根据对应的address和port  去访问DownStreamPathTemplate,那么UpstreamPathTemplate是你要写的别名,也就是说我们的台服务器无法达到匹配的时候,我们可以使用这个属性(类似我们访问www.baidu.com 第一次访问和这个ServiceName相同的服务,第二次找第二个,当然这和Type:”RoundRobin” 这个属性有极大的关联,这个就叫做轮询,这个属性是Ocelot的精髓)。我们分别通过网关地址和服务的真实地址来访问服务,看一看效果如何。

再此其中,我们使用开发模式进行启动服务器集群。

consul agent -dev -config-dir=/tmp/consul/config

我们逐一将其中的api/values的控制器返回值改以下,这里就不贴代码了,我们启动项目,看一个细节。如下是刚启动项目,还没有启动集群的时候是这个样子的,这是大家都经常看到的。

我们开始部署集群,回车!,发现诸多的代码在执行,如下图所示,这是我们通过consul的命令去扫描了tmp/consul/config/ 这里面的json,当然它只认识json,读取其中的节点,通过Consul的自动代理HttpClient注册我们的服务,那么这就是一个通俗易懂的解释了。

 

我们看一下网关的效果如何,我们发现这是非常榜的,这也就是轮询机制,通过网关代理给我们带来了极大的好处。

 

那么大家都知道WebApi限流机制,限流这个名词我就不再解释了,对请求进行限流可以防止下游服务器因为访问过载而崩溃,这个功能就是我们的张善友张队进添加进去的。非常优雅的实现,我们只需要在路由下加一些简单的配置即可以完成。

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

总结

 希望大家看完这篇可以有所收获吧,Ocelot开源地址:https://github.com/TomPallister/Ocelot,如果有问题的话在下方留言。谢谢。!

作者:张子浩