關於 API 網關的作用,核心是 API 請求的收口及控制,如:鑑權、限流、熔斷、數據緩存 等都是開發中常見的需求,將此類需求交給網關層處理,可以使每個微服務更聚焦於業務功能開發,同時也可爲下游服務的安全及穩定性保駕護航。
在之前的文章 .NET Core + Spring Cloud:API 網關 有介紹過如何基於 Spring Cloud 中的 Zuul 實現 API 網關,功能實現上拋開不提,另外一個較大的特點是 .NET Core 可以完美的擁抱 Java 體系中的部分能力。本文將主要介紹 .NET Core 體系中的 API 網關框架:Ocelot,它包含了 路由、鑑權、限流、熔斷、服務發現、請求聚合等非常豐富的功能,這些功能大多基於少量的配置實現,使用起來也並不複雜。
接下來通過簡單例子先跑起來,然後再繼續延伸更多特性的介紹,下面是 Ocelot 官方給出的一個最基礎的架構圖:
外網訪問 Ocelot API 網關服務(單實例),通過配置的規則(configuration.json
),路由到下游的兩個微服務實例(Http Service
),這也就是最基本的轉發能力。
路由轉發
以下創建的 .NET Core API 服務均基於 .NET Core 3.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"]}"; } }
-
創建網關服務
- 安裝
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(); }); }
- 安裝
網關層接口調用測試
通過以上服務搭建,就完成了路由轉發的功能,即當訪問/servicea/{任意路由地址}
都將自動轉發到下游任意一個服務實例中相匹配的路由地址,網關服務訪問地址爲:http://192.168.124.11:9600
(192.168.124.11
是本機的 IPV4 地址),測試效果如下(下游服務實例被輪詢訪問):
服務發現(Consul)
Ocelot 支持與具備 服務發現 功能的一些框架相結合,如:Consul
、Eureka
,下游服務地址可直接從服務註冊中心進行獲取。接下來將結合 Consul 進行測試,有關 Consul 與 .NET Core 結合請參考文章:.NET Core + Consul 服務註冊與發現,這部分內容這裏就不重複介紹了,最終註冊中心 service-a
有兩個實例,如下:
安裝
Ocelot.Provider.Consul
NuGet 包;-
Startup.cs
中進行服務註冊:services.AddOcelot().AddConsul();
-
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 時長內最大訪問次數
當超出限流數量時,默認返回如下:
如果需要修改返回值及狀態碼等可以通過修改 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:
網關高可用
API 網關是所有請求的唯一入口,壓力自然是比較大的,自身的高可用也很關鍵,所以網關服務在部署上必須多實例,網關上層還需要添加一層 LB,官方架構圖如下:
Ocelot 整體主要圍繞配置進行功能擴充,本文只介紹了部分 Ocelot 的功能,另外還有 鑑權、緩存、請求合併、與 Kubernetes 結合等都是非常普遍的功能。