Ocelot是一個用.NET Core實現的開源API網關,它功能強大,包括了:路由、請求聚合、服務發現、認證、鑒權、限流熔斷,緩存等。
接下來,會使用ocelot 結合consul ,polly ,cachemanager 實現負載均衡,服務發現,限流熔斷和緩存功能。(本文只做記錄,就直接貼完整代碼,不分別測試了)
新建ApiGateWay項目,nuget安裝Ocelot,Ocelot.Provider.Consul,Ocelot.Provider.Polly,Ocelot.Cache.CacheManager
注:我這里用的ocelot版本是14.1.0 ,高版本請參考官方文檔調整哈
新增ocelot.json,配置相關參數
{ // 轉發路由,數組中的每個元素都是某個服務的一組路由轉發規則 "ReRoutes": [ { "ServiceName": "Summer.Webapi", //對應consul配置的ServiceName // Uri方案,http、https "DownstreamScheme": "http", // 下游(服務提供方)服務路由模板 "DownstreamPathTemplate": "/api/{path}", // 上游(客戶端,服務消費方)請求路由模板 "UpstreamPathTemplate": "/Summer/{path}", "UpstreamHttpMethod": [ "Get", "Post" ], "LoadBalancerOptions": { "Type": "RoundRobin" //輪詢 }, "UseServiceDiscovery": true, "RateLimitOptions": { "ClientWhitelist": [ "admin" ], // 白名單 "EnableRateLimiting": true, // 是否啟用限流 "Period": "1m", // 統計時間段:1s, 5m, 1h, 1d "PeriodTimespan": 15, // 多少秒之后客戶端可以重試 "Limit": 2 // 在統計時間段內允許的最大請求數量 }, "QoSOptions": { "ExceptionsAllowedBeforeBreaking": 2, // 允許多少個異常請求 "DurationOfBreak": 15000, // 熔斷的時間,單位為毫秒 "TimeoutValue": 5000 // 如果下游請求的處理時間超過多少則視如該請求超時 }, "FileCacheOptions": { // cache response data - ttl: 10s 10秒內相同url請求直接返回緩存數據 "TtlSeconds": 10, "Region": "" } } ], // 全局配置,此節點的配置會覆蓋ReRoutes,可以在這里設置一些通用的配置 "GlobalConfiguration": { "ReRouteIsCaseSensitive": false, "ServiceDiscoveryProvider": { "Host": "localhost", "Port": 8500, "Type": "Consul" //由Consul提供服務發現 }, "RateLimitOptions": { "DisableRateLimitHeaders": false, // Http頭 X-Rate-Limit 和 Retry-After 是否禁用 "QuotaExceededMessage": "Too many requests, are you OK?", // 當請求過載被截斷時返回的消息 "HttpStatusCode": 999, // 當請求過載被截斷時返回的http status "ClientIdHeader": "client_id" // 用來識別客戶端的請求頭,默認是 ClientId } } }
在Startup.cs 中新增如下代碼:
public void ConfigureServices(IServiceCollection services) { var config = new ConfigurationBuilder().AddJsonFile("ocelot.json").Build(); services.AddOcelot(config) .AddCacheManager(x => { x.WithDictionaryHandle(); }) .AddConsul().AddPolly(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseOcelot().Wait(); }
配置完ApiGateway,接下來配置Webapi,每個Webapi都新增服務注冊,通過consul服務發現並定時做健康檢測
新增consul服務注冊擴展類庫 ConsulBuilder,方便各個項目引用,接下來直接貼代碼:
// consul服務注冊擴展類 public static class ConsulRegistrationExtensions { public static void AddConsul(this IServiceCollection service) { // 讀取服務配置文件 var config = new ConfigurationBuilder().AddJsonFile("consulconfig.json").Build(); service.Configure<ConsulServiceOptions>(config); } public static IApplicationBuilder UseConsul(this IApplicationBuilder app) { // 獲取主機生命周期管理接口 var lifetime = app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>(); // 獲取服務配置項 var serviceOptions = app.ApplicationServices.GetRequiredService<IOptions<ConsulServiceOptions>>().Value; // 服務ID必須保證唯一 serviceOptions.ServiceId = Guid.NewGuid().ToString(); var consulClient = new ConsulClient(configuration => { //服務注冊的地址,集群中任意一個地址 configuration.Address = new Uri(serviceOptions.ConsulAddress); }); // 獲取當前服務地址和端口,配置方式 var uri = new Uri(serviceOptions.ServiceAddress); // 節點服務注冊對象 var registration = new AgentServiceRegistration() { ID = serviceOptions.ServiceId, Name = serviceOptions.ServiceName,// 服務名 Address = uri.Host, Port = uri.Port, // 服務端口 Check = new AgentServiceCheck { // 注冊超時 Timeout = TimeSpan.FromSeconds(5), // 服務停止多久后注銷服務 DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5), // 健康檢查地址 HTTP = $"{uri.Scheme}://{uri.Host}:{uri.Port}{serviceOptions.HealthCheck}", // 健康檢查時間間隔 Interval = TimeSpan.FromSeconds(10), } }; // 注冊服務 consulClient.Agent.ServiceRegister(registration).Wait(); // 應用程序終止時,注銷服務 lifetime.ApplicationStopping.Register(() => { consulClient.Agent.ServiceDeregister(serviceOptions.ServiceId).Wait(); }); return app; } }
// Consul配置模型類 public class ConsulServiceOptions { // 服務注冊地址(Consul的地址) public string ConsulAddress { get; set; } // 服務ID public string ServiceId { get; set; } // 服務名稱 public string ServiceName { get; set; } // 健康檢查地址 public string HealthCheck { get; set; } //站點地址 public string ServiceAddress { get; set; } }
在Webapi 項目中引用ConsulBuilder類庫,然后在Startup.cs 中新增如下代碼:
新增consulconfig.json ,屬性設置為始終復制
{ "ConsulAddress": "http://127.0.0.1:8500", //consul 服務器地址 "ServiceName": "Summer.Webapi", //服務名稱,ApiGateway中配置的ServiceName對應這里 "HealthCheck": "/Health", //健康檢查地址 "ServiceAddress": "http://localhost:58420" //webapi 地址 }
假如要啟動多個webapi,拷貝代碼,將ServiceAddress 改為不同的端口,然后使用命令行啟動
PS D:\work\demo\core\SummerCore3.1\Summer.WebApi\bin\Debug\netcoreapp3.1> dotnet .\Summer.Webapi.dll --urls "http://loca
lhost:58420"
配置好后,開始運行,
先開啟consul: consul.exe agent -dev
然后啟動多個webapi
訪問localhost:8500 ,可以看到已經服務發現兩個webapi
測試一下是否正常運行,訪問http://localhost:58420/api/user/userlist
運行ApiGateway
PS D:\work\demo\core\SummerCore3.1\Summer.ApiGateway\bin\Debug\netcoreapp3.1> dotnet .\Summer.ApiGateway.dll --urls "htt
p://localhost:7000"
訪問http://localhost:7000/Summer/user/userlist
可以看到,API網關已經正常映射到localhost:58420的Webapi
其他效果,例如負載均衡,限流熔斷可以自行結合配置參數做測試
本文代碼主要參考zilor老師公開課源碼