25

.NET Core + Ocelot:API 网关

 3 years ago
source link: http://beckjin.com/2020/08/01/aspnet-ocelot/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

关于 API 网关的作用,核心是 API 请求的收口及控制,如:鉴权、限流、熔断、数据缓存 等都是开发中常见的需求,将此类需求交给网关层处理,可以使每个微服务更聚焦于业务功能开发,同时也可为下游服务的安全及稳定性保驾护航。

在之前的文章 .NET Core + Spring Cloud:API 网关 有介绍过如何基于 Spring Cloud 中的 Zuul 实现 API 网关,功能实现上抛开不提,另外一个较大的特点是 .NET Core 可以完美的拥抱 Java 体系中的部分能力。本文将主要介绍 .NET Core 体系中的 API 网关框架: Ocelot ,它包含了 路由、鉴权、限流、熔断、服务发现、请求聚合等非常丰富的功能,这些功能大多基于少量的配置实现,使用起来也并不复杂。

接下来通过简单例子先跑起来,然后再继续延伸更多特性的介绍,下面是 Ocelot 官方给出的一个最基础的架构图:

7nQV7nr.jpg!web

外网访问 Ocelot API 网关服务(单实例),通过配置的规则( configuration.json ),路由到下游的两个微服务实例( Http Service ),这也就是最基本的转发能力。

路由转发

以下创建的 .NET Core API 服务均基于 .NET Core 3.1

  1. 创建微服务(ServiceA),并启动2个实例,两个实例使用的配置文件设置不同的 Id,方便后面接口调用识别不同实例。

    [Route("[controller]/[action]")]
    [ApiController]
    public class TestController : ControllerBase
    {
      public readonly IConfiguration _configuration;
    
      public TestController(IConfiguration configuration)
      {
        _configuration = configuration;
      }
    
      [HttpGet]
      public string Get()
      {
        return $"service-a {_configuration["Id"]}";
      }
    }
    
  2. 创建网关服务

    • 安装 Ocelot NuGet 包;
    • 创建配置文件 configuration.json ,内容如下:

      {
        "Routes": [   // 路由规则定义,数组
          {
            "DownstreamPathTemplate": "/{url}",   // 下游路径匹配模板
            "DownstreamScheme": "http", 
            "DownstreamHostAndPorts": [           // 下游服务的 host 和 port 设置,支持多实例
              {
                "Host": "192.168.124.11",
                "Port": 8000
              },
              {
                "Host": "192.168.124.11",
                "Port": 8001
              }
            ],
            "UpstreamPathTemplate": "/servicea/{url}",  //  客户端访问地址路径匹配模板
            "UpstreamHttpMethod": [ "Get" ],            // 支持的 HttpMethod ,如:Get、Post、Put、Delete 等
            "LoadBalancerOptions": {                    // 多实例下负载均衡方式,支持:LeastConnection(最闲)、RoundRobin(轮询)、NoLoadBalance
              "Type": "RoundRobin"
            }
          }
        ]
      }
      
      • Program.cs 中添加 Ocelot 配置文件引用:
        public static IHostBuilder CreateHostBuilder(string[] args) =>
          Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
              webBuilder.UseStartup<Startup>();
              webBuilder.UseUrls("http://*:9600");
              webBuilder.ConfigureAppConfiguration(c =>
              {
                c.AddJsonFile("configuration.json");
              });
            });
        
      • Startup.cs 中注册服务与管道配置:
        public void ConfigureServices(IServiceCollection services)
        {
          services.AddControllers();
          services.AddOcelot();
        }
        
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
          // ....
          
          app.UseOcelot().Wait();
        
          app.UseRouting();
          app.UseEndpoints(endpoints =>
          {
            endpoints.MapControllers();
          });
        }
        
  3. 网关层接口调用测试

    通过以上服务搭建,就完成了路由转发的功能,即当访问 /servicea/{任意路由地址} 都将自动转发到下游任意一个服务实例中相匹配的路由地址,网关服务访问地址为: http://192.168.124.11:9600192.168.124.11 是本机的 IPV4 地址),测试效果如下(下游服务实例被轮询访问):

