在上篇.Net微服務實踐(三)[網關]:Ocelot配置路由和請求聚合中咱們介紹了Ocelot的配置,主要特性路由以及服務聚合。接下來,咱們會介紹Ocelot的限流、熔斷、緩存以及負載均衡。html
咱們先來看限流的配置git
Reroute節點中的配置以下:github
{ "DownstreamPathTemplate": "/api/orders", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 } ], "UpstreamPathTemplate": "/api/orders", "UpstreamHttpMethod": [ "Get" ], "RateLimitOptions": { "ClientWhitelist": [], "EnableRateLimiting": true, "Period": "10m", "PeriodTimespan": 3, "Limit": 1 } }
GlobalConfiguration中的配置以下:算法
"GlobalConfiguration": { "BaseUrl": "http://localhost:5000", //限流 "RateLimitOptions": { "QuotaExceededMessage": "您的請求量超過了配額1/10分鐘", "HttpStatusCode": 999 } }
配置說明json
在Reroute和GlobalConfiguration節點中添加了RateLimitOptions節點api
示例說明
客戶端在10分鐘以內只容許請求一次http://localhost:5000/api/orders,在請求以後3秒鐘以後能夠重試緩存
驗證服務器
修改配置,運行示例程序,app
訪問http://localhost:5000/api/orders,第一次能夠正常獲取返回結果,再次訪時,顯示"您的請求量超過了配額1/10分鐘, 而且response狀態碼是999負載均衡
PeriodTimespan的驗證
修改Period爲1s, 修改PeriodTimespan爲10,這樣當前的配置是1秒中容許一個請求,10秒後才能重試。 再次運行示例程序。
訪問http://localhost:5000/api/orders,第一次能夠正常獲取返回結果, 等待兩秒,再次訪問,你們想一下,這個時候,會不會返回正常結果(已通過了兩秒)。這時仍是返回999,爲何? 由於儘管配額上是容許的,可是由於配置是客戶端10秒之後才能重試,而這時只等待了2秒,因此仍是返回999.
Ocelot的熔斷使用了Polly來實現,在OcelotGateway項目添加Polly包
注入Polly
services .AddOcelot() .AddPolly();
修改配置
{ "DownstreamPathTemplate": "/api/orders", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 } ], "UpstreamPathTemplate": "/api/orders", "UpstreamHttpMethod": [ "Get" ], "QoSOptions": { "ExceptionsAllowedBeforeBreaking": 2, "DurationOfBreak": 5000, "TimeoutValue": 2000 } }
配置說明
在Reroute節點中添加了QoSOptions節點
示例說明
當訪問http://localhost:5000/api/orders出現2次異常後,服務熔斷5秒,若是服務響應超過2秒,也觸發熔斷條件
驗證
場景一:服務宕機
修改配置,只啓動網關,不啓動oder api,訪問http://localhost:5000/api/orders,第一次有響應耗時,返回500,第二次也有響應耗時,返回500. 第三次則快速返回503 Service Unavalible, 服務熔斷了。
場景二:超時
修改配置
修改api/orders代碼,等待3秒
// GET: api/orders [Route("api/orders")] [HttpGet] public IEnumerable<string> Get() { Task.Delay(3000).Wait(); return new string[] { "劉明的訂單", "王天的訂單" }; }
啓動網關,啓動order-api,訪問http://localhost:5000/api/orders,返回503
// GET: api/orders [Route("api/orders")] [HttpGet] public IEnumerable<string> Get() { throw new Exception("獲取全部訂單出錯"); }
啓動網關,啓動order-api,訪問http://localhost:5000/api/orders, 不觸發熔斷
緩存使用了CacheManageer來實現,添加CacheManager包
Install-Package Ocelot.Cache.CacheManager
注入緩存組件
services.AddOcelot() .AddCacheManager(x => { x.WithDictionaryHandle(); });
Ocelot.json配置文件修改
{ "DownstreamPathTemplate": "/api/orders", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 } ], "UpstreamPathTemplate": "/api/orders", "UpstreamHttpMethod": [ "Get" ], "FileCacheOptions": { "TtlSeconds": 60, "Region": "orders" } }
緩存是根據 downstream service 的URL來緩存的
配置說明
在Reroute節點中添加了FileCacheOptions節點
示例說明
當訪問http://localhost:5000/api/orders後,結果會緩存60秒,在緩存有效期內即便原始的order api的返回結果發生變化,經過網關請求時,仍是會返回緩存的結果。
驗證
"劉明的訂單", "王天的訂單"
[Route("api/orders")] [HttpGet] public IEnumerable<string> Get() { return new string[] { "帥的訂單", "個人訂單" }; }
"劉明的訂單", "王天的訂單"
由於結果被緩存了
"帥的訂單", "個人訂單"
由於緩存有效期已通過了
Ocelot容許在上游服務的request和下游服務的response的header中添加、替換信息
配置以下:
{ "DownstreamPathTemplate": "/api/shopping-carts", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 } ], "DownstreamHeaderTransform": { "devops": "rdc" }, "UpstreamPathTemplate": "/api/shopping-carts", "UpstreamHttpMethod": [ "Get" ], "UpstreamHeaderTransform": { "lakin": "rdc", "CI": "msbuild, jenkins", "Location": "http://localhost:5001, {BaseUrl}" } }
配置說明
在Reroute節點中添加了DownstreamHeaderTransform節點和UpstreamHeaderTransform節點
"DownstreamHeaderTransform": { "devops": "rdc" }
說明:在下游服務的response中添加一個header, key是devops, value是rdc
"UpstreamHeaderTransform": { "lakin": "rdc", "CI": "msbuild, jenkins", "Location": "http://localhost:5001, {BaseUrl}" }
示例說明
當訪問http://localhost:5000/api/orders後,結果會緩存60秒,在緩存有效期內即便原始的order api的返回結果發生變化,經過網關請求時,仍是會返回緩存的結果。
驗證
// GET: api/shopping-carts [Route("api/shopping-carts")] [HttpGet] public IEnumerable<string> Get() { Console.WriteLine($"開始打印header信息"); foreach (var item in this.Request.Headers) { Console.WriteLine($"{item.Key} - {item.Value}"); } Console.WriteLine($"打印header信息完成"); return new string[] { "洗髮水", "無人機" }; }
"CI": "msbuild", "Location": "http://localhost:5001"
開始打印header信息CI lakin - rdc CI - jenkins Location - http://localhost:5000 打印header信息完成
devops - rdc
Ocelot容許在路由時轉化HTTP方法
{ "DownstreamPathTemplate": "/api/shopping-carts", "DownstreamScheme": "http", "DownstreamHttpMethod": "POST", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 } ], "UpstreamPathTemplate": "/api/shopping-carts", "UpstreamHttpMethod": [ "Get" ] }
示例說明
上述示例中,將GET /api/shopping-carts 路由到 POST /api/shopping-carts, 將GET轉換成了POST
適用場景:例若有些已經存在的的API,由於某些歷史緣由都是用POST,在經過網關對外提供服務時,就能夠按照標準API進行轉換
驗證
"洗髮水", "無人機"
[Route("api/shopping-carts")] [HttpPost] public string Post() { return "添加商品到購物車成功"; }
添加商品到購物車成功
Ocelot內置了負載均衡,咱們先來看配置
{ "DownstreamPathTemplate": "/api/orders", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 }, { "Host": "localhost", "Port": 6001 } ], "UpstreamPathTemplate": "/api/orders", "UpstreamHttpMethod": [ "Get" ], "LoadBalancerOptions": { "Type": "RoundRobin" } }
配置說明
在DownstreamHostAndPorts指指定多個服務地址
在Reroute節點中添加LoadBalancerOptions,這是負載均衡的配置節點,其中Type屬性指定了負載均衡的算法, 它有以下幾個值:
驗證
[Route("api/orders")] [HttpGet] public IEnumerable<string> Get() { return new string[] { "劉明的訂單", "王天的訂單" }; }
[Route("api/orders")] [HttpGet] public IEnumerable<string> Get() { return new string[] { "帥的訂單", "個人訂單" }; }
第一次的結果是
"劉明的訂單", "王天的訂單"
第二次的結果是
"帥的訂單", "個人訂單"
第三次的結果是
"劉明的訂單", "王天的訂單"
Ocelot自己是一組中間件,它也提供了方式來注入和重寫其中的某些中間件:
下面是注入PreErrorResponderMiddleware中間件的代碼示例:
//注入中間件 var configuration = new OcelotPipelineConfiguration { PreErrorResponderMiddleware = async (ctx, next) => { ctx.HttpContext.Request.Headers.Add("myreq", "ocelot-request"); await next.Invoke(); } }; app.UseOcelot(configuration).Wait();
注意: Ocelot也是一組中間件,因此能夠在Ocelot中間件以前,按常規方式添加任何中間件, 可是不能在Ocelot中間件以後添加,由於Ocelot沒有調用 next
Ocelot提供了一組後臺管理的API, 從前三篇文章能夠看出,Ocelot主要也就是配置文件的管理,因此API主要也就是管理配置
本篇咱們介紹了Ocelot的限流、熔斷、緩存、負載均衡以及其餘一些特性。到目前爲止,Ocelot的基本配置和功能都已經介紹完了。接下里咱們會結合consul來介紹服務發現,以及Ocelot和Consul的集成。