前言
在這幾年的工作中,也經歷過幾個微服務專案,大多數都上了k8s,基本上都看不到Consul的身影,所以在工作之餘折騰了下Consul,作為個人來講還是得學習下,所以也就順便透過文章來記錄下學習過程。還有就是現在基本上只要提到微服務,其中涉及到的知識點就會很繁多,遇到的問題也會很多,建議閱讀本文前先了解下“什麼是Consul?”,”什麼是註冊中心、服務註冊、服務發現?”,”為什麼需要有服務註冊與服務發現?”等等,然後可以參考大佬的文章,講的非常詳細了 Consul概念及其架構方式
然後本文只是個人學習與分享,不喜勿噴,謝謝。
什麼是Consul?
這裡只簡單介紹下Consul,網上相關文章也比較多,就不過多陳述。
Consul官網:https://www.consul.io
開源地址:https://github.com/hashicorp/consul、https://github.com/G-Research/consuldotnet
Consul 作為一種分散式服務工具,為了避免單點故障常常以叢集的方式進行部署,在 Consul 叢集的節點中分為 Server和 Client兩種節點(所有的節點也被稱為Agent),Server 節點儲存資料,Client 節點負責健康檢查及轉發資料請求到 Server;Server 節點有一個 Leader 節點和多個 Follower 節點,Leader 節點會將資料同步到 Follower 節點,在 Leader 節點掛掉的時候會啟動選舉機制產生一個新的 Leader。
Client 節點很輕量且無狀態,它以 RPC 的方式向 Server 節點做讀寫請求的轉發,此外也可以直接向 Server 節點傳送讀寫請求。下面是 Consul 的架構圖:
Consul 作為一種分散式服務工具,為了避免單點故障常常以叢集的方式進行部署,在 Consul 叢集的節點中分為 Server 和 Client 兩種節點(所有的節點也被稱為Agent),Server 節點儲存資料,Client 節點負責健康檢查及轉發資料請求到 Server;Server 節點有一個 Leader 節點和多個 Follower 節點,Leader 節點會將資料同步到 Follower 節點,在 Leader 節點掛掉的時候會啟動選舉機制產生一個新的 Leader。
Client 節點很輕量且無狀態,它以 RPC 的方式向 Server 節點做讀寫請求的轉發,此外也可以直接向 Server 節點傳送讀寫請求。下面是 Consul 的架構圖,很好的解釋了Consul的工作原理。
環境準備
.Net 6
Docker desktop
Visual Studio 2022
安裝Consul
Consul 支援各種平臺的安裝,安裝文件:https://www.consul.io/downloads,為了快速使用,我這裡選擇用 docker 方式安裝。
docker pull consul --預設拉取latest
docker run -d --name consul -p 8500:8500 consul:latest --使用映象 consul:latest 啟動容器,將容器的8500埠對映到主機的8500埠
啟動Consul,開啟預設地址 http://localhost:8500 可以看到Consul的UI介面
專案搭建
我們先準備2個Service(Minimal Api)以及一個Client(空 Web)
然後準備一個類庫 Service.Framework 用於封裝Consul IOC註冊
在Service.Framework 中安裝Consul NuGet包
然後將 Consul 配置資訊新增至各自專案的 appsettings.json 檔案中
因為我們要將專案都執行在docker中,所以這裡的地址要用 host.docker.internal 代替,使用 localhost 無法正常啟動,如果不在 docker 中執行,這裡就配置層 localhost。
服務註冊
配置Consul 服務註冊
我們首先需要將ServiceA與ServiceB註冊到Consul中
我們直接在Service.Framework 新增擴充套件方法
ConsulExtend.cs
Program.cs
ConsulRegister.cs
然後直接在對應Service專案進行IOC註冊即可
配置健康檢查
然後我們還需要配置對應健康檢查,用來監控服務可用性,主動區分出不可用服務。
這裡我們使用中介軟體的方式
在Service.Framework中新增HealthCheckMiddleware.cs
這裡健康檢查地址需要與appsetting.json檔案中配置的地址對應
然後在對應服務專案中使用即可
Program.cs(示例程式碼為 ServiceA,ServiceB服務可以自行新增)
增加測試介面
直接在Program.cs 直接新增即可
增加docker支援
這裡我因為選擇的是在docker中執行,所以需要為專案新增docker支援。
接下來我們透過 Visual Studio為ServiceA與ServiceB專案生成對應的Dockfile檔案
ServiceA
ServiceB
編譯映象
然後定位到專案根目錄,使用命令去編譯兩個映象,service_a和service_b(這裡不清楚的可以參考我之前的文章 .NET 6 從0到1使用Docker部署至Linux環境)
docker image build -f ./ServiceA/Dockerfile -t service_a .
docker image build -f ./ServiceB/Dockerfile -t service_b .
檢視編譯好的映象
執行映象
接下來執行映象啟動專案例項
docker run -d -p 5050:80 --name service_a1 service_a --ConsulRegisterOptions:Port="5050"
docker run -d -p 5060:80 --name service_b1 service_b --ConsulRegisterOptions:Port="5060"
然後這裡注意一下 ConsulRegisterOptions:Port="5050"
這裡的意思是會替換appsetting.json 檔案中的ConsulRegisterOptions配置檔案中Port的內容,這裡可以方便後面啟動多例項時指定對應埠,本示例為單例項也可不需要此項內容,預設使用配置檔案中的Port
docker run -d -p 5050:80 --name service_a1 service_a
docker run -d -p 5060:80 --name service_b1 service_b
分別執行命令
然後訪問 http://localhost:8500 檢視Consul檢視服務是否註冊成功
會發現服務註冊成功,健康檢查也已透過,後面服務地址埠也都對應。
服務例項叢集
然後我們繼續為服務啟動多個例項
docker run -d -p 5051:80 --name service_a2 service_a --ConsulRegisterOptions:Port="5051"
docker run -d -p 5052:80 --name service_a3 service_a --ConsulRegisterOptions:Port="5052"
docker run -d -p 5061:80 --name service_b2 service_b --ConsulRegisterOptions:Port="5061"
docker run -d -p 5062:80 --name service_b3 service_b --ConsulRegisterOptions:Port="5062"
當然這裡如果你覺得比較繁瑣,也可以使用docker compose來編排指令碼啟動服務例項
訪問服務介面
接下來我們試著訪問訪問介面,看看能不能出現效果
因為終端編碼問題,導致顯示亂碼,這個不影響,ok,至此服務註冊大功告成
服務發現
我們直接在Client專案的Program.cs中準備兩個介面
程式碼很簡單
下面這個介面,我把上面的程式碼封裝了一下,弄了個抽象類,然後模擬了3種排程策略,意思一樣的
用之前記得先在IOC註冊一下
builder.Services.AddConsulDispatcher(ConsulDispatcherType.Polling);
然後我們分別訪問兩個介面,模擬訪問3次,看下效果:
ServiceADiscoveryTest
ServiceBDiscoveryTest
至此,服務發現就大功告成,就算其中某個節點掛掉,服務也可以正常執行。
結尾
本文只是簡單的實現了Consul的服務註冊和發現,至於怎麼更好的應用到實際專案,還得繼續探索。
後面會繼續學習閘道器等相關知識,感興趣的同學歡迎繼續關注!