Tip: 此篇已加入.NET Core微服務基礎系列文章索引html
1、Consul基礎介紹
Consul是HashiCorp公司推出的開源工具,用於實現分佈式系統的服務發現與配置。與其餘分佈式服務註冊與發現的方案,好比 Airbnb的SmartStack等相比,Consul的方案更「一站式」,內置了服務註冊與發現框 架、分佈一致性協議實現、健康檢查、Key/Value存儲、多數據中心方案,再也不須要依賴其餘工具(好比ZooKeeper等),使用起來也較 爲簡單。node
Consul用Golang實現,所以具備自然可移植性(支持Linux、windows和Mac OS X);安裝包僅包含一個可執行文件,方便部署,與Docker等輕量級容器可無縫配合。linux
關於Consul的更多介紹,好比優勢,這裏就再也不贅述了,上網一搜就能夠隨處找到了。可是,必須貼一個和其餘相似軟件的對比:算法
此外,關於Consul的架構以及相關的角色,以下圖所示:spring
要想利用Consul提供的服務實現服務的註冊與發現,咱們須要創建Consul Cluster。在Consul方案中,每一個提供服務的節點上都要部署和運行Consul的Client Agent,全部運行Consul Agent節點的集合構成Consul Cluster。Consul Agent有兩種運行模式:Server和Client。這裏的Server和Client只是Consul集羣層面的區分,與搭建在Cluster之上的應用服務無關。以Server模式運行的Consul Agent節點用於維護Consul集羣的狀態,官方建議每一個Consul Cluster至少有3個或以上的運行在Server Mode的Agent,Client節點不限。docker
Consul支持多數據中心,每一個數據中心的Consul Cluster都會在運行於Server模式下的Agent節點中選出一個Leader節點,這個選舉過程經過Consul實現的raft協議保證,多個 Server節點上的Consul數據信息是強一致的。處於Client Mode的Consul Agent節點比較簡單,無狀態,僅僅負責將請求轉發給Server Agent節點。json
2、Consul集羣搭建
2.1 環境準備
這裏我準備了三臺Linux(CentOS)虛擬機和一臺Windows Server 2008 R2虛擬機,藉助VMware Workstation搭建,以下圖所示。bootstrap
其中,192.168.80.100會做爲leader角色,其他兩臺192.168.80.101和192.168.80.102會做爲follower角色。固然,實際環境中leader角色不會是一個固定的,會隨着環境的變化(好比Leader宕機或失聯)由算法選出新的leader。在進行下面的操做會前,請確保三臺節點可以相互ping通,並可以和宿主機也ping通。另外,192.168.80.71會做爲client角色,而且和其他三臺虛擬機互相ping通。ubuntu
2.2 下載Consul
Consul的下載很簡單,直接去:https://www.consul.io/downloads.html 選擇對應的平臺便可。vim
這裏咱們的linux虛擬機選擇的是Linux版本:
下載以後是一個zip文件,咱們經過XFtp等工具將其傳送到咱們的linux節點中便可。
而Windows Server虛擬機選擇的是Windows版本,再也不贅述。
2.3 安裝與配置Consul
1.解壓Consul.zip:
分別在三臺節點中解壓,解壓命令:
> unzip consul_1.1.0_linux_386.zip
解壓以後將consul複製到咱們的自定義文件目錄中,好比:/usr/local/consul
> cp consul /usr/local/consul
2.設置環境變量
分別在三臺節點中設置環境變量:
> vim /etc/profile
在profile中增長一行CONSUL_HOME並更改PATH:
# Consul
export CONSUL_HOME=/usr/local/consul
export PATH=$PATH:$JAVA_HOME/bin:$CONSUL_HOME;
使得配置生效
> source /etc/profile
測試是否生效,在三個節點測試輸入consul
> consul
看到下圖所示的命令提示,就表明OK了。
3.啓動Server(s)
分別在三臺節點上執行如下命令便可啓動Consul
192.168.80.100>consul agent -server -ui -bootstrap-expect=3 -data-dir=/tmp/consul -node=consul-1 -client=0.0.0.0 -bind=192.168.80.100 -datacenter=dc1
192.168.80.101>consul agent -server -ui -bootstrap-expect=3 -data-dir=/tmp/consul -node=consul-2 -client=0.0.0.0 -bind=192.168.80.101 -datacenter=dc1 -join 192.168.80.100
192.168.80.102>consul agent -server -ui -bootstrap-expect=3 -data-dir=/tmp/consul -node=consul-3 -client=0.0.0.0 -bind=192.168.80.102 -datacenter=dc1 -join 192.168.80.100
注意101和102的啓動命令中,有一句 -join 192.168.80.100 => 有了這一句,就把101和102加入到了100所在的集羣中。
啓動以後,集羣就開始了Vote(投票選Leader)的過程,經過下面的命令能夠看到集羣的狀況:
在Windows Server虛擬機上啓動:
> consul agent -bind 0.0.0.0 -client 192.168.80.71 -data-dir=C:\Counsul\tempdata -node EDC.DEV.WebServer -join 192.168.80.100
啓動後會有以下提示:
4.經過UI查看集羣
Consul不只提供了豐富的命令查看集羣狀況,還提供了一個WebUI,默認端口8500,咱們能夠經過訪問這個URL(eg.http://192.168.80.100:8500)獲得以下圖所示的WebUI:
能夠看到三個節點都正常啓動,下面咱們就來試試向Consul註冊一下咱們基於ASP.NET Core的WebAPI服務。
5.模擬Leader掛掉,查看Consul集羣的新選舉Leader
這裏我暴力一點直接將Leader節點關機:shutdown -h now,能夠看到咱們的80.100已經掛了。
查看其他兩個節點的日誌能夠發現,consul-3 (80.102)被選爲了新的leader:
固然,也能夠經過80.101或102的WebUI查看:
也能夠經過如下命令查看目前的各個Server的角色狀態:
> consul operator raft list-peers
雖然這裏80.100這個原leader節點掛掉了,可是隻要超過一半的Server(這裏是2/3還活着)還活着,集羣是能夠正常工做的,這也是爲何像Consul、ZooKeeper這樣的分佈式管理組件推薦咱們使用3個或5個節點來部署的緣由。
3、ASP.NET Core WebAPI服務註冊
3.1 準備一個ASP.NET Core WebAPI程序
Step1.建立一個ASP.NET Core WebAPI程序
Step2.建立一個HealthController用於Consul的健康檢查
[Produces("application/json")] [Route("api/Health")] public class HealthController : Controller { [HttpGet] public IActionResult Get() => Ok("ok"); }
*.Consul會經過call這個API來確認Service的健康狀態。
Step3.改寫啓動代碼,調用Consul API註冊服務
(1)經過Nuget安裝Consul的.NET客戶端
PM> install-package Consul
(2)基於IApplicationBuilder寫一個擴展方法,用於調用Consul API
public static class AppBuilderExtensions { public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IApplicationLifetime lifetime, ServiceEntity serviceEntity) { var consulClient = new ConsulClient(x => x.Address = new Uri($"http://{serviceEntity.ConsulIP}:{serviceEntity.ConsulPort}"));//請求註冊的 Consul 地址 var httpCheck = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服務啓動多久後註冊 Interval = TimeSpan.FromSeconds(10),//健康檢查時間間隔,或者稱爲心跳間隔 HTTP = $"http://{serviceEntity.IP}:{serviceEntity.Port}/api/health",//健康檢查地址 Timeout = TimeSpan.FromSeconds(5) }; // Register service with consul var registration = new AgentServiceRegistration() { Checks = new[] { httpCheck }, ID = Guid.NewGuid().ToString(), Name = serviceEntity.ServiceName, Address = serviceEntity.IP, Port = serviceEntity.Port, Tags = new[] { $"urlprefix-/{serviceEntity.ServiceName}" }//添加 urlprefix-/servicename 格式的 tag 標籤,以便 Fabio 識別 }; consulClient.Agent.ServiceRegister(registration).Wait();//服務啓動時註冊,內部實現其實就是使用 Consul API 進行註冊(HttpClient發起) lifetime.ApplicationStopping.Register(() => { consulClient.Agent.ServiceDeregister(registration.ID).Wait();//服務中止時取消註冊 }); return app; }
*.這裏主要是參考的田園的蟋蟀的Code,連接見參考資料部分。
(3)在Starup類的Configure方法中,調用此擴展方法
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMvc(); // register this service ServiceEntity serviceEntity = new ServiceEntity { IP = NetworkHelper.LocalIPAddress, Port = Convert.ToInt32(Configuration["Service:Port"]), ServiceName = Configuration["Service:Name"], ConsulIP = Configuration["Consul:IP"], ConsulPort = Convert.ToInt32(Configuration["Consul:Port"]) }; app.RegisterConsul(lifetime, serviceEntity); }
其中ServiceEntity類定義以下:
其中用到了appSettings.json配置文件,其定義以下:
*.這段代碼再也不解釋,一眼就能看懂。另外,除了調用Consul API以外,還能夠經過配置文件的方式,例如如下配置文件格式,這裏再也不演示。
Step4.保留默認建立的ValuesController,其他再也不建立任何API,不是本次實驗的重點。固然,你能夠集成一下Swagger,這樣有個界面文檔能夠看。
這裏我默認跳轉到healthcontroller:
3.2 發佈到IIS
Step1.在.NET Core程序中進行發佈很簡單,既能夠採用原來在VS裏邊建立配置文件進行發佈,也可使用命令行(例如:dotnet publish),這裏我仍是在VS裏面發佈,獲得Release文件
Step2.經過Ftp工具copy到Windows Server虛擬機中
Step3.這裏個人Windows Server虛擬機是2008 R2,須要裝一個Windows Server Hosting,下載地址:點我點我。若是不安裝這個,你的IIS是跑不起來.NET Core程序的。
Step4.按照你熟悉的方式在IIS中添加一個網站(服務):
Step5.更改默認應用程序池的.net framework版本爲「無託管代碼」。
Step6.照理說,到這裏就OK了,點擊瀏覽訪問,TMD,給我報了個502.5的錯誤
因而乎網上一陣搜索,發現須要打個補丁(Windows6.1-KB2533623-x64.msu),下載地址:點我點我。
Step7.安裝補丁以後,重啓IIS,能夠成功訪問了=>確保Consul可以call到咱們的服務的health API。
3.3 查看Consul集羣狀態
Step1.訪問Consul的WebUI查看服務是否註冊成功:能夠看到咱們的ClientService已成功註冊
Step2.Consul不只僅提供了服務註冊,還提供了服務發現,咱們能夠經過調用其提供的API來發現服務的IP和Port。
Url>http://192.168.80.100:8500/v1/catalog/service/CAS.NB.ClientService
*.咱們能夠看到返回了ClientService的ServiceAddress和ServicePort,就能夠經過其組成URL進行服務調用了。固然,咱們可能會對一個服務部署多個實例,以組成集羣來實現負載均衡。咱們能夠設置一些負載均衡的策略,假設經過取模運算隨機選擇一個服務地址返回給服務消費者。
Step3.這裏咱們將發佈的Release文件在Windows Server虛擬機上copy一份,並改一下配置文件,讓其ServiceName變爲CAS.NB.ProductService,其Port變爲8820,在IIS上再添加一個網站,啓動起來,再經過WebUI查看Consul集羣狀態:
Step4.這時咱們再經過如下API進行服務發現:
Url>http://192.168.80.100:8500/v1/catalog/service/CAS.NB.ProductService
4、小結與後續工做
本篇主要基於一個最小化的集羣搭建了一個Consul服務治理組件,並將ASP.NET Core API程序註冊到了Consul,並嘗試經過Consul進行服務發現(雖然沒有模擬具體的服務消費)。本篇沒有仔細講述Consul的介紹、優勢、缺點,由於本人也沒有啥實際的經驗,所以只能是站在其餘園友的肩膀上作個小實驗。ASP.NET Core是一個天生適合微服務的技術,也但願能在咱們的學習和推進下,讓公司把.NET Core應用起來,未來可以跑在Linux和Docker上,這是我目前的目標,與你們共勉。
後續我會繼續嘗試基於Ocelot構建API網關,到時會結合Consul進行進一步的集成。另外,還會嘗試Polly進行熔斷降級、Identity Server進行驗證,Exceptionless做分佈式日誌,基本上會遵循.NET Core大隊長張善友的微服務示例項目NanoFabric用到的(或者說是給咱們安利的技術框架)那些開源技術來搭建一個初步的微服務架構,以便於之後在公司內部推廣和應用。此外,考慮到公司目前的微服務架構是基於Java的(Spring Cloud),那麼也會考慮經過 Steeltoe 來和Spring Cloud進行兼容,讓Java和.Net Core微服務可以共存(能夠參考資料裏的第7個,田園裏的蟋蟀出品)。這裏,也安利一下正在學習微服務的.NET Coder們,能夠看看張善友老師的NanoFabric,或者是楊中科老師的.NET Core微服務課程。
最近不少朋友問我爲何再也不寫技術文了,總是寫一些觀後感、讀後感之類的,一來由於讀那些書其實也是我今年的我的OKR,二來這半年來的確不想看技術書和資料,最後由於身體緣由無法過多地熬夜。如今學習.NET Core以來被其深深吸引,就像是找到了一個那些年咱們追過的女孩兒,以爲它樣樣都美,很想跟它繼續走下去,發現它更多的美,所以也會趁着微服務學習的勁跟你們分享更多的文章。
附件下載
示例代碼:點我下載
參考資料
(1)田園裏的蟋蟀,《Docker & Consul & Fabio & ASP.NET Core 2.0 微服務跨平臺實踐》
(2)不小下,《服務發現 - consul 的介紹、部署和使用》
(3)二胡槽子,《我是服務的執政官-服務發現和註冊工具consul簡介》
(4)大副,《consul分佈式集羣搭建&簡單功能測試&故障恢復》
(5)94cool,《win2008server R2 x64 部署.net core到IIS》
(6)楊中科《.NET Core微服務課件》
(7)田園裏的蟋蟀,《.NET Core 微服務架構 Steeltoe 使用(基於 Spring Cloud)》