參考:
微服務注冊中心原理,看這篇就夠了! - Java碎碎念 - 博客園
備注:K8S自帶服務注冊和發現
注冊中心
注冊中心是什么
注冊中心可以說是微服務架構中的”通訊錄“,它記錄了服務和服務地址的映射關系。在分布式架構中,服務會注冊到這里,當服務需要調用其它服務時,就到這里找到服務的地址,進行調用。
功能:
- 服務注冊表:
服務注冊表是注冊中心的核心,它用來記錄各個微服務的信息,例如微服務的名稱、IP、端口等。服務注冊表提供查詢API和管理API,查詢API用於查詢可用的微服務實例,管理API用於服務的注冊與注銷。 - 服務注冊與發現:
服務注冊是指微服務在啟動時,將自己的信息注冊到注冊中心的過程。服務發現是指查詢可用的微服務列表及網絡地址的機制。 - 服務檢查:
注冊中心使用一定的機制定時檢測已注冊的服務,如發現某實例長時間無法訪問,就會從服務注冊表移除該實例
優點
- 解耦:服務消費者個服務提供者解耦,各自變化,不互相影響
- 擴展:服務消費者和服務提供者增加和刪除新的服務,對於雙方沒有任何影響
- 中介者設計模式:這是一種多對多關系的典范
zookeeper
Consul是什么
Consul是一個用來實現分布式系統的服務發現與配置的開源工具。是由go語言開發。他主要由多個組成部分:
-
服務發現:客戶端通過Consul提供服務,類似於API,MySQL,或者其他客戶端可以使用Consul發現服務的提供者。使用類似DNS或者HTTP,應用程序和可以很輕松的發現他們依賴的服務。
-
檢查健康:Consul客戶端可以提供與給定服務相關的健康檢查(Web服務器返回200 ok)或者本地節點(“內存利用率低於90%”)。這些信息可以監控集群的運行情況,並且使訪問遠離不健康的主機組件。
-
鍵值對存儲:應用程序可以使用Cousul的層級鍵值對。
-
多數據中心:Consul有開箱及用的多數據中心。
Consul 的角色
1、server 服務端
2、client 客戶端
3、agent 代理
consul agent
命令來啟動。agent 可以運行在 server 狀態或者 client 狀態。自然的,運行在 server 狀態的節點被稱為 server 節點;運行在 client 狀態的節點被稱為 client 節點。
Consul注冊中心運行流程
文字描述:server服務默認就通過agent啟動=》其他服務要注冊服務時先調用client客戶端,client客戶端再通過agent啟動
下載+啟動
Linux安裝
參考:安裝步驟
window版下載地址
啟動服務端:不需要安裝,命令啟動
下載完解壓后,不需要安裝,在解壓后的文件夾中打開CMD命令窗口
如果要查看consul命令,輸入:consul
環境變量設置:為了方便啟動,最好設置環境變量,這樣就不用每次都去指定文件夾啟動consul了,具體參考:consul環境變量設置
開發模式啟動命令(所有數據都保存在內存中):consul.exe agent -dev
生產模式啟動命令(綁定默認地址和存儲數據的路徑):consul agent -server -bind=127.0.0.1 -bootstrap-expect 1 -data-dir d:/consul/data
在瀏覽器中輸入查看地址(端口默認是8500,如果變更,在啟動后命令窗口處能看到):http://localhost:8500
客戶端啟動
使用.NET啟動客戶端
項目中使用Consul
先參考文檔:注冊中心--文檔
設計思路:
Consul服務器方法和Consul客戶端方法都封裝在MicroService.Core中,使用時是:例如在TeamService中調用Consul服務端方法進行服務注冊,在AggregateService中調用Consul客戶端方法來服務發現
Consul服務端和客戶端封裝在MicroService.Core(核心服務)中
- 包安裝:NuGet包中搜索Consul且安裝
- 注冊服務端方法:在ConsulServiceRegistry類中服務注冊
/// <summary> /// 注冊服務方法 /// </summary> /// <param name="serviceNode"></param> public void Register(ServiceRegistryConfig serviceNode) { // 1、創建consul客戶端連接 var consulClient = new ConsulClient(configuration => { //1.1 建立客戶端和服務端連接 configuration.Address = new Uri(serviceNode.RegistryAddress); }); // 2、獲取服務內部地址 // 3、創建consul服務注冊對象 var registration = new AgentServiceRegistration() { ID = serviceNode.Id, Name = serviceNode.Name, Address = serviceNode.Address, Port = serviceNode.Port, Tags = serviceNode.Tags, //心跳檢測 Check = new AgentServiceCheck { // 3.1、consul健康檢查超時間 Timeout = TimeSpan.FromSeconds(10), // 3.2、服務停止5秒后注銷服務 DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5), // 3.3、consul健康檢查地址 HTTP = serviceNode.HealthCheckAddress, // 3.4 consul健康檢查間隔時間 Interval = TimeSpan.FromSeconds(10), } }; // 4、注冊服務 consulClient.Agent.ServiceRegister(registration).Wait(); // 5、關閉連接 consulClient.Dispose(); }
- 客戶端方法:在ConsulHttpClient類中服務發現
/// <summary> /// Get方法 /// </summary> /// <typeparam name="T"></typeparam> /// param name="ServiceSchme">服務名稱:(http/https)</param> /// <param name="ServiceName">服務名稱</param> /// <param name="serviceLink">服務路徑</param> /// <returns></returns> public async Task<T> GetAsync<T>(string Serviceshcme, string ServiceName,string serviceLink) { // 1、獲取服務 IList<ServiceUrl> serviceUrls = await serviceDiscovery.Discovery(ServiceName); // 2、負載均衡服務 ServiceUrl serviceUrl = loadBalance.Select(serviceUrls); // 3、建立請求 Console.WriteLine($"請求路徑:{Serviceshcme} +'://'+{serviceUrl.Url} + {serviceLink}"); HttpClient httpClient = httpClientFactory.CreateClient("mrico"); // HttpResponseMessage response = await httpClient.GetAsync(serviceUrl.Url + serviceLink); HttpResponseMessage response = await httpClient.GetAsync(Serviceshcme +"://"+serviceUrl.Url + serviceLink); // 3.1 json轉換成對象 if (response.StatusCode == HttpStatusCode.OK) { string json = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject<T>(json); } else { // 3.2 進行自定義異常處理,這個地方進行了降級處理 throw new Exception($"{ServiceName}服務調用錯誤:{response.Content.ReadAsStringAsync()}"); } }
在TeamService(團隊服務)中調用Consul服務端方法
在Startup類的Configure方法中調用Consul服務端方法:
app.UseConsulRegistry() ;
在AggregateService(聚合服務)中調用Consul客戶端方法
在HttpTeamServiceClient類中的GetTeams方法中調用Consul客戶端方法
List<Team> teams = await consulHttpClient.GetAsync<List<Team>>(ServiceSchme, ServiceName, ServiceLink);