Ocelot(五)- 流量限制、服務質量

Ocelot(五)- 流量限制、服務質量

做者:markjiang7m2
原文地址:http://www.javashuo.com/article/p-gfqlqute-cu.html
源碼地址:https://gitee.com/Sevenm2/OcelotDemohtml

本文是我關於Ocelot系列文章的第五篇,流量限制、服務質量。Ocelot容許針對具體的服務接口進行流量限制,以便下游服務不會過載而影響響應速度。服務質量則是Ocelot根據下游服務響應的結果作出判斷,當超過必定次數的響應失敗時,Ocelot認爲該服務不可用,自動產生熔斷,在必定的時間範圍內再也不向該服務轉發請求,同時Ocelot也支持自定義的請求超時時間,當下遊響應超過設定的時間,會認爲該服務響應失敗。git

關於更多的Ocelot功能介紹,能夠查看個人系列文章github

本文中涉及案例的完整代碼均可以從個人代碼倉庫進行下載。算法

案例六 流量限制

Ocelot支持流量限制,只要在路由中添加RateLimitOptions配置便可shell

"RateLimitOptions": {
    "ClientWhiteList": [
        "markadmin"
    ],
    "EnableRateLimiting": true,
    "Period": "1m",
    "PeriodTimespan": 30,
    "Limit": 5
}
  • ClientWhiteList:數組,在請求頭中包含ClientId=xxx的請求不受限流控制,其中ClientId這個key能夠修改,xxx表示配置的白名單。
  • EnableRateLimiting:是否啓用限流
  • Period:限流控制的時間週期,輸入單位支持s(秒), m(分), h(時), d(天)
  • PeriodTimespan:恢復等待時間,當訪問超過限流限制的次數後,須要等待的時間,單位爲s,如當一分鐘內訪問超過5次,就須要等待30秒後,訪問纔會從新有效
  • Limit:一個時間週期內容許訪問的最大次數。

下面來看案例,在ReRoutes中添加一組路由c#

{
    "DownstreamPathTemplate": "/api/ocelot/{postId}",
    "DownstreamScheme": "http",
    "DownstreamHostAndPorts": [
    {
        "Host": "localhost",
        "Port": 8001
    }
    ],
    "UpstreamPathTemplate": "/ocelot/ratelimit/{postId}",
    "UpstreamHttpMethod": [ "Get" ],
    "Priority": 2,
    "RateLimitOptions": {
    "ClientWhiteList": [
        "markadmin"
    ],
    "EnableRateLimiting": true,
    "Period": "1m",
    "PeriodTimespan": 30,
    "Limit": 5
    }
}

在這裏我只是添加多了一組路由,但下游服務接口是重用了以前使用過的接口,流量限制部分配置上面已經介紹過了。下面運行來看結果。api

當我第一次訪問http://localhost:4727/ocelot/ratelimit/5的時候,獲得了正常的返回結果數組

Ocelot_043_ratelimit_request1

並且,在請求頭能夠看到流量限制的相關信息負載均衡

Ocelot_047_ratelimit_request1header

而後,我又很快地繼續發出請求,能夠看到,當我第六次發出請求的時候,獲得了429 To Many Requests的狀態async

Ocelot_044_ratelimit_request6

而此時的請求頭信息也會不同,這裏能夠看到Retry-After →28,意思是在28秒後能夠恢復請求

Ocelot_048_ratelimit_request6header

這證實,咱們的Ocelot網關流量限制的做用起效了,並且與咱們的配置一致。
在等待30秒以後,我從新發出請求,又獲得了正常的返回結果

Ocelot_045_ratelimit_request7

當我在請求頭中加上[ClientId]=markadmin後,清空Postman的請求記錄,從新開始發出請求,不管請求多少次,Ocelot也不會對個人訪問進行限流

Ocelot_046_ratelimit_nolimit

