Ocelot(五)- 流量限制、服务质量
ocelot(五)- 流量限制、服务质量
作者:markjiang7m2
原文地址:
源码地址:https://gitee.com/sevenm2/ocelotdemo
本文是我关于ocelot系列文章的第五篇,流量限制、服务质量。ocelot允许针对具体的服务接口进行流量限制,以便下游服务不会过载而影响响应速度。服务质量则是ocelot根据下游服务响应的结果做出判断,当超过一定次数的响应失败时,ocelot认为该服务不可用,自动产生熔断,在一定的时间范围内不再向该服务转发请求,同时ocelot也支持自定义的请求超时时间,当下游响应超过设定的时间,会认为该服务响应失败。
关于更多的ocelot功能介绍,可以查看我的系列文章
本文中涉及案例的完整代码都可以从我的代码仓库进行下载。
案例六 流量限制
ocelot支持流量限制,只要在路由中添加ratelimitoptions
配置即可
"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
中添加一组路由
{ "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
的时候,得到了正常的返回结果
而且,在请求头可以看到流量限制的相关信息
然后,我又很快地继续发出请求,可以看到,当我第六次发出请求的时候,得到了429 to many requests
的状态
而此时的请求头信息也会不一样,这里可以看到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网关的时候就可以综合地考虑到底哪些功能应该配置使用,如何适当地建立路由表。例外,我在这几个案例中为了突出要介绍的功能,基本上都是一组路由单独配置一个功能,而在实际项目中通常都是需要在一组路由当中同时配置多个功能的,希望大家在实际项目中能够灵活运用。今天就先跟大家介绍到这里,希望大家能持续关注我们。
上一篇: JAVA-基础(接口---抽象)
下一篇: 教你用Fireworks简单绘制QQ企鹅