.NET Core + Consul 服务注册与发现
在分布式架構(gòu)中,服務(wù)治理是必須面對的問題,如果缺乏簡單有效治理方案,各服務(wù)之間只能通過人肉配置的方式進(jìn)行服務(wù)關(guān)系管理,當(dāng)遇到服務(wù)關(guān)系變化時(shí),就會(huì)變得極其麻煩且容易出錯(cuò)。
Consul[1] 是一個(gè)用來實(shí)現(xiàn)分布式系統(tǒng)服務(wù)發(fā)現(xiàn)與配置的開源工具。它內(nèi)置了服務(wù)注冊與發(fā)現(xiàn)框架、分布一致性協(xié)議實(shí)現(xiàn)、健康檢查、Key/Value存儲、多數(shù)據(jù)中心方案,不再需要依賴其他工具(比如 ZooKeeper 等),使用起來也較為簡單。
Consul 架構(gòu)
Consul 集群支持多數(shù)據(jù)中心,在上圖中有兩個(gè) DataCenter,他們通過 Internet 互聯(lián),為了提高通信效率,只有 Server 節(jié)點(diǎn)才加入跨數(shù)據(jù)中心的通信。在單個(gè)數(shù)據(jù)中心中,Consul 分為 Client 和 Server 兩種節(jié)點(diǎn)(所有的節(jié)點(diǎn)也被稱為 Agent),Server 節(jié)點(diǎn)保存數(shù)據(jù),Client 負(fù)責(zé)健康檢查及轉(zhuǎn)發(fā)數(shù)據(jù)請求到 Server,本身不保存注冊信息;Server 節(jié)點(diǎn)有一個(gè) Leader 和多個(gè) Follower,Leader 節(jié)點(diǎn)會(huì)將數(shù)據(jù)同步到 Follower,Server 節(jié)點(diǎn)的數(shù)量推薦是3個(gè)或者5個(gè),在 Leader 掛掉的時(shí)候會(huì)啟動(dòng)選舉機(jī)制產(chǎn)生一個(gè)新 Leader。
Consul 集群搭建
這里使用 Docker 搭建 3個(gè) Server 節(jié)點(diǎn) + 1 個(gè) Client 節(jié)點(diǎn),API 服務(wù)通過 Client 節(jié)點(diǎn)進(jìn)行服務(wù)注冊和發(fā)現(xiàn)。
從 Docker Hub 拉取 Consul 鏡像
docker pull consul啟動(dòng) 3個(gè) Server 節(jié)點(diǎn) + 1 個(gè) Client 節(jié)點(diǎn)
docker-compose.yaml 如下:
version: '3'services:cs1:image: consulcommand: agent -server -client=0.0.0.0 -bootstrap-expect=3 -node=cs1 -data-dir=/datavolumes:- /usr/local/docker/consul/data/cs1:/datacs2:image: consulcommand: agent -server -client=0.0.0.0 -retry-join=cs1 -node=cs2 -data-dir=/datavolumes:- /usr/local/docker/consul/data/cs2:/datadepends_on:- cs1cs3:image: consulcommand: agent -server -client=0.0.0.0 -retry-join=cs1 -node=cs3 -data-dir=/datavolumes:- /usr/local/docker/consul/data/cs3:/datadepends_on:- cs1cc1:image: consulcommand: agent -client=0.0.0.0 -retry-join=cs1 -ui -node=cc1 -data-dir=/dataports:- 8500:8500volumes:- /usr/local/docker/consul/data/cc1:/datadepends_on:- cs2- cs3主要參數(shù)說明:
| -server | 設(shè)置為 Server 類型節(jié)點(diǎn),不加則為 Client 類型節(jié)點(diǎn) |
| -client | 注冊或者查詢等一系列客戶端對它操作的IP,默認(rèn)是127.0.0.1 |
| -bootstrap-expect | 集群期望的 Server 節(jié)點(diǎn)數(shù),只有達(dá)到這個(gè)值才會(huì)選舉 Leader |
| -node | 指定節(jié)點(diǎn)名稱 |
| -data-dir | 數(shù)據(jù)存放位置 |
| -retry-join | 指定要加入的節(jié)點(diǎn)地址(組建集群) |
| -ui | 啟用 UI 界面 |
集群狀態(tài)
(e002ca62ac24 ?為容器名稱,可通過 docker ps | grep consul 查看,選擇任意一個(gè)即可)
查看節(jié)點(diǎn)狀態(tài)和類型
docker exec -t e002ca62ac24 consul members當(dāng)前為3 個(gè) Server 類型節(jié)點(diǎn) ,1 個(gè) Client 類型節(jié)點(diǎn)。
查看 Server 節(jié)點(diǎn)類型
docker exec -t e002ca62ac24 consul operator raft list-peers當(dāng)前為 cs1 為 leader,可以測試將 cs1 stop 觀察 leader 的重新選舉。
通過 http://192.168.124.9:8500 UI 界面查看 Consul 節(jié)點(diǎn)狀態(tài)如下:(192.168.124.9 是 consul 容器外部訪問 IP)
.NET Core 接入 Consul
創(chuàng)建 .NET Core WebAPI(3.1) 服務(wù) ServiceA(2個(gè)實(shí)例) 和 ServiceB
NuGet 安裝 Consul
注冊到 Consul 的核心代碼如下(源碼下載[2]):
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,// 服務(wù)名Address = consulOption.ServiceIP, // 服務(wù)綁定IPPort = consulOption.ServicePort, // 服務(wù)綁定端口Check = new AgentServiceCheck(){DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服務(wù)啟動(dòng)多久后注冊Interval = TimeSpan.FromSeconds(10),//健康檢查時(shí)間間隔HTTP = consulOption.ServiceHealthCheck,//健康檢查地址Timeout = TimeSpan.FromSeconds(5)}};// 服務(wù)注冊consulClient.Agent.ServiceRegister(registration).Wait();// 應(yīng)用程序終止時(shí),服務(wù)取消注冊lifetime.ApplicationStopping.Register(() =>{consulClient.Agent.ServiceDeregister(registration.ID).Wait();});return app;} }添加配置如下:
"Consul": {"ServiceName": "service-a","ServiceIP": "192.168.124.11", // 當(dāng)前服務(wù)訪問 IP"ServicePort": 8000,"ServiceHealthCheck": "http://192.168.124.11:8000/healthCheck","Address": "http://192.168.124.9:8500" }注冊成功結(jié)果如下:
ServiceB 調(diào)用 ServiceA 接口
ServiceB 通過 ConsulClient 進(jìn)行服務(wù)發(fā)現(xiàn),獲取到 ServiceA 的地址,然后隨機(jī)請求請求任意一個(gè)實(shí)例,關(guān)鍵代碼如下:
using (var consulClient = new ConsulClient(a => a.Address = new Uri(_consulOption.Address))) {var services = consulClient.Catalog.Service("service-a").Result.Response;if (services != null && services.Any()){// 模擬隨機(jī)一臺進(jìn)行請求,這里只是測試,可以選擇合適的負(fù)載均衡框架var service = services.ElementAt(new Random().Next(services.Count()));var client = _httpClientFactory.CreateClient();var response = await client.GetAsync($"http://{service.ServiceAddress}:{service.ServicePort}/test/get");var result = await response.Content.ReadAsStringAsync();return result;} }多次調(diào)用結(jié)果如下:
參考資料
[1]
Consul: https://www.consul.io/
[2]源碼下載: https://github.com/beckjin/ConsulDotnetSamples
總結(jié)
以上是生活随笔為你收集整理的.NET Core + Consul 服务注册与发现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 不用虚机不用Docker使用Azure应
- 下一篇: .NET Core + Spring C