網際網路熱潮下,“微服務”技術架構成為了一種高大上的技術,其顧名思義就是將傳統的大的業務服務拆分成獨立的小服務,當拆分的服務慢慢多起來的時候,我們會發現服務地址很難管理,傳統的方式一般會通過配置檔案或者資料庫儲存,這種手動的維護的方式顯然不夠靈活,如果某個服務掛了,系統得不到及時的通知,只能等維護人員處理。這個時候如果有個中介軟體來做服務發現的話,顯然會顯得很靈活。
.Net平臺上使用“微服務”時做服務發現,目前來說Cosul是一個不錯的選擇。
什麼是Consul
Consul是一種提供了服務發現,配置管理等功能的服務網格解決方案,是一種分散式,高可用的服務管理架構。
主要功能:
服務發現(Service Discovery):Consul提供了通過DNS或者HTTP API介面的方式來發現服務。服務與服務之間通過Consul中心來統一獲取呼叫服務的地址,而不再是傳統模式下服務之間呼叫的“硬編碼”配置管理。
服務註冊(Service Register):Consul提供了兩種方式進行服務註冊。第一種通過Http API的方式在服務啟動時註冊,第二種通過json配置檔案的方式註冊。
健康檢查(Health Checking):一旦服務註冊到Consul的client節點下,consul就會根據服務註冊時配置的間隔時間,主動請求服務,以獲取服務的健康狀態,如發現不健康的服務,則將該服務從consul中登出。
Key/Value儲存:應用程式可以根據自己的需要使用Consul提供的Key/Value儲存。 Consul提供了簡單易用的HTTP介面,結合其他工具可以實現動態配置、功能標記、領袖選舉等等功能。
一張圖簡單瞭解下Consul
client節點
Client表示consul的client模式,即客戶端模式。
1)client節點負責轉發請求給server節點,本身不持久化任何資訊
2)提供服務健康檢查
3)client節點支援任意擴充套件,數量不受限制。
server 節點
Server表示consul的server模式,即服務端模式。
1)server節點接收client的轉發請求,並本地持久化這些資訊,遇到故障後方便排查。
2)consul叢集中至少有一個server,官方建議server節點的個數3個或者5個比較合適(叢集管理)。server的叢集解決了單點問題,server間需要選舉一個ledger,由server-ledger負責server叢集之間的資訊同步。
3)採用Raft一致性協議,保證server節點之間資料一致
consul節點間通訊
Consul使用GossIP協議管理成員關係、廣播訊息到整個叢集,包括兩個gossip pool(LAN pool和WAN pool),LAN pool是同一個資料中心內部通訊的,WAN pool是多個資料中心之間通訊的,LAN pool有多個,WAN pool只有一個。
通過上圖我們會發現,consul推薦是以叢集的形式部署。但是很多人剛開始接觸學習的時候並沒有那麼多機器模擬(Docker模擬我們先不討論了),server單節點模式是否可行呢?
答案當然是可行的,但弊端也顯而易見,首先肯定會有單點故障問題,其次如果註冊的服務太多,server需要不斷的向服務傳送請求,進行健康檢查,顯然大量、高頻次的請求會極大影響consul節點。
如果只有一個server節點,那麼實際上它自身即充當了client又充當了server。本文我們就以server單節點的模式,以最簡單的應用和大家學習一下如何在.netcore中使用consul。
準備環境.netcore3.1 、consul部署包
首先下載consul,官方地址:https://www.consul.io/downloads,解壓我們會發現就是一個exe程式,掌握一些常用的cmd命令即可。
本地環境consul啟動CMD命令:
首先cd到consul.exe所在目錄目錄
然後輸入consul agent -server -bootstrap-expect=1 -node=service1 -bind=127.0.0.1 -data-dir=./data -client=0.0.0.0 -ui -config-dir=./config
常用引數說明:
-server:表示consul代理模式,有兩個選擇-server和-client
-bootstrap-expect:在一個資料中心中期望提供的server節點數量,只有等到指定數量的server全部啟動後,才會啟動叢集(自行選舉ledger)
-node:叢集中節點名稱,同一叢集中唯一,預設為主機名
-bind:繫結叢集內部通訊的地址,表示該節點監聽的地址,這個地址必須是叢集內部所有節點可達的。預設是0.0.0.0(將繫結機器得所有地址,同時把 ipv4地址告訴叢集得其他人)
-client:繫結客戶端的ip地址,預設127.0.0.1,可繫結多個。0.0.0.0表示誰都可以訪問。
-data-dir:用於存放Agent狀態的目錄
-ui:啟用web ui
-config-dir:配置目錄,將載入目錄中的 .hcl 或 .json 格式配置。 注意子路徑不會載入
啟動consul後,我們可以通過http://localhost:8500訪問consuld的UI頁面
HTTP方式註冊.netcore服務
新建API專案(服務A)
Nuget新增consul依賴包
新增Consul引數配置
{ "ConsulConfig": { "ServiceName": "WebApi1", "ServiceIP": "localhost", "ServicePort": 6000, "HealthCheck": "/healthcheck", "ConsulAddress": "http://localhost:8500" } }
註冊服務
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); //新增consul服務註冊 app.UseConsul(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
consul服務註冊具體實現邏輯
public static class ConsulExtensions { public static IApplicationBuilder UseConsul(this IApplicationBuilder app) { //獲取consul配置例項 var consulConfig = app.ApplicationServices.GetRequiredService<IOptions<ConsulOptions>>().Value; //獲取應用程式宣告週期事件 var lifetime = app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>(); var consulClient = new ConsulClient(c => { //consul服務註冊地址 c.Address = new Uri(consulConfig.ConsulAddress); }); //服務註冊配置 var registration = new AgentServiceRegistration() { ID = Guid.NewGuid().ToString(), Name = consulConfig.ServiceName,//服務名稱 Address = consulConfig.ServiceIP,//服務IP Port = consulConfig.ServicePort,//服務埠 Check = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服務啟動後多久註冊服務 Interval = TimeSpan.FromSeconds(10),//健康檢查時間間隔 HTTP = $"http://{consulConfig.ServiceIP}:{consulConfig.ServicePort}{consulConfig.HealthCheck}",//健康檢查地址 Timeout = TimeSpan.FromSeconds(5)//超時時間 } }; //服務註冊 consulClient.Agent.ServiceRegister(registration).Wait(); //應用程式結束時 取消註冊 lifetime.ApplicationStopping.Register(() => { consulClient.Agent.ServiceDeregister(registration.ID).Wait(); }); return app; } }
1)使用IOptions管理配置類ConsulOptions,將配置檔案(比如appsettings.json)中的配置反序列化至配置類的例項中
2)AgentServiceRegistration代理服務註冊類,例項化註冊服務配置。
健康檢查介面
[Route("[controller]")] [ApiController] public class HealthCheckController : ControllerBase { /// <summary> /// 健康檢查介面 /// </summary> /// <returns></returns> [HttpGet] public IActionResult Get() => Ok(); }
consul節點會根據配置的間隔時間進行定期請求改健康檢查介面,獲取服務健康狀態。
服務啟動
檢視consul UI頁面我們會發現我們註冊的服務WebApi1資訊已顯示
那麼如何做到服務發現呢?
通常情況下,如果服務B呼叫服務A,需要在服務B中配置並指向服務A的地址,也就是上面說的“硬編碼”的配置方式,這種模式下,如果服務A部署了多個,那麼就需要管理多個地址,並且服務B本身無法知道某個服務A掛掉就放棄請求。
而consul為我們提供了便利,現在服務B不用關心服務A具體的服務地址以及服務A是否健康。服務B直接請求consul服務地址,告訴它我要訪問服務A,consul就會啟動服務發現機制,找到所有已註冊並且健康的服務A,然後根據選擇其中的一個返回給服務B,然後服務B根據服務A具體的地址發起請求。consul幫我們管理了服務地址和服務健康檢查。
下面我們就模擬一下consul的服務發現。
服務發現
新建API專案(服務B)
Nuget新增consul依賴包
模擬服務發現
[HttpGet] [Route("/consul")] public void ReuestConsul() { //獲取Consul配置地址 var consulAddress = _configuration["ConsulAddress"]?.ToString(); using (var consulClient = new ConsulClient(x => x.Address = new Uri(consulAddress))) { //獲取根據服務註冊名稱webApi1 獲取consul註冊的服務 var services = consulClient.Catalog.Service("WebApi1").Result.Response; if (services != null && services.Any()) { //模擬隨機一臺進行請求,這裡只是測試,可以選擇合適的負載均衡框架 Random r = new Random(); int index = r.Next(services.Count()); var service = services.ElementAt(index); using (HttpClient client = new HttpClient()) { //請求服務WebApi1 var response = client.GetAsync($"http://{service.ServiceAddress}:{service.ServicePort}/api/values").Result; string result = response.Content.ReadAsStringAsync().Result; } } } }
1)ConsulClient例項化consul服務節點
2)consulClient.Catalog.Service("服務名稱").Result.Response根據服務名稱,獲取conusl註冊的所有服務地址資訊(IP、埠)。
好了,本文主要是採用server單節點的模式,和大家介紹了一下consul的特性,以及結合.netcore做了服務註冊和模擬了服務發現。
我相信,大家帶著動手測試一遍,也會有所思考和收穫。