這裏對於PeriodTimespan(恢復等待時間)的算法,我卻是有點疑問的。我一開始的理解是,基於上面案例的配置,當一分鐘內訪問超過5次時,就須要等待Period + PeriodTimespan,也就是從第一個有效請求開始算起,一分半鐘以後Ocelot纔會從新正常轉發請求,可是我作了幾回重複實驗,獲得的結果都是:當一分鐘內訪問到第1次時,Ocelot開始進入PeriodTimespan時間內的倒計時,也就是實際的重置時間爲PeriodTimespan

爲了更加明確地驗證這個問題,我使用OcelotConsole項目進行測試。
首先,修改路由配置以下:

{
    "DownstreamPathTemplate": "/api/ocelot/{postId}",
    "DownstreamScheme": "http",
    "DownstreamHostAndPorts": [
    {
        "Host": "localhost",
        "Port": 8001
    }
    ],
    "UpstreamPathTemplate": "/ocelot/ratelimit/{postId}",
    "UpstreamHttpMethod": [ "Get" ],
    "Priority": 2,
    "RateLimitOptions": {
    "ClientWhiteList": [
        "markadmin"
    ],
    "EnableRateLimiting": true,
    "Period": "1m",
    "PeriodTimespan": 10,
    "Limit": 5
    }
}

而後,在OcelotConsole項目中添加代碼以下:

public static async Task Main(string[] args)
{
    using (var client = new HttpClient())
    {
        for (var i = 0; i < 100; i++)
        {
            Console.WriteLine(DateTime.Now);

            var result = await client.GetAsync("http://localhost:4727/ocelot/ratelimit/5");
            Console.WriteLine($"{result.StatusCode}, {result.Content.ReadAsStringAsync().Result}");
            System.Threading.Thread.Sleep(1000);
        }
        Console.Read();
    }
}

每隔1s就發出一次請求,運行,在命令窗口獲得如下輸出:

2019/6/3 13:33:31
OK, This is from localhost:8001, path: /api/ocelot/5
2019/6/3 13:33:32
OK, This is from localhost:8001, path: /api/ocelot/5
2019/6/3 13:33:33
OK, This is from localhost:8001, path: /api/ocelot/5
2019/6/3 13:33:34
OK, This is from localhost:8001, path: /api/ocelot/5
2019/6/3 13:33:35
OK, This is from localhost:8001, path: /api/ocelot/5
2019/6/3 13:33:36
TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
2019/6/3 13:33:37
TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
2019/6/3 13:33:38
TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
2019/6/3 13:33:39
TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
2019/6/3 13:33:40
TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
2019/6/3 13:33:41
OK, This is from localhost:8001, path: /api/ocelot/5
2019/6/3 13:33:43
OK, This is from localhost:8001, path: /api/ocelot/5
2019/6/3 13:33:44
OK, This is from localhost:8001, path: /api/ocelot/5
2019/6/3 13:33:45
OK, This is from localhost:8001, path: /api/ocelot/5
2019/6/3 13:33:46
OK, This is from localhost:8001, path: /api/ocelot/5
2019/6/3 13:33:47
TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
2019/6/3 13:33:48
TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
2019/6/3 13:33:49
TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
2019/6/3 13:33:50
TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
2019/6/3 13:33:51
TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.

而後,我又經過修改參數,得出以下結果:

  • PeriodTimespan=10, Limit=5:5個成功,5個失敗
  • PeriodTimespan=10, Limit=6:6個成功,4個失敗
  • PeriodTimespan=20, Limit=5:5個成功,15個失敗
  • PeriodTimespan=30, Limit=5:5個成功,25個失敗

彷佛都是與我前面獲得的結論相同,與官方文檔不一致。
我在GitHub上提了一個issue:https://github.com/ThreeMammals/Ocelot/issues/910,期待能獲得答覆。

流量限制的全局配置

