.NET Core + Ocelot:API 網(wǎng)關(guān)

關(guān)于 API 網(wǎng)關(guān)的作用,核心是 API 請求的收口及控制,如:鑒權(quán)、限流、熔斷、數(shù)據(jù)緩存 等都是開發(fā)中常見的需求,將此類需求交給網(wǎng)關(guān)層處理,可以使每個(gè)微服務(wù)更聚焦于業(yè)務(wù)功能開發(fā),同時(shí)也可為下游服務(wù)的安全及穩(wěn)定性保駕護(hù)航。

在之前的文章 .NET Core + Spring Cloud:API 網(wǎng)關(guān) 有介紹過如何基于 Spring Cloud 中的 Zuul 實(shí)現(xiàn) API 網(wǎng)關(guān),功能實(shí)現(xiàn)上拋開不提,另外一個(gè)較大的特點(diǎn)是 .NET Core 可以完美的擁抱 Java 體系中的部分能力。本文將主要介紹 .NET Core 體系中的 API 網(wǎng)關(guān)框架:Ocelot,它包含了 路由、鑒權(quán)、限流、熔斷、服務(wù)發(fā)現(xiàn)、請求聚合等非常豐富的功能,這些功能大多基于少量的配置實(shí)現(xiàn),使用起來也并不復(fù)雜。

接下來通過簡單例子先跑起來,然后再繼續(xù)延伸更多特性的介紹,下面是 Ocelot 官方給出的一個(gè)最基礎(chǔ)的架構(gòu)圖:

外網(wǎng)訪問 Ocelot API 網(wǎng)關(guān)服務(wù)(單實(shí)例),通過配置的規(guī)則(configuration.json),路由到下游的兩個(gè)微服務(wù)實(shí)例(Http Service),這也就是最基本的轉(zhuǎn)發(fā)能力。

路由轉(zhuǎn)發(fā)

以下創(chuàng)建的 .NET Core API 服務(wù)均基于 .NET Core 3.1

  1. 創(chuàng)建微服務(wù)(ServiceA),并啟動2個(gè)實(shí)例,兩個(gè)實(shí)例使用的配置文件設(shè)置不同的 Id,方便后面接口調(diào)用識別不同實(shí)例。

    [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. 創(chuàng)建網(wǎng)關(guān)服務(wù)

    • 安裝 Ocelot NuGet 包;
    • 創(chuàng)建配置文件 configuration.json,內(nèi)容如下:
      {
        "Routes": [   // 路由規(guī)則定義,數(shù)組
          {
            "DownstreamPathTemplate": "/{url}",   // 下游路徑匹配模板
            "DownstreamScheme": "http", 
            "DownstreamHostAndPorts": [           // 下游服務(wù)的 host 和 port 設(shè)置,支持多實(shí)例
              {
                "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": {                    // 多實(shí)例下負(fù)載均衡方式,支持: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 中注冊服務(wù)與管道配置
      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. 網(wǎng)關(guān)層接口調(diào)用測試
    通過以上服務(wù)搭建,就完成了路由轉(zhuǎn)發(fā)的功能,即當(dāng)訪問 /servicea/{任意路由地址} 都將自動轉(zhuǎn)發(fā)到下游任意一個(gè)服務(wù)實(shí)例中相匹配的路由地址,網(wǎng)關(guān)服務(wù)訪問地址為:http://192.168.124.11:9600192.168.124.11 是本機(jī)的 IPV4 地址),測試效果如下(下游服務(wù)實(shí)例被輪詢訪問):

服務(wù)發(fā)現(xiàn)(Consul)

Ocelot 支持與具備 服務(wù)發(fā)現(xiàn) 功能的一些框架相結(jié)合,如:Consul、Eureka,下游服務(wù)地址可直接從服務(wù)注冊中心進(jìn)行獲取。接下來將結(jié)合 Consul 進(jìn)行測試,有關(guān) Consul 與 .NET Core 結(jié)合請參考文章:.NET Core + Consul 服務(wù)注冊與發(fā)現(xiàn),這部分內(nèi)容這里就不重復(fù)介紹了,最終注冊中心 service-a 有兩個(gè)實(shí)例,如下:

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

  2. Startup.cs 中進(jìn)行服務(wù)注冊:

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

    {
      "GlobalConfiguration": {
        "ServiceDiscoveryProvider": {  // 提供服務(wù)發(fā)現(xiàn)的 Provider
          "Scheme": "http",
          "Host": "192.168.124.9",     // Consul 服務(wù) host
          "Port": 8500,                // Consul 服務(wù)端口
          "Type": "Consul"             // 類型
        }
      },
      "Routes": [
        {
          "DownstreamPathTemplate": "/{url}",
          "DownstreamScheme": "http",
          "ServiceName": "service-a",  // 注冊的服務(wù)名
          "UpstreamPathTemplate": "/servicea/{url}",
          "UpstreamHttpMethod": [ "Get" ],
          "LoadBalancerOptions": {
            "Type": "RoundRobin"
          }
        }
      ]
    }
    

最終測試結(jié)果與上一部分一致,所以 Ocelot 完全可以與服務(wù)注冊發(fā)現(xiàn)相結(jié)合應(yīng)用到項(xiàng)目中。

限流

為了可以防止因請求過載而引起服務(wù)不穩(wěn)定,可為路由規(guī)則添加相應(yīng)的限流配置,如下:

"RateLimitOptions": {
  "ClientWhitelist": [ "clientId1" ],
  "EnableRateLimiting": true, 
  "Period": "5s", 
  "PeriodTimespan": 5,
  "Limit": 5  // 測試設(shè)置比較小
}

ClientWhitelist:限流白名單。如上,當(dāng)請求頭中包含 ClientId=clientId1 的請求則不受限流規(guī)則控制(ClientId key 名可修改
EnableRateLimiting:開啟限流
Period:限流控制時(shí)間段,也就是多長時(shí)間內(nèi)。支持 s(秒)、m(分)、h(小時(shí))、d(天)
PeriodTimespan:超過限制次數(shù)后,需要等待的時(shí)長(秒)
Limit:在 Period 時(shí)長內(nèi)最大訪問次數(shù)

當(dāng)超出限流數(shù)量時(shí),默認(rèn)返回如下:

如果需要修改返回值及狀態(tài)碼等可以通過修改 GlobalConfiguration 配置中的 RateLimitOptions 參數(shù)。

熔斷

熔斷是結(jié)合 Polly 實(shí)現(xiàn)的,在使用之前需要先安裝 Ocelot.Provider.Polly NuGet 包,然后添加服務(wù)注冊,如下:

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

路由規(guī)則中增加如下配置:

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

ExceptionsAllowedBeforeBreaking:允許連續(xù)發(fā)生異常次數(shù)
DurationOfBreak:熔斷時(shí)長(ms)
TimeoutValue:請求超時(shí)時(shí)間(ms)

當(dāng)超出允許異常次數(shù)時(shí),接口 5s 內(nèi)都會返回 503:

網(wǎng)關(guān)高可用

API 網(wǎng)關(guān)是所有請求的唯一入口,壓力自然是比較大的,自身的高可用也很關(guān)鍵,所以網(wǎng)關(guān)服務(wù)在部署上必須多實(shí)例,網(wǎng)關(guān)上層還需要添加一層 LB,官方架構(gòu)圖如下:

Ocelot 整體主要圍繞配置進(jìn)行功能擴(kuò)充,本文只介紹了部分 Ocelot 的功能,另外還有 鑒權(quán)、緩存、請求合并、與 Kubernetes 結(jié)合等都是非常普遍的功能。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容