前言:
上一篇 介紹了Ocelot閘道器和認證服務的結合使用,本篇繼續介紹Ocelot相關請求聚合和Ocelot限流
一、請求聚合
Ocelot允許宣告聚合路由,這樣可以把多個正常的Routes打包並對映到一個物件來對客戶端的請求進行響應。
例如:在獲取訂單記錄時,也需要檢視訂單中對應的商品資訊,這裡的資料就來源於兩個微服務:訂單服務、商品服務。如果不使用聚合路由時,對於現實一個訂單資訊時,客戶端需要呼叫兩次服務請求,實際上會造成服務端額外的效能消耗。這是如果配置了聚合路由時,客戶端只需要請求一次聚合路由,然後聚合路由會合並訂單服務和商品服務的請求結果到一個物件中,並返回給客戶端。使用Ocelot的此特性可以讓你很容易的實現前後端分離的架構。接下來我們就來驗證該功能的實現。
在ocelot.json中進行如下配置:
1、為每個Route設定一個Key屬性:如:"Key": "Catalog"
2、在ocelot.json中新增Aggregates節點,並指定RouteKeys中指定1中設定的Key值組成的陣列,並設定UpstreamPathTemplate匹配上游使用者請求;它的工作方式和正常的Route類似。
調整後如下:
{ "Aggregates": [ { "RouteKeys": [ "Catalog", "Ordering" ], "UpstreamPathTemplate": "/GetOrderDetail/{id}" } ], "GlobalConfiguration": { }, "Routes": [ { "DownstreamPathTemplate": "/api/Values/{id}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5332 } ], "UpstreamPathTemplate": "/Catalog/{id}", "UpstreamHttpMethod": [ "Get", "Post" ], "LoadBalancerOptions": { "Type": "RoundRobin" }, "Key": "Catalog" }, { "DownstreamPathTemplate": "/api/Values/{id}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5331 } ], "UpstreamPathTemplate": "/Ordering/{id}", "UpstreamHttpMethod": [ "Get", "Post" ], "LoadBalancerOptions": { "Type": "RoundRobin" }, "Key": "Ordering" } ] }
3、如圖調整專案程式碼:返回不同結果
4、訪問設定的聚合地址結果如下:
返回結果為設定的Key組合的資料結構。
5、如果服務出現異常會怎麼樣:
a) 如果當某個服務出現異常會返回什麼呢?接下來做個驗證,修改訂單服務返回結果:
public IActionResult Get(int id) { throw new Exception("模擬異常"); }
如圖所示返回的結果和正常是結構是相同的,只是Ordering返回的是異常資訊;
b) 如果某個服務當機,回得到什麼結果呢?接下來停止了Ordering服務訪問結果如下,得到502錯誤
6、如果預設的聚合返回的結果資料結構不是我們想要的,想要修改怎麼辦?答案是使用自定義聚合
a)新增一個自動以聚合器FakeDefinedAggregator, 必須實現IDefinedAggregator介面。這個聚合器的功能很簡單,就是將兩個聚合請求的結果,用逗號拼接起來返回
public class FakeDefinedAggregator : IDefinedAggregator { public FakeDefinedAggregator() { } public async Task<DownstreamResponse> Aggregate(List<HttpContext> responses) { List<string> result = new List<string>(); foreach (var item in responses) { byte[] tmp = new byte[item.Response.Body.Length]; await item.Response.Body.ReadAsync(tmp, 0, tmp.Length); var val = Encoding.UTF8.GetString(tmp); result.Add(val); } var merge = string.Join(";", result.ToArray()); List<Header> headers = new List<Header>(); return new DownstreamResponse(new StringContent(merge), HttpStatusCode.OK, headers, "some reason"); } }
b)註冊自定義聚合器
services.AddOcelot()
.AddSingletonDefinedAggregator<FakeDefinedAggregator>();
c)修改ocelot.json配置檔案
"Aggregates": [ { "ReRouteKeys": [ "Orders", "Products" ], "UpstreamPathTemplate": "/GetOrderDetail/{id}",
"Aggregator": "FakeDefinedAggregator" } ]
d)執行結果:
{"id":1,"name":"Api.Catalog1"};{"id":1,"name":"Api.Ordering"}}
二、限流
1、修改Route節點中的新增如下節點:
"RateLimitOptions": { "ClientWhitelist": [], "EnableRateLimiting": true, "Period": "10m", "PeriodTimespan": 3, "Limit": 1 }
2、在GlobalConfiguration新增如下節點:
//限流 "RateLimitOptions": { "QuotaExceededMessage": "您的請求量超過了配額1/10分鐘", "HttpStatusCode": 999 }
3、配置說明:
在Route和GlobalConfiguration節點中新增了RateLimitOptions節點 ClientWhitelist - 白名單,也就是不受限流控制的客戶端 EnableRateLimiting - 是否開啟限流 Period & Limit - 在一段時間內允許的請求次數 PeriodTimespan - 客戶端的重試間隔數,也就是客戶端間隔多長時間可以重試 QuotaExceededMessage - 限流以後的提示資訊 HttpStatusCode - 超出配額時,返回的http狀態碼
4、配置說明:
客戶端在10分鐘之內只允許請求一次,在請求之後3秒鐘之後可以重試
總結:
1、請求聚合需要為每個Route設定一個Key,並設定Aggregates節點指定需要的RouteKeys。
2、請求聚合支援自定義設定返回結果:實現IDefinedAggregator介面,並註冊自定義聚合器;
3、在需要對伺服器請求進行限流時,Ocelot也能很好的支援
後續:
後續將對Consul介紹,並結合Ocelot使用。