-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
limit req may be not strictly accurate under certain circumstances #855
Comments
excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; maybe you can consider excess as the total request nums in the limit queue so, we can get as follows: nums in queue now = nums in queue before - nums can be processed in passed ms + this request
therefore, we do not need to consider "ms = (ngx_msec_int_t) (now - lr->last) will return 0" wish to be helpful |
@hongxiaolong 兄弟,才看到你的评论。 这个算法应该属于令牌桶算法,应该是存在误差的,假设以下场景: 在高并发请求的情况下,配置限速为10000,实际上可能达到20000。 这种可能后端业务系统就会被压死,引起一系列崩溃。 我的意思是可以通过限制每ms令牌桶最大容量,而不是每秒令牌桶最大容量来解决这个问题。 阿里的兄弟也来讨论下这个问题吧 |
可能你对令牌桶算法的理解有一点偏差,摘一段维基百科解释如下: 令牌桶: 1、每秒将 r 个令牌放入令牌桶,或者说,每过 1/r 秒桶中增加一个令牌; 而且,NGINX中的限流算法更准确地说其实是漏桶和令牌桶算法思想的结合:
在没有设置"burst"时,用漏桶可能更易理解; 在设置"burst"允许一定量的突发时,令牌桶的思想可能更贴切。 还是直接上代码解释一下最开始的回答:
剩下的很容易理解,当前时刻队列请求数即左值excess:
不知这样解答是否可以有帮助 如有兴趣,后续我也可以汇总一下NGINX官方的限流模块及其算法,到时候可以贴出来一起讨论 多谢 |
@hongxiaolong 实际上允许的连接应该是rate+burst。刚好实现了限流,和分析的一致。 |
好的,你的问题应该已完结, 我关闭了该issue,如果有问题可以再打开 |
@hongxiaolong 我觉得,如果rata / 1000 > limit->burst,应该改为如下: 或者在检查配置的时候,如果配置rata > 1000,则burst 必须大于rate/1000 @hongxiaolong |
我们还是继续来分析一下这段代码,或者说是公式。 以你说的rate=10000r/s,burst=1为例子: 0ms: excess = 0 - 10000000 * 1 / 1000 + 1000 = -9000 可以看到,我们得到的excess为一个很大的负数,而且在这里我们已经假设ms这个值很小为1的情况,实际情况会更大。
上面这段代码,如果要条件成立,起码excess要超过0,这样的情况,起码 lr->excess这个队列中已经存在很多的请求,见
综上,各种条件其实还是满足限流算法的思想的: 首先,限流队列中已经有很多请求,且在这样的情况下,单位时间内还是超过了burst的上限,才会被限流。 wish to be helpful, thanks |
@hongxiaolong 这里的时间精度单位为ms,如果请求在1ms内全部过来,ms = (ngx_msec_int_t) (now - lr->last) = 0 上周四晚上我司做全链路压测,我专门搭了一套环境,配置rate=10000, burst=1, 压测情况下,放行的请求数为每秒1000左右,和我上面的分析一致,单我本来预期放行的请求数十10000左右。 @hongxiaolong |
@y123456yz 赞思路和测试 我觉得我们已经讨论了两个维度: 1、NGINX现在的限流算法是否合理; NGINX的限流算法代码分析后,现在的限流算法是合理的,它的配置项rate、burst都很好地支持着流量的限流,符合预期,而且NGINX限流默认的时间维度是毫秒级,也就是说rate的指标换算成毫秒级的数量后,NGINX可以很精确地进行限流。 2、NGINX现在的限流算法是否可以优化,或者说符合更大流量的需求场景; Linux的系统调用gettimeofday的时间维度是精确到微秒级的,NGINX是基于该系统调用来更新时间的:
可以看到,NGINX是在微秒级上再除以1000来得到其默认的时间维度毫秒级。 所以你的推算也是符合预期的,即在1毫秒内进来10000个请求,NGINX实际放过去的请求量是每毫秒burst=1,也就是每秒1000左右。 那么,如果我们把维度提升到微秒级,理论上NGINX可以提升限流性能上千倍,但是,我们来考虑另一个角度,我们限流的主要目的还是保持服务可用,NGINX的每个连接内存占用在1K左右,10万连接在1G左右,如果可以提升一千倍性能,短时间内连接数激增,内存占用会在百倍千倍量级去提升,现在的硬件条件估计无法满足,而且epoll在这种短时间内的性能下降估计也会很可观。 综上,一定程度上NGINX现有的限流算法会丧失一些精度,不知道当时NGINX作者在默认时间维度为毫秒时是否已经提前考虑到其它的综合情况,而且估计到了这个量级,可能一般公司更多会去注重总系统而不是单机的性能瓶颈,推荐你可以NGINX mailist里邮件问问,可以互相探讨学习~ 多谢 |
@hongxiaolong 我觉得取us作为时间精度的话,突发流量会压到us时间段内,系统应该会处理不过来,应该就是你的分析,作者估计也会考虑到这个。 另外: 就如上面我分析的,如配置rate=10000,burst=1,那么OK的请求数只能为1000左右,感觉这个是个bug。我觉得不调整时间精度,可以做如下修改,同样可以满足限速要求,并且每秒突发最多为burst: 法1: 法2: 如果可以解决,法2相对比较好。 抽空我发发邮件到nginx mailist,问下他们的想法。 |
回去看了一眼NGINX对这两个配置项变量的注释,如下:
感觉原作者可能想表达的是,在没有设置burst时rate在0.001r/s,如果设置了burst,那么burst优先生效,还是蛮符合漏桶的思想的。 当然,我感觉你的思路未尝也是一种不错的方案,我的如上阅读理解你可以参考,希望有所帮助。 多谢 |
@y123456yz 假如:双11零点瞬间,1ms内来了10000个请求,发行请求每秒1000请求,没有问题,因为漏桶和令牌的消耗是成比例的,为什么会预期是几十万请求? 可以在nginx官网Report a Bug里讨论,用你的github账号登录。 |
ngx_http_limit_req_lookup()
{
...............
ms = (ngx_msec_int_t) (now - lr->last);
excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000;
...........
}
if there have several connections(For example 10 connections ) in a millimeter, ms = (ngx_msec_int_t) (now - lr->last) will return 0, then excess +=1000, So excess is larger than the actual value , for example, 10000 requests in a millisecon.
I think the unit of max Token bucket should be ms.it will be More accurate
The text was updated successfully, but these errors were encountered: