一. 基礎說明
1. API網關剖析
(1).什么是Api
API是Application Programming Interface縮寫,翻譯成中文就是應用程序接口。在實際微服務中可以理解一個個功能方法。就比如你一個商品服務的微服務, 可以對外提供 API 接口為,獲取商品目錄、獲取商品詳情等。
(2).什么是網關(Gateway)
它是一個服務器,用來轉發其他服務器通信數據的, 它接收從客戶端發送來的請求時,它就像自己擁有資源的源服務器一樣對請求進行處理。
(3).什么是Api網關
通俗的來說就是用來限制客戶端訪問服務端api一道門檻。
2. 微服務架構中為什么要用網關?
(1).在這之前,我們的技術棧中只引入了Consul,客戶端訪問Consul拿到對應的IP+Port,最終還是要訪問業務服務器的,但很多情況我們並不想讓業務服務器直接對外開放,所以這個時候就需要引入網關進行轉發了.
(2).現在的微服務還沒有加權限校驗,如果將權限校驗加個每個微服務的業務服務器上,開發量很大,這個時候引入網關,可以在網關層校驗.
(3).沒有網關,很難做限流,而且各個業務的負責人員不能獨立負責自己的服務器器。
3. 網關都有哪些作用?
路由、負載均衡、限流、認證、授權、鏈路監控、熔斷降級、Service Fabric
4. Ocelot相關信息
(1).依賴程序集:通過Nuget安裝 【Ocelot 16.0.1】
GitHub地址:https://github.com/ThreeMammals/Ocelot
(2).參考文檔:
官網:https://ocelot.readthedocs.io/en/latest/
ocelot 中文文檔:https://blog.csdn.net/sD7O95O/article/details/79623654
資料:http://www.csharpkit.com/apigateway.html
(3).其他網關框架:
A. Netflix Zuul +java實現
B. Kong nginx +lua腳本實現
C. Tyk go語言開發,收費版本
D. Ocelot aspnetcore開發的
5. Ocelot的原理
Ocelot是一堆的asp.net core middleware組成的一個管道。當它拿到請求之后會用一個request builder來構造一個HttpRequestMessage發到下游的真實服務器,等下游的服務返回response之后再由一個middleware將它返回的HttpResponseMessage映射到HttpResponse上。
(1).上游是什么:Ocelot自身就是上游(Upstream)
(2).下游是什么:Ocelot轉發給的(業務)服務器就是下游(Downstream)
二. 路由功能
架構圖:
1.路由的含義
Ocelot(即上游)按照匹配規則接收客戶端發送的請求 → 將客戶端請求轉換成業務服務器(即下游)的地址 → 調用下游服務,返回結果 → Ocelot再將下游服務的結果返回給客戶端.
2. 參數介紹
- Downstream 下游服務配置
- UpStream 上游服務配置
- Aggregates 服務聚合配置
- ServiceName, LoadBalancer, UseServiceDiscovery 配置服務發現
- AuthenticationOptions 配置服務認證
- RouteClaimsRequirement 配置Claims鑒權
- RateLimitOptions 限流配置
- FileCacheOptions 緩存配置
- QosOptions 服務質量與熔斷
- DownstreamHeaderTransform 頭信息轉發
3. 路由直接轉發指定的地址
(1).業務場景:
客戶端訪問網關 → 網關把請求直接轉發給"指定ip+端口"業務服務器 (該場景網關本身不配置Consul,直接轉發)
(2).業務編寫與測試:
A. 新建網關項目OcelotGateWay,通過Nuget安裝【Ocelot 16.0.1】程序集
B. 新建一個OcelotConfig.json的配置文件,屬性改為"始終復制",用於存放Ocelot的配置。
代碼如下:
{
"Routes": [
{
//轉發下游(業務服務器)的匹配規則
"DownstreamPathTemplate": "/api/{url}",
//下游請求類型
"DownstreamScheme": "http",
//下游的ip和端口,和上面的DownstreamPathTemplate匹配起來
"DownstreamHostAndPorts": [
{
"Host": "127.0.0.1",
"Port": 7001
}
],
//上游(即Ocelot)接收規則
"UpstreamPathTemplate": "/GoodsService/{url}",
//上游接收請求類型
"UpstreamHttpMethod": [ "Get", "Post" ]
},
{
"DownstreamPathTemplate": "/api/{url}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "127.0.0.1",
"Port": 7004
}
],
"UpstreamPathTemplate": "/OrderService/{url}",
"UpstreamHttpMethod": [ "Get", "Post" ]
}
]
}
剖析上述xml:
- DownstreamPathTemplate:下游路徑模板
- DownstreamScheme:下游服務http schema
- DownstreamHostAndPorts:下游服務的地址,如果使用LoadBalancer的話這里可以填多項
- UpstreamPathTemplate: 上游也就是用戶輸入的請求Url模板,會將這個請求轉發給下游,如上代碼,客戶端請求 :網關ip+端口/GoodsService/{url},會轉發給下游:127.0.0.1:7001/api/{url}
- UpstreamHttpMethod: 上游請求http方法,可使用數組
C. 在Program中通過AddJsonFile將上述json文件加載進來.
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) //配置相關 .ConfigureAppConfiguration((hostingContext, config) => { //1. 加載json文件 (配置后面兩個參數為true,當配置文件發生變化的時候,會自動更新加載,而不必重啟整個項目) config.AddJsonFile("OcelotConfig.json", optional: true, reloadOnChange: true); }) .ConfigureWebHostDefaults(webBuilder => { //添加命令行支持(寫在上面的Main里也可以) var config = new ConfigurationBuilder().AddCommandLine(args).Build(); webBuilder.UseStartup<Startup>(); });
D. 在Startup中進行注冊和使用,services.AddOcelot(); app.UseOcelot().Wait();
public void ConfigureServices(IServiceCollection services) { //1.注冊Ocelot var ocelot = services.AddOcelot(); services.AddControllers(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //1.使用Ocelot app.UseOcelot().Wait(); //這里不寫異步用法了 app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
E. 啟動項目,7001端口啟動GoodsService、7004端口啟動OrderService、7020端口啟動OcelotGateWay,指令如下:
【dotnet GoodsService.dll --urls="http://*:7001" --ip="127.0.0.1" --port=7001】 業務服務器地址
【dotnet OrderService.dll --urls="http://*:7004" --ip="127.0.0.1" --port=7004】 業務服務器地址
【dotnet OcelotGateWay.dll --urls="http://*:7020" --ip="127.0.0.1" --port=7020】 網關地址
F. PostMan測試
(1). Get測試: http://127.0.0.1:7020/GoodsService/Catalog/GetGoodById1?id=123,會將請求地址轉發給 http://127.0.0.1:7001/api/Catalog/GetGoodById1?id=123 ,請求成功。
(2). Post請求:http://127.0.0.1:7020/OrderService/Buy/pOrder1,會將請求地址轉發給 http://127.0.0.1:7004/api/Buy/pOrder1,請求成功。
三. 集成Consul
與Consul結合實現業務服務器的負載均衡(推薦用法)
架構圖:
1.業務背景
上述通過 Ocelot直接轉發給指定的 ip+端口,只是為了演示,實際場景中,比如OrderService這個業務服務器,會部署在多台服務器上進行分攤請求壓力,當然我可以利用Ocelot自身實現負載均衡,但不推薦,原因有二: ① Ocelot本身的負載均衡機制不完善 ② 每次增加或減少業務服務器,都需要改網關的配置文件,耦合性很強。
解決方案:Ocelot與Consul結合,客戶端訪問網關→網關通過ServiceName去Consul中找一個地址進行匹配訪問(Ocelot提供了多種算法去Consul中找地址)
2.業務編寫與測試
A. 通過Nuget安裝【Ocelot 16.0.1】程序集 和 【Ocelot.Provider.Consul 16.0.1】程序集
B. 新建一個OcelotConfig.json的配置文件,屬性改為"始終復制",用於存放Ocelot的配置.
配置分享:
//模式三:將Ocelot與consul結合處理,在consul中已經注冊業務服務器地址,在Ocelot端不需要再注冊了(推薦用法) { "Routes": [ { "DownstreamPathTemplate": "/api/{url}", "DownstreamScheme": "http", "ServiceName": "GoodsService", //Consul中的服務名稱 "LoadBalancerOptions": { "Type": "RoundRobin" //輪詢算法:依次調用在consul中注冊的服務器 }, "UseServiceDiscovery": true, //啟用服務發現(可以省略,因為會默認賦值) "UpstreamPathTemplate": "/GoodsService/{url}", "UpstreamHttpMethod": [ "Get", "Post" ] }, { "DownstreamPathTemplate": "/api/{url}", "DownstreamScheme": "http", "ServiceName": "OrderService", "LoadBalancerOptions": { "Type": "LeastConnection" //最小連接數算法 }, "UseServiceDiscovery": true, "UpstreamPathTemplate": "/OrderService/{url}", "UpstreamHttpMethod": [ "Get", "Post" ] } ], //下面是配置Consul的地址和端口 "GlobalConfiguration": { //對應Consul的ip和Port(可以省略,因為會默認賦值) "ServiceDiscoveryProvider": { "Host": "127.0.0.1", "Port": 8500 } } }
剖析配置:
LoadBalancer將決定負載均衡的算法
- LeastConnection – 將請求發往最空閑的那個服務器
- RoundRobin – 輪流發送
- NoLoadBalance – 總是發往第一個請求或者是服務發現
ServiceName(對應服務名), UseServiceDiscovery 啟用注冊發現(可省略),ServiceDiscoveryProvider 配置Consul的ip和端口。
C. 在Program中通過AddJsonFile將上述json文件加載進來. (代碼同上)
D. 在Startup中進行注冊和使用,services.AddOcelot().AddConsul(); app.UseOcelot().Wait();
代碼分享:
public void ConfigureServices(IServiceCollection services) { //1.注冊Ocelot和Consul services.AddOcelot().AddConsul(); services.AddControllers(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //1.使用Ocelot app.UseOcelot().Wait(); //這里不寫異步用法了 app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
E. 啟動項目
7001,7002,7003 端口啟動GoodsService、7004,7005,7006端口啟動OrderService、7020端口啟動OcelotGateWay
【dotnet GoodsService.dll --urls="http://*:7001" --ip="127.0.0.1" --port=7001】 業務服務器1地址
【dotnet GoodsService.dll --urls="http://*:7002" --ip="127.0.0.1" --port=7002】 業務服務器1地址
【dotnet GoodsService.dll --urls="http://*:7003" --ip="127.0.0.1" --port=7003】 業務服務器1地址
【dotnet OrderService.dll --urls="http://*:7004" --ip="127.0.0.1" --port=7004】 業務服務器2地址
【dotnet OrderService.dll --urls="http://*:7005" --ip="127.0.0.1" --port=7005】 業務服務器2地址
【dotnet OrderService.dll --urls="http://*:70046" --ip="127.0.0.1" --port=7006】 業務服務器2地址
【dotnet OcelotGateWay.dll --urls="http://*:7020" --ip="127.0.0.1" --port=7020】 網關地址
F. PostMan測試:
(1).Get測試: http://127.0.0.1:7020/GoodsService/Catalog/GetGoodById1?id=123, 會按照輪詢算法依次轉發給 :http://127.0.0.1:7001/api/Catalog/GetGoodById1?id=123,http://127.0.0.1:7002/api/Catalog/GetGoodById1?id=123,http://127.0.0.1:7003/api/Catalog/GetGoodById1?id=123,請求成功。
(2).Post請求:http://127.0.0.1:7020/OrderService/Buy/pOrder1 ,會根據最小連接數算法,轉發給7004 7005 7006連接數最小的業務服務器。
測試結果同上述路由轉發的圖
!
- 作 者 : Yaopengfei(姚鵬飛)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 如有錯誤,歡迎討論,請勿謾罵^_^。
- 聲 明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。