.Net 6 使用 Consul 實現服務註冊與發現 看這篇就夠了

Mamba24⁸發表於2023-01-06

前言

在這幾年的工作中,也經歷過幾個微服務專案,大多數都上了k8s,基本上都看不到Consul的身影,所以在工作之餘折騰了下Consul,作為個人來講還是得學習下,所以也就順便透過文章來記錄下學習過程。還有就是現在基本上只要提到微服務,其中涉及到的知識點就會很繁多,遇到的問題也會很多,建議閱讀本文前先了解下“什麼是Consul?”,”什麼是註冊中心、服務註冊、服務發現?”,”為什麼需要有服務註冊與服務發現?”等等,然後可以參考大佬的文章,講的非常詳細了 Consul概念及其架構方式
然後本文只是個人學習與分享,不喜勿噴,謝謝。

什麼是Consul?

這裡只簡單介紹下Consul,網上相關文章也比較多,就不過多陳述
Consul官網:https://www.consul.io
開源地址:https://github.com/hashicorp/consulhttps://github.com/G-Research/consuldotnet

Consul 作為一種分散式服務工具,為了避免單點故障常常以叢集的方式進行部署,在 Consul 叢集的節點中分為 ServerClient兩種節點(所有的節點也被稱為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的工作原理。

pasted-124.png

環境準備

.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介面
image 100.png

專案搭建

我們先準備2個Service(Minimal Api)以及一個Client(空 Web)

然後準備一個類庫 Service.Framework 用於封裝Consul IOC註冊

image - 2023-01-06T171915.795.png

在Service.Framework 中安裝Consul NuGet包
image - 2023-01-06T171937.761.png

然後將 Consul 配置資訊新增至各自專案的 appsettings.json 檔案中
image - 2023-01-06T172002.522.png
因為我們要將專案都執行在docker中,所以這裡的地址要用 host.docker.internal 代替,使用 localhost 無法正常啟動,如果不在 docker 中執行,這裡就配置層 localhost。

服務註冊

配置Consul 服務註冊

我們首先需要將ServiceA與ServiceB註冊到Consul中

我們直接在Service.Framework 新增擴充套件方法
ConsulExtend.cs
image - 2023-01-06T172019.627.png

Program.cs
image - 2023-01-06T172043.818.png

ConsulRegister.cs
image - 2023-01-06T172124.482.png

然後直接在對應Service專案進行IOC註冊即可

image - 2023-01-06T172155.711.png

配置健康檢查

然後我們還需要配置對應健康檢查,用來監控服務可用性,主動區分出不可用服務。
這裡我們使用中介軟體的方式
在Service.Framework中新增HealthCheckMiddleware.cs
image - 2023-01-06T172247.088.png

這裡健康檢查地址需要與appsetting.json檔案中配置的地址對應
image - 2023-01-06T172302.930.png

然後在對應服務專案中使用即可
Program.cs(示例程式碼為 ServiceA,ServiceB服務可以自行新增)
image - 2023-01-06T172320.358.png

增加測試介面

直接在Program.cs 直接新增即可
image - 2023-01-06T172405.273.png

增加docker支援

這裡我因為選擇的是在docker中執行,所以需要為專案新增docker支援。

接下來我們透過 Visual Studio為ServiceA與ServiceB專案生成對應的Dockfile檔案
image - 2023-01-06T172419.874.png

ServiceA
image - 2023-01-06T172451.611.png

ServiceB
image - 2023-01-06T172511.183.png

編譯映象

然後定位到專案根目錄,使用命令去編譯兩個映象,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 .

image - 2023-01-06T172607.293.png

image - 2023-01-06T172623.116.png

檢視編譯好的映象
image - 2023-01-06T172647.537.png

執行映象

接下來執行映象啟動專案例項

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

分別執行命令
image - 2023-01-06T172804.135.png

image - 2023-01-06T172822.110.png

然後訪問 http://localhost:8500 檢視Consul檢視服務是否註冊成功
image - 2023-01-06T172843.274.png

image - 2023-01-06T172859.225.png

image - 2023-01-06T173039.696.png

會發現服務註冊成功,健康檢查也已透過,後面服務地址埠也都對應。

服務例項叢集

然後我們繼續為服務啟動多個例項

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"

image - 2023-01-06T173117.874.png

image - 2023-01-06T173132.859.png

image - 2023-01-06T173149.865.png

當然這裡如果你覺得比較繁瑣,也可以使用docker compose來編排指令碼啟動服務例項

訪問服務介面

接下來我們試著訪問訪問介面,看看能不能出現效果

image - 2023-01-06T173211.994.png

因為終端編碼問題,導致顯示亂碼,這個不影響,ok,至此服務註冊大功告成

服務發現

我們直接在Client專案的Program.cs中準備兩個介面

程式碼很簡單
image - 2023-01-06T173234.124.png

下面這個介面,我把上面的程式碼封裝了一下,弄了個抽象類,然後模擬了3種排程策略,意思一樣的

image - 2023-01-06T173248.258.png

image - 2023-01-06T173311.441.png

用之前記得先在IOC註冊一下

builder.Services.AddConsulDispatcher(ConsulDispatcherType.Polling);

image - 2023-01-06T173340.067.png

然後我們分別訪問兩個介面,模擬訪問3次,看下效果:

ServiceADiscoveryTest

image - 2023-01-06T173406.898.png

image - 2023-01-06T173422.438.png

image - 2023-01-06T173439.187.png

ServiceBDiscoveryTest

image - 2023-01-06T173457.278.png

image - 2023-01-06T173510.990.png

image - 2023-01-06T173537.945.png

至此,服務發現就大功告成,就算其中某個節點掛掉,服務也可以正常執行。

結尾

本文只是簡單的實現了Consul的服務註冊和發現,至於怎麼更好的應用到實際專案,還得繼續探索。

後面會繼續學習閘道器等相關知識,感興趣的同學歡迎繼續關注!

程式碼倉庫地址

https://github.com/fengzhonghao8-24/ConsulIntroduction

相關文章