上篇文章給你們講解了Ocelot的一些特性並對路由進行了詳細的介紹,今天呢就你們一塊兒來學習下Ocelot的請求聚合以及服務發現功能。但願能對你們有所幫助。html
做者:依樂祝
原文地址:http://www.javashuo.com/article/p-htmfesyx-em.htmlgit
Ocelot容許你聲明聚合路由,這樣你能夠把多個正常的ReRoutes打包並映射到一個對象來對客戶端的請求進行響應。好比,你請求訂單信息,訂單中又包含商品信息,這裏就設計到兩個微服務,一個是商品服務,一個是訂單服務。若是不運用聚合路由的話,對於一個訂單信息,客戶端可能須要請求兩次服務端。實際上這會形成服務端額外的開銷。這時候有了聚合路由後,你只須要請求一次聚合路由,而後聚合路由會合並訂單跟商品的結果都一個對象中,並把這個對象響應給客戶端。使用Ocelot的此特性可讓你很容易的實現先後端分離的架構。
爲了實現Ocelot的請求功能,你須要在ocelot.json中進行以下的配置。這裏咱們指定了了兩個正常的ReRoutes,而後給每一個ReRoute設置一個Key屬性。最後咱們再Aggregates節點中的ReRouteKeys屬性中加入咱們剛剛指定的兩個Key從而組成了兩個ReRoutes的聚合。固然咱們還須要設置UpstreamPathTemplate匹配上游的用戶請求,它的工做方式與正常的ReRoute相似。github
注意:不要把Aggregates中UpstreamPathTemplate設置的跟ReRoutes中的UpstreamPathTemplate設置成同樣。算法
下面咱們先上個實例例子先!演示代碼已經同步更新Github上。有興趣的朋友能夠查看源碼:https://github.com/yilezhu/OcelotDemo數據庫
在開始實例前先把咱們的ocelot Nuget包升級到最新的12.0.0版本,固然你也能夠不進行升級。這裏須要注意一下,若是你升級到12.0.0的版本的話,那麼你
config.AddOcelot()
的用法會發生改變,須要傳入參數config.AddOcelot(hostingContext.HostingEnvironment)
json
1.爲了演示的須要這裏咱們新增一個類庫項目,分別新建兩個類,一個是商品Good類,一個是訂單Order類(這裏只是爲了演示的須要,因此代碼很簡陋)以下所示:c#
public class Goods { public int Id { get; set; } public string Content { get; set; } } public class Orders { public int Id { get; set; } public string Content { get; set; } }
接下來咱們給OrderApi以及GoodApi分別新建一個控制器,並返回相應的實體。以下所示:後端
//GoodApi項目中 [Route("api/[controller]")] [ApiController] public class GoodController : ControllerBase { // GET api/Good/5 [HttpGet("{id}")] public ActionResult<string> Get(int id) { var item = new Goods { Id = id, Content = $"{id}的關聯的商品明細", }; return JsonConvert.SerializeObject(item); } } //OrderApi項目中 [Route("api/[controller]")] [ApiController] public class OrderController : ControllerBase { // GET api/Order/5 [HttpGet("{id}")] public ActionResult<string> Get(int id) { var item = new Orders { Id=id, Content=$"{id}的訂單明細", }; return JsonConvert.SerializeObject(item); } }
接下來咱們分別在ocelot.good.json以及ocelot.order.json中新增一個路由,並給出Keys.以下所示:api
這裏注意,跟上篇文章中的路由不一樣的是,這裏多了一個Key屬性。數組
//ocelot.good.json { "DownstreamPathTemplate": "/api/Good/{id}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 1001 } ], "UpstreamPathTemplate": "/good/{id}", "UpstreamHttpMethod": [ "Get", "Post" ], "Key": "Good", "Priority": 2 } //ocelot.order.json { "DownstreamPathTemplate": "/api/Order/{id}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 1002 } ], "UpstreamPathTemplate": "/order/{id}", "UpstreamHttpMethod": [ "Get", "Post" ], "Key": "Order", "Priority": 2 }
在ocelot.all.json中加入聚合配置,以下所示:
"Aggregates": [ { "ReRouteKeys": [ "Good", "Order" ], "UpstreamPathTemplate": "/GetOrderDetail/{id}" } ]
注意:這裏
Aggregates
跟ReRoutes
同級,ReRouteKeys
中填寫的數組就是上面步驟3中設置的Key
屬性對應的值。
咱們分別運行起來三個項目,而後訪問接口地址:http://localhost:1000/GetOrderDetail/1 會獲得以下的聚合響應內容:
格式化後代碼以下:
{ "Good":{ "Id":1, "Content":"1的關聯的商品明細" }, "Order":{ "Id":1, "Content":"1的訂單明細" } }
眼尖的朋友可能已經猜到了。聚合路由返回的內容就是json串。json串由ReRouteKeys
組成,每一個Key
的內容就是具體下游響應的內容了!實例代碼已經同步更新到Github上,地址:https://github.com/yilezhu/OcelotDemo
Ocelot將始終使用聚合請求返回內容類型application/json。還有須要注意的是聚合請求不會返回404請求。若是兩個下游都返回404狀態碼的話,這裏聚合後的響應也不會返回404,只會返回空的json串,拿上面的實例,若是兩個下游都返回404的話,那麼他的響應代碼相似下面這樣:
{ "Good": , "Order": }
若是下游服務返回404,則聚合將僅爲該下游服務返回任何內容。即便全部下游都返回404,它也不會將聚合響應更改成404。
Ocelot容許您指定服務發現提供程序,並將使用它來查找Ocelot將請求轉發到的下游服務的主機和端口。目前,這僅在GlobalConfiguration部分中受支持,這意味着相同的服務發現提供程序將用於爲ReRoute級別指定ServiceName的全部ReRoutes。
在使用Consul前你首先要作的就是安裝在Ocelot中提供Consul支持的NuGet包
Install-Package Ocelot.Provider.Consul
而後將下面的內容添加在ConfigureServices方法中
services.AddOcelot()//注入Ocelot服務 .AddConsul();
GlobalConfiguration中須要加入如下內容。若是您未指定主機和端口,則將使用Consul默認值。
"ServiceDiscoveryProvider": { "Host": "localhost", "Port": 8500, "Type": "Consul" }
注意:若是你採用
AddOcelot()
這種方式來自動加載ocelot配置文件的方式,那麼你須要新建一個ocelot.global.json文件,而後加入上面的配置:以下所示:{ "GlobalConfiguration": { "ServiceDiscoveryProvider": { "Host": "localhost", "Port": 8500, "Type": "Consul" } } }
而後從新運行dotnet run命令會自動合併配置信息到Ocelot.json中,生成的對應內容以下: ```C# "ServiceDiscoveryProvider": { "Host": "localhost", "Port": 8500, "Type": "Consul", "Token": null, "ConfigurationKey": null, "PollingInterval": 0 }這個上篇文章中已經進行了相關的介紹。
爲了告訴Ocelot ReRoute是爲其主機和端口使用服務發現提供程序,您必須在下游請求時添加要使用的ServiceName和負載均衡器。目前,Ocelot可使用RoundRobin和LeastConnection算法。若是未指定負載均衡器,則Ocelot將不會對請求進行負載均衡。
{ "DownstreamPathTemplate": "/api/posts/{postId}", "DownstreamScheme": "https", "UpstreamPathTemplate": "/posts/{postId}", "UpstreamHttpMethod": [ "Put" ], "ServiceName": "product", "LoadBalancerOptions": { "Type": "LeastConnection" }, }
設置此項後,Ocelot將從服務發現提供程序中查找下游主機和端口,並跨任何可用服務進行負載平衡請求。
做者的想法是在使用服務發現提供程序時啓用動態路由。在此模式下,Ocelot將使用上游路徑的第一個段來與服務發現提供程序一塊兒查找下游服務。
例如,使用https://api.yilezhu.cn/product/products 等網址調用ocelot 。Ocelot將採用產品路徑的第一部分product
,並將其用做在Consul中查找服務的Key。若是consul返回一個服務,Ocelot將使用從consul返回的主機和端口以及剩餘路徑段組合後的Url來進行請求的響應。,如:http:// hostfromconsul:portfromconsul/products。Ocelot將正常向下游URL轉發查詢字符串。即query
要啓用動態路由,您須要在配置中保留0個ReRoutes。目前您沒法混合動態和配置ReRoutes。除此以外,您還須要指定上面概述的Service Discovery提供程序詳細信息和下游http / https方案做爲DownstreamScheme。
除此以外,您還能夠設置RateLimitOptions,QoSOptions,LoadBalancerOptions和HttpHandlerOptions,DownstreamScheme(您可能但願在https上調用Ocelot,但能夠經過http與私有服務進行通訊),這些將應用於全部動態ReRoutes。
配置可能看起來像:
{ "ReRoutes": [], "Aggregates": [], "GlobalConfiguration": { "RequestIdKey": null, "ServiceDiscoveryProvider": { "Host": "localhost", "Port": 8500, "Type": "Consul", "Token": null, "ConfigurationKey": null }, "RateLimitOptions": { "ClientIdHeader": "ClientId", "QuotaExceededMessage": null, "RateLimitCounterPrefix": "ocelot", "DisableRateLimitHeaders": false, "HttpStatusCode": 429 }, "QoSOptions": { "ExceptionsAllowedBeforeBreaking": 0, "DurationOfBreak": 0, "TimeoutValue": 0 }, "BaseUrl": null, "LoadBalancerOptions": { "Type": "LeastConnection", "Key": null, "Expiry": 0 }, "DownstreamScheme": "http", "HttpHandlerOptions": { "AllowAutoRedirect": false, "UseCookieContainer": false, "UseTracing": false } } }
Ocelot還容許您設置DynamicReRoutes,容許您爲每一個下游服務設置速率限制規則。若是您有一個產品和搜索服務,而且您但願對另外一個進行速率限制,則此功能很是有用。這方面的一個例子以下。
{ "DynamicReRoutes": [ { "ServiceName": "product", "RateLimitRule": { "ClientWhitelist": [], "EnableRateLimiting": true, "Period": "1s", "PeriodTimespan": 1000.0, "Limit": 3 } } ], "GlobalConfiguration": { "RequestIdKey": null, "ServiceDiscoveryProvider": { "Host": "localhost", "Port": 8523, "Type": "Consul" }, "RateLimitOptions": { "ClientIdHeader": "ClientId", "QuotaExceededMessage": "", "RateLimitCounterPrefix": "", "DisableRateLimitHeaders": false, "HttpStatusCode": 428 } "DownstreamScheme": "http", } }
此配置意味着若是您在/product/上進入Ocelot請求,則動態路由將啓動,而且ocelot將使用針對DynamicReRoutes部分中的產品服務的速率限制設置。
https://github.com/yilezhu/OcelotDemo
本文接着上篇文章進行了Ocelot請求聚合功能以及服務發現功能的介紹,而且對Ocelot動態路由功能也進行了簡單的闡述。對於請求聚合這塊進行了相關實例代碼的演示,並已經更新到Github上面了!但願能對你們有所幫助!