前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Ocelot(五)- 流量限制、服务质量

Ocelot(五)- 流量限制、服务质量

作者头像
.Net框架学苑
修改2019-07-19 09:30:53
1.4K0
修改2019-07-19 09:30:53
举报
文章被收录于专栏:.Net框架学苑.Net框架学苑

本文是我关于Ocelot系列文章的第五篇,流量限制、服务质量。Ocelot允许针对具体的服务接口进行流量限制,以便下游服务不会过载而影响响应速度。服务质量则是Ocelot根据下游服务响应的结果做出判断,当超过一定次数的响应失败时,Ocelot认为该服务不可用,自动产生熔断,在一定的时间范围内不再向该服务转发请求,同时Ocelot也支持自定义的请求超时时间,当下游响应超过设定的时间,会认为该服务响应失败。

关于更多的Ocelot功能介绍,可以查看我的系列文章

本文中涉及案例的完整代码都可以从我的代码仓库进行下载。

  • 仓库地址:https://gitee.com/Sevenm2/OcelotDemo

案例六 流量限制

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

代码语言:javascript
复制
"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中添加一组路由

代码语言:javascript
复制
{
 "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的时候,得到了正常的返回结果

而且,在请求头可以看到流量限制的相关信息

然后,我又很快地继续发出请求,可以看到,当我第六次发出请求的时候,得到了 429ToManyRequests的状态

而此时的请求头信息也会不一样,这里可以看到 Retry-After→28,意思是在28秒后可以恢复请求

这证明,我们的Ocelot网关流量限制的作用起效了,而且与我们的配置一致。 在等待30秒之后,我重新发出请求,又得到了正常的返回结果

当我在请求头中加上 [ClientId]=markadmin后,清空Postman的请求记录,重新开始发出请求,无论请求多少次,Ocelot也不会对我的访问进行限流

这里对于PeriodTimespan(恢复等待时间)的算法,我倒是有点疑问的。我一开始的理解是,基于上面案例的配置,当一分钟内访问超过5次时,就需要等待 Period + PeriodTimespan,也就是从第一个有效请求开始算起,一分半钟之后Ocelot才会重新正常转发请求,但是我做了几次重复实验,得到的结果都是:当一分钟内访问到第1次时,Ocelot开始进入 PeriodTimespan时间内的倒计时,也就是实际的重置时间为 PeriodTimespan

为了更加明确地验证这个问题,我使用 OcelotConsole项目进行测试。 首先,修改路由配置如下:

代码语言:javascript
复制
{
 "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项目中添加代码如下:

代码语言:javascript
复制
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就发出一次请求,运行,在命令窗口得到以下输出:

代码语言:javascript
复制
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,期待能得到答复。

流量限制的全局配置

代码语言:javascript
复制
"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会进行自动熔断,不再将请求转发给该下游服务。来看看配置

代码语言:javascript
复制
"QoSOptions": {
 "ExceptionsAllowedBeforeBreaking":3,
 "DurationOfBreak":3000,
 "TimeoutValue":5000
}
  • ExceptionsAllowedBeforeBreaking:允许异常次数,当Ocelot转发给该下游服务连续出现异常次数达到该数字时,Ocelot会进行自动熔断,一段时间内不再向该下游服务转发请求
  • DurationOfBreak:熔断时间,单位为ms(毫秒),持续多长时间不向该下游服务转发请求
  • TimeoutValue:服务质量配置项,超时时间,单位为ms(毫秒),当Ocelot向下游服务转发请求多长时间后,自动认为该请求超时

ExceptionsAllowedBeforeBreaking 必须跟 DurationOfBreak一起使用,TimeoutValue可以单独使用。

首先需要安装 Polly支持程序,通过Nuget搜索 Ocelot.Provider.Polly或者通过以下命令安装

代码语言:javascript
复制
Install-Package Ocelot.Provider.Polly

然后在Startup.cs中的 ConfigureServices方法注册该中间件

代码语言:javascript
复制
using Ocelot.Provider.Polly;
代码语言:javascript
复制
public void ConfigureServices(IServiceCollection services)
{
    ……
        services.AddOcelot()
                .AddPolly();
    ……
 }

ReRoutes中添加一组路由

代码语言:javascript
复制
{
 "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已经产生熔断

扫码关注我们,我们学的不仅是框架,更是梦想!更多技术文章查看 http://letyouknow.net/
扫码关注我们,我们学的不仅是框架,更是梦想!更多技术文章查看 http://letyouknow.net/
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 dotNet框架学苑 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 案例六 流量限制
  • 案例七 服务质量
相关产品与服务
API 网关
腾讯云 API 网关(API Gateway)是腾讯云推出的一种 API 托管服务,能提供 API 的完整生命周期管理,包括创建、维护、发布、运行、下线等。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档