用nginx的HttpLimitReq模块请求可以被IP限制。 但是,我不明白“nodelay”选项的作用。
如果限制突发延迟内的多余请求不是必需的,则应使用节点布局
limit_req zone=one burst=5 nodelay;
这里的文档有一个解释,听起来像你想知道的:
该指令指定区域(区域)和最大可能的突发请求(突发)。 如果速率超过区域中列出的要求,则请求被延迟,以便以给定的速度处理查询
据我所知,突发请求将被延迟(需要更多的时间,并等待,直到他们可以服务),与nodelay选项延迟不使用和超出的请求被拒绝503错误。
这个博客文章 ( archive.org )给出了对nginx速率限制如何工作的很好的解释:
如果你和我一样,你可能想知道爆裂究竟意味着什么。 这里有个诀窍:用“桶”replace“burst”这个词,并且假设每个用户都有一个有5个标记的桶。 每次他们每秒超过1次请求的速度,他们都要付出代价。 一旦他们花掉了所有的令牌,就会得到一个HTTP 503错误消息,这个消息本质上已经成为“退缩”的标准。
我看到的方式如下:
尽可能快地提供请求,直到超过区域费率。 区域速率是“平均”,所以如果你的速度是1r/s和10爆炸你可以在10秒的窗口10个请求。
在区域率超过之后:
一个。 没有nodelay ,进一步的请求到burst将被延迟。
湾 使用nodelay ,进一步请求到burst将尽可能快地服务。
burst超过后,服务器将返回错误响应,直到突发窗口过期。 例如,对于速率1r/s和突发10 ,客户端将需要等待最多10秒才能进行下一个接受的请求。
该设置定义了请求是否被延迟,以便它们符合期望的速率,或者它们是否会被简单地拒绝……速度限制是由服务器pipe理还是由责任传递给客户端。
nodelay存在 请求将尽快处理; 超过指定限制发送的任何请求将被拒绝,代码设置为limit_req_status
nodelay不存在(又名延迟) 请求将以符合指定限制的速度处理。 例如,如果速率设置为10 req / s,那么每个请求将以> = .1(1 / rate)秒处理,从而不允许速率被超过,但允许请求被备份。 如果有足够的请求返回到溢出存储区(这也会被同时连接限制阻止),那么它们将被拒绝,代码设置为limit_req_status 。
这里的血淋淋的细节在这里: https : //github.com/nginx/nginx/blob/master/src/http/modules/ngx_http_limit_req_module.c#L263当限制还没有通过,逻辑开始,可以select应用于请求。 特别是来自指令的nodelay的应用在这里起作用: https : //github.com/nginx/nginx/blob/master/src/http/modules/ngx_http_limit_req_module.c#L495导致上面的delay值为0触发该处理程序立即返回NGX_DECLINED ,将NGX_DECLINED传递给下一个处理程序(而不是NGX_AGAIN ,它将有效地重新处理它)。
TL; DR: 如果您希望在不限制请求之间允许的间隔的情况下施加速率限制,那么nodelay选项非常有用。
我很难消化其他的答案,然后我发现了Nginx的新文档,其中的例子可以解决这个问题: https : //www.nginx.com/blog/rate-limiting-nginx/
这是相关的部分。 鉴于:
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; location /login/ { limit_req zone=mylimit burst=20; ... }
突发参数定义了客户端可以超过区域指定的速率(使用我们的示例mylimit区域,速率限制为每秒10个请求,或每100毫秒1个)可以产生多less个请求。 在前一个请求到达100毫秒后的请求被放入一个队列中,这里我们将队列大小设置为20。
这意味着如果21个请求同时从一个给定的IP地址到达,NGINX立即将第一个请求转发到上游服务器组,并将剩下的20个放入队列中。 然后,它每100毫秒转发一个排队的请求,并且仅当传入的请求使排队请求的数量超过20时才返回503给客户端。
如果您添加节点:
location /login/ { limit_req zone=mylimit burst=20 nodelay; ... }
通过nodelay参数,NGINX仍然根据burst参数在队列中分配时隙,并且强加configuration的速率限制,但是不排除转发排队的请求。 相反,当请求到达“太快”时,只要队列中有可用的时隙,NGINX就会立即转发请求。 它将该插槽标记为“已采用”,并且不会将其释放以供其他请求使用,直到经过适当的时间(在本示例中为100毫秒之后)。