"RateLimitOptions": {
    "DisableRateLimitHeaders": true,
    "QuotaExceededMessage": "Customize Tips!",
    "HttpStatusCode": 999,
    "ClientIdHeader": "Test"
}
  • DisableRateLimitHeaders:當設爲true時,請求頭中就不會輸出流量限制的相關信息,默認值:"false"
  • QuotaExceededMessage:當請求數量超出流量限制時,輸出的信息,默認值:"API calls quota exceeded! maximum admitted {Limit} per {Period}."
  • HttpStatusCode:當請求數量超出流量限制時,輸出的狀態碼,默認值:"429"
  • ClientIdHeader:標識爲白名單中的客戶端的請求頭key,默認值:"ClientId"

Ocelot_049_ratelimit_request1noheader

Ocelot_050_ratelimit_request6status

Ocelot_051_ratelimit_whitelist

案例七 服務質量

Ocelot支持服務質量與熔斷,意味着當下遊服務不可用時,Ocelot會進行自動熔斷,再也不將請求轉發給該下游服務。來看看配置

"QoSOptions": {
    "ExceptionsAllowedBeforeBreaking":3,
    "DurationOfBreak":3000,
    "TimeoutValue":5000
}
  • ExceptionsAllowedBeforeBreaking:容許異常次數,當Ocelot轉發給該下游服務連續出現異常次數達到該數字時,Ocelot會進行自動熔斷,一段時間內再也不向該下游服務轉發請求
  • DurationOfBreak:熔斷時間,單位爲ms(毫秒),持續多長時間不向該下游服務轉發請求
  • TimeoutValue:服務質量配置項,超時時間,單位爲ms(毫秒),當Ocelot向下遊服務轉發請求多長時間後,自動認爲該請求超時

ExceptionsAllowedBeforeBreaking 必須跟 DurationOfBreak一塊兒使用,TimeoutValue能夠單獨使用。

首先須要安裝Polly支持程序,經過Nuget搜索Ocelot.Provider.Polly或者經過如下命令安裝

Install-Package Ocelot.Provider.Polly

而後在Startup.cs中的ConfigureServices方法註冊該中間件

using Ocelot.Provider.Polly;
public void ConfigureServices(IServiceCollection services)
{
    ……
    services.AddOcelot()
        .AddPolly();
    ……
}

ReRoutes中添加一組路由

{
    "DownstreamPathTemplate": "/api/ocelot/{postId}",
    "DownstreamScheme": "http",
    "DownstreamHostAndPorts": [
    {
        "Host": "localhost",
        "Port": 8001
    }
    ],
    "UpstreamPathTemplate": "/ocelot/qos/{postId}",
    "UpstreamHttpMethod": [ "Get" ],
    "Priority": 2,
    "QoSOptions": {
    "ExceptionsAllowedBeforeBreaking": 3,
    "DurationOfBreak": 3000,
    "TimeoutValue": 5000
    }
}

爲了看出熔斷效果,我將8001端口的下游服務中止了,而後運行OcelotDemo項目

當第一次向網關發出請求時,獲得500的狀態碼

Ocelot_052_qos_500

連續3次請求事後,就會獲得503的狀態碼,證實Ocelot已經產生熔斷

Ocelot_053_qos_503

總結

在這篇文章中就跟你們介紹了Ocelot的兩個基礎功能,在路由中進行配置便可使用,不須要依賴於第三方的服務。固然在我實踐的過程當中產生的一個疑問暫時還沒獲得答案,若是有知道緣由的朋友也能夠給我留言,感激涕零。 結合前面的幾篇文章,你們在設計項目API網關的時候就能夠綜合地考慮到底哪些功能應該配置使用,如何適當地創建路由表。例外,我在這幾個案例中爲了突出要介紹的功能,基本上都是一組路由單獨配置一個功能,而在實際項目中一般都是須要在一組路由當中同時配置多個功能的,但願你們在實際項目中可以靈活運用。今天就先跟你們介紹到這裏,但願你們能持續關注咱們。

相關文章
相關標籤/搜索