Ocelot(五)- 流量限制、服务质量
做者:markjiang7m2
原文地址:http://www.javashuo.com/article/p-gfqlqute-cu.html
源码地址:https://gitee.com/Sevenm2/OcelotDemojavascript
本文是我关于Ocelot系列文章的第五篇,流量限制、服务质量。Ocelot容许针对具体的服务接口进行流量限制,以便下游服务不会过载而影响响应速度。服务质量则是Ocelot根据下游服务响应的结果作出判断,当超过必定次数的响应失败时,Ocelot认为该服务不可用,自动产生熔断,在必定的时间范围内再也不向该服务转发请求,同时Ocelot也支持自定义的请求超时时间,当下游响应超过设定的时间,会认为该服务响应失败。css
关于更多的Ocelot功能介绍,能够查看个人系列文章html
本文中涉及案例的完整代码均可以从个人代码仓库进行下载。java
案例六 流量限制
Ocelot支持流量限制,只要在路由中添加RateLimitOptions
配置便可git
"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
中添加一组路由github
{
"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
}
}
在这里我只是添加多了一组路由,但下游服务接口是重用了以前使用过的接口,流量限制部分配置上面已经介绍过了。下面运行来看结果。算法
当我第一次访问http://localhost:4727/ocelot/ratelimit/5
的时候,获得了正常的返回结果shell
并且,在请求头能够看到流量限制的相关信息c#
而后,我又很快地继续发出请求,能够看到,当我第六次发出请求的时候,获得了429 To Many Requests
的状态api
而此时的请求头信息也会不同,这里能够看到Retry-After →28
,意思是在28秒后能够恢复请求
这证实,咱们的Ocelot网关流量限制的做用起效了,并且与咱们的配置一致。
在等待30秒以后,我从新发出请求,又获得了正常的返回结果
当我在请求头中加上[ClientId]=markadmin
后,清空Postman的请求记录,从新开始发出请求,不管请求多少次,Ocelot也不会对个人访问进行限流
这里对于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支持服务质量与熔断,意味着当下游服务不可用时,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
的状态码
连续3次请求事后,就会获得503
的状态码,证实Ocelot已经产生熔断
总结
在这篇文章中就跟你们介绍了Ocelot的两个基础功能,在路由中进行配置便可使用,不须要依赖于第三方的服务。固然在我实践的过程当中产生的一个疑问暂时还没获得答案,若是有知道缘由的朋友也能够给我留言,感激涕零。 结合前面的几篇文章,你们在设计项目API网关的时候就能够综合地考虑到底哪些功能应该配置使用,如何适当地创建路由表。例外,我在这几个案例中为了突出要介绍的功能,基本上都是一组路由单独配置一个功能,而在实际项目中一般都是须要在一组路由当中同时配置多个功能的,但愿你们在实际项目中可以灵活运用。今天就先跟你们介绍到这里,但愿你们能持续关注咱们。