Ocelot(五)- 流量限制、服务质量
作者:markjiang7m2
原文地址:https://www.cnblogs.com/markjiang7m2/p/10965300.html
源碼地址:https://gitee.com/Sevenm2/OcelotDemo
本文是我關(guān)于Ocelot系列文章的第五篇,流量限制、服務(wù)質(zhì)量。Ocelot允許針對(duì)具體的服務(wù)接口進(jìn)行流量限制,以便下游服務(wù)不會(huì)過(guò)載而影響響應(yīng)速度。服務(wù)質(zhì)量則是Ocelot根據(jù)下游服務(wù)響應(yīng)的結(jié)果做出判斷,當(dāng)超過(guò)一定次數(shù)的響應(yīng)失敗時(shí),Ocelot認(rèn)為該服務(wù)不可用,自動(dòng)產(chǎn)生熔斷,在一定的時(shí)間范圍內(nèi)不再向該服務(wù)轉(zhuǎn)發(fā)請(qǐng)求,同時(shí)Ocelot也支持自定義的請(qǐng)求超時(shí)時(shí)間,當(dāng)下游響應(yīng)超過(guò)設(shè)定的時(shí)間,會(huì)認(rèn)為該服務(wù)響應(yīng)失敗。
關(guān)于更多的Ocelot功能介紹,可以查看我的系列文章
Ocelot - .Net Core開(kāi)源網(wǎng)關(guān)
Ocelot(二)- 請(qǐng)求聚合與負(fù)載均衡
Ocelot(三)- 服務(wù)發(fā)現(xiàn)
Ocelot(四)- 認(rèn)證與授權(quán)
本文中涉及案例的完整代碼都可以從我的代碼倉(cāng)庫(kù)進(jìn)行下載。
倉(cāng)庫(kù)地址:https://gitee.com/Sevenm2/OcelotDemo
案例六 流量限制
Ocelot支持流量限制,只要在路由中添加 RateLimitOptions配置即可
"RateLimitOptions": { "ClientWhiteList": [ "markadmin" ], "EnableRateLimiting": true, "Period": "1m", "PeriodTimespan": 30, "Limit": 5 }ClientWhiteList:數(shù)組,在請(qǐng)求頭中包含ClientId=xxx的請(qǐng)求不受限流控制,其中ClientId這個(gè)key可以修改,xxx表示配置的白名單。
EnableRateLimiting:是否啟用限流
Period:限流控制的時(shí)間周期,輸入單位支持s(秒), m(分), h(時(shí)), d(天)
PeriodTimespan:恢復(fù)等待時(shí)間,當(dāng)訪問(wèn)超過(guò)限流限制的次數(shù)后,需要等待的時(shí)間,單位為s,如當(dāng)一分鐘內(nèi)訪問(wèn)超過(guò)5次,就需要等待30秒后,訪問(wèn)才會(huì)重新有效
Limit:一個(gè)時(shí)間周期內(nèi)允許訪問(wèn)的最大次數(shù)。
下面來(lái)看案例,在 ReRoutes中添加一組路由
{
"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
}
}
在這里我只是添加多了一組路由,但下游服務(wù)接口是重用了之前使用過(guò)的接口,流量限制部分配置上面已經(jīng)介紹過(guò)了。下面運(yùn)行來(lái)看結(jié)果。
當(dāng)我第一次訪問(wèn) http://localhost:4727/ocelot/ratelimit/5的時(shí)候,得到了正常的返回結(jié)果
而且,在請(qǐng)求頭可以看到流量限制的相關(guān)信息
然后,我又很快地繼續(xù)發(fā)出請(qǐng)求,可以看到,當(dāng)我第六次發(fā)出請(qǐng)求的時(shí)候,得到了 429ToManyRequests的狀態(tài)
而此時(shí)的請(qǐng)求頭信息也會(huì)不一樣,這里可以看到 Retry-After→28,意思是在28秒后可以恢復(fù)請(qǐng)求
這證明,我們的Ocelot網(wǎng)關(guān)流量限制的作用起效了,而且與我們的配置一致。
在等待30秒之后,我重新發(fā)出請(qǐng)求,又得到了正常的返回結(jié)果
當(dāng)我在請(qǐng)求頭中加上 [ClientId]=markadmin后,清空Postman的請(qǐng)求記錄,重新開(kāi)始發(fā)出請(qǐng)求,無(wú)論請(qǐng)求多少次,Ocelot也不會(huì)對(duì)我的訪問(wèn)進(jìn)行限流
這里對(duì)于PeriodTimespan(恢復(fù)等待時(shí)間)的算法,我倒是有點(diǎn)疑問(wèn)的。我一開(kāi)始的理解是,基于上面案例的配置,當(dāng)一分鐘內(nèi)訪問(wèn)超過(guò)5次時(shí),就需要等待 Period + PeriodTimespan,也就是從第一個(gè)有效請(qǐng)求開(kāi)始算起,一分半鐘之后Ocelot才會(huì)重新正常轉(zhuǎn)發(fā)請(qǐng)求,但是我做了幾次重復(fù)實(shí)驗(yàn),得到的結(jié)果都是:當(dāng)一分鐘內(nèi)訪問(wèn)到第1次時(shí),Ocelot開(kāi)始進(jìn)入 PeriodTimespan時(shí)間內(nèi)的倒計(jì)時(shí),也就是實(shí)際的重置時(shí)間為 PeriodTimespan。
為了更加明確地驗(yàn)證這個(gè)問(wèn)題,我使用 OcelotConsole項(xiàng)目進(jìn)行測(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": 10,
"Limit": 5
}
}
然后,在 OcelotConsole項(xiàng)目中添加代碼如下:
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就發(fā)出一次請(qǐng)求,運(yùn)行,在命令窗口得到以下輸出:
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.
然后,我又通過(guò)修改參數(shù),得出如下結(jié)果:
PeriodTimespan=10, Limit=5:5個(gè)成功,5個(gè)失敗
PeriodTimespan=10, Limit=6:6個(gè)成功,4個(gè)失敗
PeriodTimespan=20, Limit=5:5個(gè)成功,15個(gè)失敗
PeriodTimespan=30, Limit=5:5個(gè)成功,25個(gè)失敗
似乎都是與我前面得到的結(jié)論相同,與官方文檔不一致。
我在GitHub上提了一個(gè)issue:https://github.com/ThreeMammals/Ocelot/issues/910,期待能得到答復(fù)。
流量限制的全局配置
"RateLimitOptions": {
"DisableRateLimitHeaders": true,
"QuotaExceededMessage": "Customize Tips!",
"HttpStatusCode": 999,
"ClientIdHeader": "Test"
}
DisableRateLimitHeaders:當(dāng)設(shè)為true時(shí),請(qǐng)求頭中就不會(huì)輸出流量限制的相關(guān)信息,默認(rèn)值:"false"
QuotaExceededMessage:當(dāng)請(qǐng)求數(shù)量超出流量限制時(shí),輸出的信息,默認(rèn)值:"API calls quota exceeded! maximum admitted?{Limit}?per?{Period}."
HttpStatusCode:當(dāng)請(qǐng)求數(shù)量超出流量限制時(shí),輸出的狀態(tài)碼,默認(rèn)值:"429"
ClientIdHeader:標(biāo)識(shí)為白名單中的客戶端的請(qǐng)求頭key,默認(rèn)值:"ClientId"
案例七 服務(wù)質(zhì)量
Ocelot支持服務(wù)質(zhì)量與熔斷,意味著當(dāng)下游服務(wù)不可用時(shí),Ocelot會(huì)進(jìn)行自動(dòng)熔斷,不再將請(qǐng)求轉(zhuǎn)發(fā)給該下游服務(wù)。來(lái)看看配置
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking":3,
"DurationOfBreak":3000,
"TimeoutValue":5000
}
ExceptionsAllowedBeforeBreaking:允許異常次數(shù),當(dāng)Ocelot轉(zhuǎn)發(fā)給該下游服務(wù)連續(xù)出現(xiàn)異常次數(shù)達(dá)到該數(shù)字時(shí),Ocelot會(huì)進(jìn)行自動(dòng)熔斷,一段時(shí)間內(nèi)不再向該下游服務(wù)轉(zhuǎn)發(fā)請(qǐng)求
DurationOfBreak:熔斷時(shí)間,單位為ms(毫秒),持續(xù)多長(zhǎng)時(shí)間不向該下游服務(wù)轉(zhuǎn)發(fā)請(qǐng)求
TimeoutValue:服務(wù)質(zhì)量配置項(xiàng),超時(shí)時(shí)間,單位為ms(毫秒),當(dāng)Ocelot向下游服務(wù)轉(zhuǎn)發(fā)請(qǐng)求多長(zhǎng)時(shí)間后,自動(dòng)認(rèn)為該請(qǐng)求超時(shí)
ExceptionsAllowedBeforeBreaking 必須跟 DurationOfBreak一起使用,TimeoutValue可以單獨(dú)使用。
首先需要安裝 Polly支持程序,通過(guò)Nuget搜索 Ocelot.Provider.Polly或者通過(guò)以下命令安裝
Install-Package Ocelot.Provider.Polly
然后在Startup.cs中的 ConfigureServices方法注冊(cè)該中間件
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端口的下游服務(wù)停止了,然后運(yùn)行OcelotDemo項(xiàng)目
當(dāng)?shù)谝淮蜗蚓W(wǎng)關(guān)發(fā)出請(qǐng)求時(shí),得到 500的狀態(tài)碼
連續(xù)3次請(qǐng)求過(guò)后,就會(huì)得到 503的狀態(tài)碼,證明Ocelot已經(jīng)產(chǎn)生熔斷
總結(jié)
在這篇文章中就跟大家介紹了Ocelot的兩個(gè)基礎(chǔ)功能,在路由中進(jìn)行配置即可使用,不需要依賴于第三方的服務(wù)。當(dāng)然在我實(shí)踐的過(guò)程中產(chǎn)生的一個(gè)疑問(wèn)暫時(shí)還沒(méi)得到答案,如果有知道原因的朋友也可以給我留言,感激不盡。
結(jié)合前面的幾篇文章,大家在設(shè)計(jì)項(xiàng)目API網(wǎng)關(guān)的時(shí)候就可以綜合地考慮到底哪些功能應(yīng)該配置使用,如何適當(dāng)?shù)亟⒙酚杀怼A硗?#xff0c;我在這幾個(gè)案例中為了突出要介紹的功能,基本上都是一組路由單獨(dú)配置一個(gè)功能,而在實(shí)際項(xiàng)目中通常都是需要在一組路由當(dāng)中同時(shí)配置多個(gè)功能的,希望大家在實(shí)際項(xiàng)目中能夠靈活運(yùn)用。今天就先跟大家介紹到這里,希望大家能持續(xù)關(guān)注我們。
總結(jié)
以上是生活随笔為你收集整理的Ocelot(五)- 流量限制、服务质量的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Docker最全教程之MySQL容器化
- 下一篇: Ocelot(三)- 服务发现