z2Ur2aB.png!web

服务发现(Consul)

Ocelot 支持与具备 服务发现 功能的一些框架相结合,如: ConsulEureka ,下游服务地址可直接从服务注册中心进行获取。接下来将结合 Consul 进行测试,有关 Consul 与 .NET Core 结合请参考文章: .NET Core + Consul 服务注册与发现 ,这部分内容这里就不重复介绍了,最终注册中心 service-a 有两个实例,如下:

eANfi2b.png!web

  1. 安装 Ocelot.Provider.Consul NuGet 包;

  2. Startup.cs 中进行服务注册:

    services.AddOcelot().AddConsul();
    
  3. configuration.json 配置修改为如下:

    {
      "GlobalConfiguration": {
        "ServiceDiscoveryProvider": {  // 提供服务发现的 Provider
          "Scheme": "http",
          "Host": "192.168.124.9",     // Consul 服务 host
          "Port": 8500,                // Consul 服务端口
          "Type": "Consul"             // 类型
        }
      },
      "Routes": [
        {
          "DownstreamPathTemplate": "/{url}",
          "DownstreamScheme": "http",
          "ServiceName": "service-a",  // 注册的服务名
          "UpstreamPathTemplate": "/servicea/{url}",
          "UpstreamHttpMethod": [ "Get" ],
          "LoadBalancerOptions": {
            "Type": "RoundRobin"
          }
        }
      ]
    }
    

最终测试结果与上一部分一致,所以 Ocelot 完全可以与服务注册发现相结合应用到项目中。

限流

为了可以防止因请求过载而引起服务不稳定,可为路由规则添加相应的限流配置,如下:

"RateLimitOptions": {
  "ClientWhitelist": [ "clientId1" ],
  "EnableRateLimiting": true, 
  "Period": "5s", 
  "PeriodTimespan": 5,
  "Limit": 5  // 测试设置比较小
}

ClientWhitelist:限流白名单。如上,当请求头中包含 ClientId=clientId1 的请求则不受限流规则控制( ClientId key 名可修改

EnableRateLimiting:开启限流

Period:限流控制时间段,也就是多长时间内。支持 s(秒)、m(分)、h(小时)、d(天)

PeriodTimespan:超过限制次数后,需要等待的时长(秒)

Limit:在 Period 时长内最大访问次数

当超出限流数量时,默认返回如下:

BJ7fYbq.png!web

如果需要修改返回值及状态码等可以通过修改 GlobalConfiguration 配置中的 RateLimitOptions 参数。

熔断

熔断是结合 Polly 实现的,在使用之前需要先安装 Ocelot.Provider.Polly NuGet 包,然后添加服务注册,如下:

services.AddOcelot() .AddConsul().AddPolly();

路由规则中增加如下配置:

"QoSOptions": { 
  "ExceptionsAllowedBeforeBreaking": 3,
  "DurationOfBreak": 5000,
  "TimeoutValue": 3000
}

ExceptionsAllowedBeforeBreaking:允许连续发生异常次数

DurationOfBreak:熔断时长(ms)

TimeoutValue:请求超时时间(ms)

当超出允许异常次数时,接口 5s 内都会返回 503:

BR7NBv.png!web

网关高可用

API 网关是所有请求的唯一入口,压力自然是比较大的,自身的高可用也很关键,所以网关服务在部署上必须多实例,网关上层还需要添加一层 LB,官方架构图如下:

uiqYVvQ.jpg!web

Ocelot 整体主要围绕配置进行功能扩充,本文只介绍了部分 Ocelot 的功能,另外还有 鉴权、缓存、请求合并、与 Kubernetes 结合等都是非常普遍的功能。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK