微服務說起來高大尚,實際擼一遍來試試看,用現在比較常用的微服務框架,Consul和Ocelote做一個Demo,一起來試試吧! 說在前面的話 準備好環境,拉取源代碼,按照每個章節中的【實踐操作】進行操作,即可搭建起來,已經測試通過。 不想把篇幅拉太長,且此文實踐為主,如果對微服務沒有理論基礎,建議先 ...
微服務說起來高大尚,實際擼一遍來試試看,用現在比較常用的微服務框架,Consul和Ocelote做一個Demo,一起來試試吧!
說在前面的話
準備好環境,拉取源代碼,按照每個章節中的【實踐操作】進行操作,即可搭建起來,已經測試通過。
不想把篇幅拉太長,且此文實踐為主,如果對微服務沒有理論基礎,建議先閱讀其他博主的微服務理論,再食用本文,效果更佳~
如有解釋不當或錯誤的地方,歡迎各位大佬加以斧正!
之後要是有空,後續會容器化部署上雲伺服器,把部署過程剪一個視頻出來。
環境準備(Windows版)
- Windows 系統
- 源代碼:https://gitee.com/yi_zihao/micservice 或 Github https://github.com/OrzCoCo-Y/MicService.Net
- Consul安裝包:https://www.consul.io/downloads
- Nginx: https://nginx.org/en/download.html
- Apipost 或者 PostMan
- Visual Studio 2019:Demo用的.Net Core 3.1,能跑起來就行
- (建議安裝)控制台終端:https://docs.microsoft.com/zh-cn/windows/terminal/install
- 修改Hosts文件,單機跑Consul集群,解決Ocelot在請求下發時,出現識別不到主機錯誤,此錯誤的原因是服務實例和Consul在同一臺電腦上時,Ocelot會將請求下發至對應的HostName , 在不同電腦上則返回服務所在電腦的 ipAddress.具體參考這位博主的分享:
https://www.cnblogs.com/citycomputing/p/12070909.html
Windows單體部署架構圖
- 用戶發送請求至網關地址,網關對此次請求做請求轉發,轉發的策略及配置規則在Ocelot項目中,指定一個configuration.json的配置文件,在宿主機創建IConfiguration時,將配置json文件作為鍵值對給Ocelot做配置使用
- 一開始,用戶在授權中心獲取Token
- 從ocelot源代碼可以看到FileRoute定義了Ocelot的基本配置
- 上游的請求(upstream),在網關中,根據路由匹配規則(Routes),轉發到下游地址(downstream)
- 下游地址便是服務地址,那網關如何知道將請求轉發到哪個服務呢,這裡便用上了Consul的服務註冊與發現,當然不僅僅只集成Consul,Consul只是選擇之一。
- 請求在經過網關時,使用了Polly的彈性故障處理框架,加了一層自定義緩存。
- 身份認證下放至服務實例,未在網關層加驗證
以上便是簡易的微服務Demo框架介紹,下邊開始拉取項目實踐吧!
服務註冊與發現
啟動並創建Consul集群
簡單來說,各個業務服務實例註冊在Consul這個平臺的節點中,各個節點分享註冊信息,一起組合成為一個集群。
每個節點分為客戶端模式與服務端模式,其區別就是,服務端會存儲各個節點的數據,客戶端則所有註冊到該節點的服務信息,都會轉發至其他服務端節點,本身不存儲這些信息。
也是由此原因,客戶端模式的節點數量是不限制的,服務端模式節點則會控制數據
raft是一種選舉的演算法,用來實現微服務CAP中的分散式一致性,上圖的Server模式帶星的則為選舉出來的Lead,可以自行瞭解一下
模擬動畫,輔助理解raft:http://thesecretlivesofdata.com/raft/
Consul配置詳解: https://www.cnblogs.com/sunsky303/p/9209024.html
實踐操作
準備Consul配置文件,源代碼根目錄下已經上傳
- 啟動Consul有兩種方式,比如純命令行啟動、按照配置文件啟動
- 因為是單機部署,所以此處為:配置文件指定了每個Consul實例的埠,按照配置文件結合命令進行啟動
// Windows 終端
-- 進入Consul解壓目錄
cd D:\Consul
-- 服務端模式
.\consul.exe agent -server -bootstrap-expect=3 -data-dir=d:\consultmp\data-dir1 -config-file=D:\Consul\config\8500.json -node=server1 -bind='127.0.0.1' -client='0.0.0.0' -ui
.\consul.exe agent -server -data-dir=d:\consultmp\data-dir2 -config-file=D:\Consul\config\9500.json -node=server2 -bind='127.0.0.1' -client='0.0.0.0' -join='127.0.0.1:8301' -ui
.\consul.exe agent -server -data-dir=d:\consultmp\data-dir3 -config-file=D:\Consul\config\10500.json -node=server3 -bind='127.0.0.1' -client='0.0.0.0' -join='127.0.0.1:8301' -ui
-- 客戶端模式
.\consul.exe agent -data-dir=d:\consultmp\data-dir4 -config-file=D:\Consul\config\11500.json -node=client1 -bind='127.0.0.1' -join='127.0.0.1:8301' -client='0.0.0.0' -ui
下載Consul應用程式之後,存放在指定文件夾,分別啟動服務端模式和客戶端模式的節點,組成Consul集群
啟動集群之後可以分別打開
127.0.0.1:8500
127.0.0.1:9500
127.0.0.1:10500
127.0.0.1:11500
可以看到Consul的自帶的ui界面,啟動命令中的 -ui開啟此界面
至此,Consul集群搭建完成,接下來用Nginx為集群做請求負載均衡。
Nginx使用如下配置
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream ConsulNginx {
server localhost:8500;
server localhost:9500;
server localhost:10500;
server localhost:11500;
}
server {
listen 8080;
server_name localhost;
location / {
proxy_pass http://ConsulNginx;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
進入Nginx安裝目錄,使用start nginx
命令
Nginx啟動成功,則進入http://localhost:8080/
即可看到Consul的UI界面
業務服務啟動與註冊到Consul
準備一個業務服務程式,實際開發中可以為商品服務,訂單服務,支付服務等等,服務中在調用Consul提供的方法註冊在其節點中之後,業務服務需要拋出一個簡易的可以返回當前狀態的介面,用作健康檢查。
此Demo使用一個簡易的用戶服務做演示,其中包含了受保護的資源、可匿名訪問的資源,健康檢查則是一個列印當前日期的介面。
實踐操作
服務實例註冊到Consul節點中,Appsettings.json文件中的ConsulAddress對應註冊到某個Consul節點
// 啟動webapi
-- Windows 終端
-- 進入指定文件夾,自行修改文件路徑,生成路徑
cd D:\Study\micservice-master\MicServiceDemo\MicServiceWebApi\bin\Debug\netcoreapp3.1
-- 微服務Api,可以是用戶服務,產品服務等待
dotnet MicServiceWebApi.dll --urls="http://*:44380" --ip="127.0.0.1" --port=44380
dotnet MicServiceWebApi.dll --urls="http://*:44381" --ip="127.0.0.1" --port=44381
dotnet MicServiceWebApi.dll --urls="http://*:44382" --ip="127.0.0.1" --port=44382
dotnet MicServiceWebApi.dll --urls="http://*:44383" --ip="127.0.0.1" --port=44383
註冊至服務Conul節點,當然可以直接用ConsulNginx 8080埠進行註冊,此處是為了註冊至每個節點而這樣處理
在此,啟動了四個服務實例:
127.0.0.1:44380
127.0.0.1:44381
127.0.0.2:44382
127.0.0.2:44383
分別註冊在4個consul節點之中
http://127.0.0.1:8500
http://127.0.0.1:9500
http://127.0.0.1:10500
http://127.0.0.1:11500
試著請求 127.0.0.1:44380/api/user/getall
請求保護資源,因為未授權則會是401無許可權錯誤,這裡需要授權中心拿到accesstoken才可以獲取到結果,Token的獲取在下一節便能知道。
接著嘗試請求127.0.0.1:44381/api/user/getallwithnoverify
請求匿名介面,則可以拿到mock的數據。
授權中心
目前為止,此時還只是註冊了服務,獲取數據還是請求的業務服務暴露出來的地址與埠,這顯然還不算微服務,也不安全,現在先把授權中心啟動,待萬事具備,再網關啟動則可以跑通整個鏈路。
當然為了安全,服務實例部署到雲伺服器,會將44380這些埠用防火牆給牆柱,不讓外部直接訪問,只留下網關埠地址即可
Ids4授權中心
Identity Server 4 中有多種授權模式,常見的密碼模式、客戶端模式用的比較多,這裡使用簡單的客戶端模式,他們都是基於Oauth2.0協議,可自行瞭解,這裡不展開,使用起來還是很容易理解。
AuthenticationCenter項目,Startup中啟用的授權中心services.AddIdentityServer
,就是核心的一些配置和參數,他們決定了授權服務保護了哪些API作用域,決定了哪些客戶端可以使用這個授權服務。
這裡指定了一個客戶端的Id與密碼,以及授權訪問的域
StartUp.cs授權下方的【測試訪問受保護資源】,則是在授權中心這個項目中做了一個測試,用於測試授權訪問是否成功,例如:
Home/Index 設為[Authorize] 需要授權才能訪問
Home/Allow 設為[AllowAnonymous] 匿名訪問
實踐操作
// 啟動授權中心
-- 進入生成目錄
cd G:\Study\Git\micservice\MicServiceDemo\AuthenticationCenter\bin\Debug\netcoreapp3.1\
-- 啟動授權中心
dotnet AuthenticationCenter.dll --urls="http://*:7000" --ip="127.0.0.1" --port=7000
驗證授權中心是否生效,此時預留測試介面派上用場
1.從授權中心獲取token,http://localhost:7000/connect/token
- 直接訪問受保護的資源,必定401無權訪問,將獲取的token放置請求頭中,即可通過授權
授權中心,便啟動測試成功了,以上的測試是一個極簡的OAuth2.0流程,授權中心拿Token去訪問受保護資源
網關啟動
現在服務註冊準備好了,多個業務服務也註冊在Consul的各個節點之中,授權中心也是啟動可授權狀態,現在便開始Ocelot網關的啟動
Ocelot
在上文中一起看過源碼,瞭解到ocelot集成了包括路由、請求聚合、服務發現、認證鑒權、限流、負載均衡等功能。而這些功能都可以直接通過修改json配置文件即可使用
//*****************************超時+限流+熔斷+降級+Consul+Polly********************************
{
"Routes": [
{
//轉發到下游服務地址--url變數
"DownstreamPathTemplate": "/api/{url}", // 服務地址--url變數
//下游http協議
"DownstreamScheme": "http",
//負載方式,
"LoadBalancerOptions": {
"Type": "RoundRobin" // RoundRobin 輪詢 LeastConnection-最少連接數的伺服器 NoLoadBalance不負載均衡
},
//上游地址
"UpstreamPathTemplate": "/gateway/{url}", // 網關地址--url變數 // 衝突的還可以加權重Priority
"UpstreamHttpMethod": [ "Get", "Post", "DELETE", "PUT" ],
// 使用服務發現
"UseServiceDiscovery": true,
"ServiceName": "MicServiceDemo", //consul服務名稱
// 限流設置, polly
"RateLimitOptions": {
"ClientWhitelist": [ "admin" ], //白名單 請求頭ClientId 區分大小寫
"EnableRateLimiting": true,
"Period": "5m", //1s, 5m, 1h, 1d
"PeriodTimespan": 30, //多少秒之後客戶端可以重試
"Limit": 5 //統計時間段內允許的最大請求數量
},
// 熔斷設置,熔斷器使用Polly
//"QoSOptions": {
// "ExceptionsAllowedBeforeBreaking": 3, //允許多少個異常請求
// "DurationOfBreak": 10000, // 熔斷的時間,單位為ms
// "TimeoutValue": 2000 //單位ms 如果下游請求的處理時間超過多少則自如將請求設置為超時 預設90秒
//}
// 鑒權
//"AuthenticationOptions": {
// "AuthenticationProviderKey": "UserGatewayKey", // 指定一個key,startUp中使用
// "AllowedScopes": [ "gatewayScope" ]
//},
// 文件緩存
"FileCacheOptions": {
"TtlSeconds": 15,
"Region": "UserCache" //可以調用Api清理
}
}
],
"GlobalConfiguration": {
"ServiceDiscoveryProvider": {
"Host": "localhost", // Consul 集群地址
"Port": 8080, // Consul Nginx負載均衡 埠
// "Port": 8500. // Consul 節點埠
// 由Consul提供服務發現
"Type": "Consul"
},
// 限流選項
"RateLimitOptions": {
"QuotaExceededMessage": "請求太頻繁,觸發限流 ", // 當請求過載被截斷時返回的消息
"HttpStatusCode": 666 // 當請求過載被截斷時返回的http status
//"ClientIdHeader": "client_id" // 用來識別客戶端的請求頭,預設是 ClientId
}
}
}
在此配置下,可以大致瞭解,請求經過網關時,Ocelot所做的一些處理
- 上游當請求至網關,符合
UpstreamPathTemplate
節點所設置的模板“/gateway/{url}”,則將請求下發至下游的DownstreamPathTemplate
:"/api/{url}" - 服務的提供者則為
GlobalConfiguration.ServiceDiscoveryProvider
,包含Consul的地址與埠,服務名稱為"ServiceName": "MicServiceDemo"
- 判斷該請求是否觸發polly的限流策略,在此配置中
RateLimitOptions
和GlobalConfiguration.RateLimitOptions
的策略為:5分鐘之內,至多請求5次,第6次開始HTTP狀態碼為666,返回的信息為“請求太頻繁,觸發限流”,30秒冷卻期,請求頭中加入 ClientId=admin,則為白名單可不受限流策略影響 - 授權策略在這裡註釋了,認證授權在服務層做,而不再網關層,如果想要在網關進行授權認證,取消註釋即可
實踐操作
-- 進入生成目錄
cd D:\Study\Git\micservice\MicServiceDemo\OcelotGateway\bin\Debug\netcoreapp3.1\
-- Windows 終端
dotnet OcelotGateway.dll --urls="http://*:6297" --ip="127.0.0.1" --port=6297
dotnet OcelotGateway.dll --urls="http://*:6298" --ip="127.0.0.1" --port=6298
dotnet OcelotGateway.dll --urls="http://*:6299" --ip="127.0.0.1" --port=6299
為了容錯及高可用, 啟動三個 網關實例。
此時可以用 http://localhost:6297/gateway/user/getallwithnoverify
測試鏈路是否通了
http://localhost:6297/gateway/user/getallwithnoverify
符合網關下發請求的規則,則在服務註冊中心(NginxForConsul:localhost:8080)取一個節點(此處隨機到節點client1)- 將請求下發至
http://client1:44380/api/user/getallwithnoverify
- 因為修改了Host文件,client1映射為127.0.0.1,故請求轉發的真實地址為
http://127.0.0.1:44380/api/user/getallwithnoverify
至此網關的集群搭建已完成,與Consul集群一樣,這裡再用Nginx做一層針對於Ocelot網關的負載均衡
NginxForOcelot 使用如下配置
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream OcelotNginx {
server localhost:6297;
server localhost:6298;
server localhost:6299;
}
server {
listen 9090;
server_name localhost;
location / {
proxy_pass http://OcelotNginx;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
進入Nginx安裝目錄,使用start nginx
命令
啟動Nginx之後,則可在上文的基礎上再做一次負載均衡。
嘗試請求 http://127.0.0.1:9090/gateway/user/getallwithnoverify
,則會自動選擇Ocelot集群中的某一個網關進行請求下發
OK,至此整個微服務架構就搭建完了,下麵進行測試
測試負載均衡
多次請求網關獲取數據,返回的apiDomain不盡相同,則負載均衡完成
當然可以查看Ocelot網關的控制台,是將請求轉發至哪個網關,及其網關下的Consul節點
測試授權訪問
直接訪問http://localhost:9090/gateway/User/GetAll
是為401未授權錯誤。
在授權中心獲取Token之後,ApiPost中填入認證Token,即可獲取到受保護介面提供的數據
測試限流
快速請求多次,觸發限流
總結
這次的微服務搭建,只在單機環境下,做的負載均衡都是偽負載均衡,沒有整虛擬機和多個伺服器上去部署,確實是一個遺憾,但是涉及的方面比較多還是有很多的學習價值,Consul和Ocelot這一套算是很常見的.net 微服務框架了,之後也可以試試其他框架。
往後,準備給目前這一套架構舔磚加瓦,比如分散式配置中心Apollo,分散式系統的應用程式性能監視工具 skywalking等等.....
最後再貼一下架構圖
總結一下部署的流程
- 啟動Consul集群
- 為Consul集群添加Nginx 負載均衡
- 啟動服務實例,並且註冊至Consul
- 啟動Ids4授權中心
- 啟動Ocelot網關集群
- 為網關集群添加Nginx 負載均衡
源代碼
【Gitee】源代碼 https://gitee.com/yi_zihao/micservice
【GitHub】源代碼 https://github.com/OrzCoCo-Y/MicService.Net.git
參考資料
【博客園-可均可可】微服務簡介與技術棧 https://www.cnblogs.com/PatrickLiu/p/13925259.html
【博客園-sunsky303】consul配置參數大全、詳解、總結 https://www.cnblogs.com/sunsky303/p/9209024.html
【博客園-神游虛空】Ocelot 發現服務總是失敗的解決辦法 https://www.cnblogs.com/citycomputing/p/12070909.html
【raft】 http://thesecretlivesofdata.com/raft/