Ocelot簡易教程(四)之請求聚合以及服務發現
上篇文章給大家講解了Ocelot的一些特性并對路由進行了詳細的介紹,今天呢就大家一起來學習下Ocelot的請求聚合以及服務發現功能。希望能對大家有所幫助。
作者:依樂祝
原文位址:
https://www.cnblogs.com/yilezhu/p/9695639.html
請求聚合
Ocelot允許你聲明聚合路由,這樣你可以把多個正常的ReRoutes打包并映射到一個對象來對用戶端的請求進行響應。比如,你請求訂單資訊,訂單中又包含商品資訊,這裡就設計到兩個微服務,一個是商品服務,一個是訂單服務。如果不運用聚合路由的話,對于一個訂單資訊,用戶端可能需要請求兩次服務端。實際上這會造成服務端額外的開銷。這時候有了聚合路由後,你隻需要請求一次聚合路由,然後聚合路由會合并訂單跟商品的結果都一個對象中,并把這個對象響應給用戶端。使用Ocelot的此特性可以讓你很容易的實作前後端分離的架構。
為了實作Ocelot的請求功能,你需要在ocelot.json中進行如下的配置。這裡我們指定了了兩個正常的ReRoutes,然後給每個ReRoute設定一個Key屬性。最後我們再Aggregates節點中的ReRouteKeys屬性中加入我們剛剛指定的兩個Key進而組成了兩個ReRoutes的聚合。當然我們還需要設定UpstreamPathTemplate比對上遊的使用者請求,它的工作方式與正常的ReRoute類似。
注意:不要把Aggregates中UpstreamPathTemplate設定的跟ReRoutes中的UpstreamPathTemplate設定成一樣。
下面我們先上個執行個體例子先!示範代碼已經同步更新Github上。有興趣的朋友可以檢視源碼:
https://github.com/yilezhu/OcelotDemo在開始執行個體前先把我們的ocelot Nuget包更新到最新的12.0.0版本,當然你也可以不進行更新。這裡需要注意一下,如果你更新到12.0.0的版本的話,那麼你的用法會發生改變,需要傳入參數
config.AddOcelot()
config.AddOcelot(hostingContext.HostingEnvironment)
1.為了示範的需要這裡我們新增一個類庫項目,分别建立兩個類,一個是商品Good類,一個是訂單Order類(這裡隻是為了示範的需要,是以代碼很簡陋)如下所示:
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.如下所示:
這裡注意,跟上篇文章中的路由不同的是,這裡多了一個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
中填寫的數組就是上面步驟3中設定的
ReRouteKeys
屬性對應的值。
Key
- 我們分别運作起來三個項目,然後通路接口位址: http://localhost:1000/GetOrderDetail/1 會得到如下的聚合響應内容:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLzEDO3UjNzgjMx0CN5kjMycjM1EDNykDM4EDMy0CM1IzN3MTMvwVOwgTMwIzLcBTNyczNzEzLcd2bsJ2Lc12bj5ycn9Gbi52YugTMwIzZtl2Lc9CX6MHc0RHaiojIsJye.png)
格式化後代碼如下:
{
"Good":{
"Id":1,
"Content":"1的關聯的商品明細"
},
"Order":{
"Id":1,
"Content":"1的訂單明細"
}
}
Ocelot将始終使用聚合請求傳回内容類型application/json。還有需要注意的是聚合請求不會傳回404請求。如果兩個下遊都傳回404狀态碼的話,這裡聚合後的響應也不會傳回404,隻會傳回空的json串,拿上面的執行個體,如果兩個下遊都傳回404的話,那麼他的響應代碼類似下面這樣:{ "Good": , "Order": }
如果下遊服務傳回404,則聚合将僅為該下遊服務傳回任何内容。即使所有下遊都傳回404,它也不會将聚合響應更改為404。
服務發現
Ocelot允許您指定服務發現提供程式,并将使用它來查找Ocelot将請求轉發到的下遊服務的主機和端口。目前,這僅在GlobalConfiguration部分中受支援,這意味着相同的服務發現提供程式将用于為ReRoute級别指定ServiceName的所有ReRoutes。
Consul
在使用Consul前你首先要做的就是安裝在Ocelot中提供Consul支援的NuGet包
Install-Package Ocelot.Provider.Consul
然後将下面的内容添加在ConfigureServices方法中
services.AddOcelot()//注入Ocelot服務
.AddConsul();
GlobalConfiguration中需要加入以下内容。如果您未指定主機和端口,則将使用Consul預設值。
"ServiceDiscoveryProvider": {
"Host": "localhost",
"Port": 8500,
"Type": "Consul"
}
注意:如果你采用這種方式來自動加載ocelot配置檔案的方式,那麼你需要建立一個ocelot.global.json檔案,然後加入上面的配置:如下所示:
AddOcelot()
{ "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部分中的産品服務的速率限制設定。
GitHub位址
Ocelot簡易教程目錄
總結
本文接着上篇文章進行了Ocelot請求聚合功能以及服務發現功能的介紹,并且對Ocelot動态路由功能也進行了簡單的闡述。對于請求聚合這塊進行了相關執行個體代碼的示範,并已經更新到Github上面了!希望能對大家有所幫助!