Ocelot基於Consul服務發現
Ocelot基於Consul服務發現
前言
上章節介紹了將WebAPI介面服務註冊到Consul中,這節介紹.NET Core平臺下Ocelot基於Consul的服務發現。
環境:Win10+VS2022 +.NET5.0 + Ocelot17.0.0.0 + Consul 1.6.1.1
1 服務發現
Ocelot 允許您指定服務發現提供程式,並將使用它來查詢 Ocelot 將請求轉發到的下游服務的主機和埠。目前這僅在 GlobalConfiguration 部分中受支援,這意味著相同的服務發現提供程式將用於您在路由級別指定 ServiceName 的所有路由。
2 Consul
需要做的第一件事是在
Install-Package Ocelot.Provider.Consul |
然後將以下內容新增到您的 ConfigureServices 方法中。
s.AddOcelot() .AddConsul(); |
GlobalConfiguration 中需要以下內容。Provider 是必需的,如果您不指定主機和埠,則將使用 Consul 預設值。
請注意 Scheme 選項預設為 HTTP。它被新增到這個PR中。它預設為 HTTP 以不引入重大更改。
"ServiceDiscoveryProvider": { "Scheme": "https", "Host": "localhost", "Port": 8500, "Type": "Consul" } |
將來我們可以新增一個允許特定路由配置的功能。
為了告訴 Ocelot Route 是為其主機和埠使用服務發現提供程式,您必須新增您希望在向下遊發出請求時使用的 ServiceName 和負載均衡器。目前,Ocelot 有一個可以使用的 RoundRobin 和 LeastConnection 演算法。如果沒有指定負載均衡器,Ocelot 將不會對請求進行負載均衡。
{ "DownstreamPathTemplate": "/api/posts/{postId}", "DownstreamScheme": "https", "UpstreamPathTemplate": "/posts/{postId}", "UpstreamHttpMethod": [ "Put" ], "ServiceName": "product", "LoadBalancerOptions": { "Type": "LeastConnection" }, } |
設定完成後,Ocelot 將從服務發現提供者那裡查詢下游主機和埠,並在任何可用服務之間實現負載平衡請求。
很多人要求我實現一個功能,即 Ocelot 輪詢 Consul 以獲取最新的服務資訊,而不是每個請求。如果您想輪詢 Consul 以獲取最新服務而不是每個請求(預設行為),那麼您需要設定以下配置。
"ServiceDiscoveryProvider": { "Host": "localhost", "Port": 8500, "Type": "PollConsul", "PollingInterval": 100 } |
輪詢間隔以毫秒為單位,告訴 Ocelot 多久呼叫一次 Consul 以更改服務配置。
請注意這裡有權衡。如果您輪詢 Consul,Ocelot 可能不會根據您的輪詢間隔知道服務是否已關閉,並且您可能會遇到比您獲得每個請求的最新服務更多的錯誤。這實際上取決於您的服務有多不穩定。我懷疑這對大多數人來說很重要,輪詢可能會比每個請求呼叫 Consul(作為 Sidecar 代理)帶來微小的效能改進。如果您正在呼叫遠端 Consul 代理,那麼輪詢將是一個很好的效能改進。
您的服務需要新增到 Consul 中,如下所示(C# 風格,但希望這是有意義的)……唯一需要注意的是不要在地址欄位中新增 http 或 https。
"Service": { "ID": "some-id", "Service": "some-service-name", "Address": "localhost", "Port": 8080 } |
3 ACL 令牌
如果您將 ACL 與 Consul Ocelot 一起使用,則支援新增 X-Consul-Token 標頭。為了使它起作用,您必須在下面新增附加屬性。
"ServiceDiscoveryProvider": { "Host": "localhost", "Port": 8500, "Token": "footoken", "Type": "Consul" } |
Ocelot 會將此令牌新增到它用來發出請求的 Consul 客戶端,然後用於每個請求。
4 專案實現
4.1 新建Ocelot閘道器專案
在上節的專案中再新建一個Ocelot閘道器專案,命名為“Yak.Ocelot.Gateway”,修改啟動埠為“5000”。
"Yak.Ocelot.Gateway": { "commandName": "Project", "dotnetRunMessages": "true", "launchBrowser": true, "applicationUrl": "http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } |
4.2 新增Ocelot和Ocelot的Consul依賴
新增依賴後,Yak.Ocelot.Gateway專案檔案下添加了下面程式碼。
<ItemGroup> <PackageReference Include="Ocelot" Version="17.0.0" /> <PackageReference Include="Ocelot.Provider.Consul" Version="17.0.0" /> </ItemGroup> |
4.3 把服務註冊到Consul
- 專案中新增Consul 註冊發現相關引數類ConsulOption。
/// <summary> /// Consul 註冊發現相關引數 /// </summary> public class ConsulOption { /// <summary> /// 服務名稱 /// </summary> public string ServiceName { get; set; }
/// <summary> /// 服務IP /// </summary> public string ServiceIP { get; set; }
/// <summary> /// 服務埠 /// </summary> public int ServicePort { get; set; }
/// <summary> /// 服務健康檢查地址 /// </summary> public string ServiceHealthCheck { get; set; }
/// <summary> /// Consul 地址 /// </summary> public string Address { get; set; } } |
- 新增Consul註冊發現擴充套件類ConsulBuilderExtensions。
public static class ConsulBuilderExtensions { public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IHostApplicationLifetime lifetime, ConsulOption consulOption) { var consulClient = new ConsulClient(x => { x.Address = new Uri(consulOption.Address); });
var registration = new AgentServiceRegistration() { ID = Guid.NewGuid().ToString(), Name = consulOption.ServiceName,// 服務名 Address = consulOption.ServiceIP, // 服務繫結IP Port = consulOption.ServicePort, // 服務繫結埠 Check = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服務啟動多久後註冊 Interval = TimeSpan.FromSeconds(10),//健康檢查時間間隔 HTTP = consulOption.ServiceHealthCheck,//健康檢查地址 Timeout = TimeSpan.FromSeconds(5) } };
// 服務註冊 consulClient.Agent.ServiceRegister(registration).Wait();
// 應用程式終止時,服務取消註冊 lifetime.ApplicationStopping.Register(() => { consulClient.Agent.ServiceDeregister(registration.ID).Wait(); }); return app; } } |
- 新增ocelot配置檔案,ocelot.json檔案。
{ "Routes": [ { "DownstreamPathTemplate": "/WeatherForecast", "DownstreamScheme": "http", "ServiceName": "service-a", "UseServiceDiscovery": true, "UpstreamPathTemplate": "/Weather", "UpstreamHttpMethod": [ "Get" ], "LoadBalancerOptions": { "Type": "RoundRobin" } } ], "GlobalConfiguration": { "BaseUrl": "http://localhost:5000" } } |
- 修改Startup。
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services .AddOcelot() .AddConsul(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime lifetime, ConsulOption consulOption) { ......... app.UseEndpoints(endpoints => { endpoints.MapGet("/", async context => { await context.Response.WriteAsync("我是Ocelot閘道器!"); }); }); // 註冊 app.UseOcelot().Wait(); ........... } |
4.4 啟動Consul
這裡是Win10系統,下載相應的Consul後,在資料夾下建立啟動BAT檔案用於啟動Consul,雙擊啟動。
4.5 服務發現
啟動“Yak.Ocelot.Api”專案,檢視到服務已經註冊到Consul中。
4.6 除錯
執行閘道器專案“Yak.Ocelot.Gateway”,通過訪問閘道器地址:http://localhost:5000/Weather訪問WebAPI天氣介面服務。
5 總結
通過Consul服務發現功能,先將介面服務註冊到Consul中,然後結合Ocelot,在不需要配置下游介面服務地址和埠情況下,直接就可以訪問介面服務了,省去了配置介面服務的麻煩。
6 鳴謝
https://ocelot.readthedocs.io/en/latest/features/servicediscovery.html
7 原始碼
https://github.com/yandaniugithub/NETCore/tree/main/Yak.Ocelot.Demo