通过配置文件,我们可以设定路由规则模板,Ocelot网关会将接收到的符合规则的请求转发到下游服务,再从后端http service获取响应(Response)后,再返回给客户端。这样子外部应用就不需要记住每个service所在的IP和端口,而是只需要告诉网关需要消费哪个service即可。

但是对于众多的微服务,如果我们都一一硬编码地配置其IP和Port在配置文件中,不适合微服务架构的风格,因为众多的服务地址变化会让静态配置的工作变得越来越大,而且容易出错。

Ocelot作为网关,支持的功能中包括服务发现,可以和多种服务注册中心结合,在请求转发的时候自动获取下游服务的IP和端口,减少配置的工作。其中对于Eureka和Consul,Ocelot官方已经给出了解决方案。

集成Consul

Ocelot集成Consul注册中心,需要对网关应用做一些改造。

  1. 安装Ocelot.Provider.Consul依赖包

    Install-package Ocelot.Provider.Consul
    
  2. 设置依赖注入

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddOcelot(Configuration)
            .AddConsul();
        services.AddControllers();
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "OcelotGateWay", Version = "v1" });
        });
    }
    
  3. 修改配置信息
    (1) 在之前的配置信息的基础上添加GlobalConfiguration,配置Consul相关信息

    "GlobalConfiguration": {
    "ServiceDiscoveryProvider": {
      "Scheme": "http",
      "Host": "127.0.0.1",
      "Port": 8500,
      "Type": "Consul"
    }
    

    (2)修改原有的Route配置信息,去除下游服务的具体ip和端口配置,改为服务名称

    "Routes": [
        {
          "UpstreamPathTemplate": "/Customer/{url}",
          "UpstreamHttpMethod": [ "Get", "Post" ],
          "DownstreamPathTemplate": "/{url}",
          "DownstreamScheme": "http",
          "UseServiceDiscovery": true,
          "ServiceName": "customerService"
        }
      ]
    
  4. 启动CustomerService
    可以在Consul管理页面中看到注册上来的服务
    在这里插入图片描述

  5. 启动网关,通过postman进行测试
    在这里插入图片描述

集成nacos

Ocelot官方没有提供集成nacos注册中心的支持,但是github中有一个开源库完成了Ocelot集成nacos的扩展,我们也不必重复造轮子。

扩展库github地址: https://github.com/softlgl/Ocelot.Provider.Nacos

  1. 安装依赖包
    由于Ocelot.Provider.Nacos对nacos1.x和2.x的支持是通过nuget包的不同版本区分的,使用时请注意Ocelot.Provider.Nacos的版本,这里我使用nacos 2.x版本,所以安装1.2.2版本的包

    Install-package Ocelot.Provider.Nacos -v 1.2.2
    
  2. 设置依赖注入

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddNacosAspNet(Configuration, "nacos");
        services.AddControllers();
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "CustomerService", Version = "v1" });
        });
    }
    
  3. 修改配置文件
    GlobalConfiguration节点中ServiceDiscoveryProvider改为nacos

    // Ocelot结合nacos注册中心
      "GlobalConfiguration": {
        "ServiceDiscoveryProvider": {
          "Type": "Nacos"
        }
      }
    

    添加nacos服务注册配置,这里和正常的nacos服务注册配置一致,实际上也是将网关作为一个服务注册到nacos中

    "nacos": {
        "ServerAddresses": [ "http://127.0.0.1:8848" ],
        "DefaultTimeOut": 15000,
        "Namespace": "yyl", // Please set the value of Namespace ID !!!!!!!!
        "ListenInterval": 1000,
        "ServiceName": "gateway",
        "GroupName": "DEFAULT_GROUP",
        "ClusterName": "DEFAULT",
        "Port": 0,
        "Weight": 100,
        "RegisterEnabled": true,
        "InstanceEnabled": true,
        "Ephemeral": true,
        "Secure": false,
        "UserName": "nacos",
        "Password": "nacos",
        "ConfigUseRpc": false, 
        "NamingUseRpc": false, 
        "NamingLoadCacheAtStart": "",
        "LBStrategy": "WeightRandom" 
      }
    
  4. 启动Customer服务和网关
    可以看到Customer服务和网关都注册到nacos中
    在这里插入图片描述

  5. 通过postman调用网关进行测试
    在这里插入图片描述

动态路由

就算将Ocelot和服务注册中心结合了,可以通过服务发现自动获取下游服务的ip和端口,减少了在启动相同服务的多个实例动时的配置工作量,但是在新增或减少一个服务时还是需要修改配置文件,在routes节点中增加或减少一个配置。

当服务拆分得非常多时,将服务一一地配置到配置文件,将会是一个巨大的工程,虽然都是copy,但是会增加出错的机会,并且很难排查。

而Ocelot提供了Dynamic Routing功能,这个功能是在issue 340后增加的(见下图官方文档),目的是在使用服务发现之后,直接通过服务发现去定位从而减少配置文件中的Routes配置项。

只要请求的url地址符合既定的规则,Ocelot网关就会通过服务发现查找到对于服务的IP和地址,而Routes节点可以不做任何配置。
例如以下url:http://localhost:5001/customerService/WeatherForecast
Ocelot会将url地址中域名或者ip+端口后的第一个参数,也就是customerService作为ServiceName调用服务发现API得到IP和Port,然后加上后续的请求URL部分(/WeatherForecast)进行最终URL的访问:http://ip:port/WeatherForecast。

"Routes": [],
"GlobalConfiguration": {
   "RequestIdKey": null,
   "ServiceDiscoveryProvider": {
     "Scheme": "http",
     "Host": "127.0.0.1",
     "Port": 8500,
     "Type": "Consul"
   }
 }

postman调用测试如下:
在这里插入图片描述

扩展Ocelot对注册中心的适配

查看核心Ocelot.Provider.Consul的源码,可以看到Ocelot对于不同的注册中心的适配,其实就是通过一个ServiceDiscoveryFinderDelegate委托实现的,我们只要根据不同的注册中心编写ServiceDiscoveryFinderDelegate不同的实现即可

在这里插入图片描述
像适配nacos,只要提供自己的ServiceDiscoveryFinderDelegate,返回一个IServiceDiscoveryProvider实现类即可
在这里插入图片描述
在这里插入图片描述
IServiceDiscoveryProvider实现类中重点就是Get方法,在Get方法中通过ServiceName从注册中心中获取到可用的服务集合,而Ocelot的负载均衡机制会从中选出一个作为当前请求的url。

在使用Ocelot.Provider.Nacos的时候,GlobalConfiguration节点中的ServiceDiscoveryProvider时不需要配置注册中心地址的,但是为了使用动态路由,就必须加上Host和Port了,这里的Host和Port并没有其他作用,只是让Ocelot可以根据url解解析路由。
如下:

"GlobalConfiguration": {
    "ServiceDiscoveryProvider": {
      "Type": "Nacos",
      "Host": "127.0.0.1",
      "Port": 8000
    }
  }

为了集成nacos和Ocelot的动态路由功能折腾了好久,还以为动态路由功能也需要自己提供实现,查看了好久Ocelot的源码,才在DownstreamRouteFinderMiddleware中发现,查看DownstreamRouteFinderMiddleware中的IDownstreamRouteProviderFactory获取时,只有存在Host和Port的时候,才能获取到DownstreamRouteCreator,才能从url中解析出ServiceName。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

微服务系列文章:
上一篇:API网关—Ocelot
下一篇:API网关—Ocelot之负载均衡

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