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

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

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

1. 集成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 进行测试
    在这里插入图片描述

2. 集成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 调用网关进行测试
    在这里插入图片描述

3. 动态路由

就算将 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 调用测试如下:
在这里插入图片描述

4. 扩展 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全生命周期开发者社区

更多推荐