ngx_http_limit_req_module
模块介绍
limit_req模块是令牌通算法的实现,用于对指定key(一般就是IP)对应的请求数进行限制。它的配置与之前的limit_conn类似,如下:
http{
limit_req_zone #binary_remote_addr zone=perip:10m rate=1r/s;
limit_conn_log_level error;
limit_conn_status 503;
server{
location / {
limit_req zone=perip burst=5 nodelay;
}
}
}
配置解释
limit_req:配置限流区域、桶(burst)大小,是否延迟(默认延迟);
limit_req_zone:配置限流key、存放key对应信息的共享内存区域大小、固定请求速率;
对应到上面的示例配置,即对客户端IP进行限制,桶大小为5,不延迟,每1s的时间内允许1个请求。
执行流程
假如请求在设定的访问频率之内进行访问,那么一切正常。如果请求过快,那么将会对超出设定频率允许的请求做如下处理:
默认情况下(没有配置
burst
, 没有配置nodelay
),请求将被直接返回定义的错误码(默认是503);假如配置了
burst
,那么超出频率的这些请求将会存放到burst中,但最多只能存放设定的桶大小的数量的请求(放不下的那些请求,将返回错误码)。然后,这些保存的请求将在之后按照设定的访问频率来得到处理。假如配置了
burst
,同时也配置了nodelay
,那么存放到桶中的请求不必等待,将会直接得到处理(此时,处理速率将超过设定的访问频率,即允许突发,但最多突发桶大小的请求数)。
官方文档对burst
参数的解释如下:
Excessive requests are delayed until their number exceeds the maximum burst size [...]
官方文档对nodelay
参数的解释如下:
If delaying of excessive requests while requests are being limited is not desired, the parameter nodelay should be used
场景理解
场景1
桶容量(burst)为0,延迟模式, 限制每秒500个请求,即固定平均速率为2ms一个请求,配置如下:
limit_req_zone $binary_remote_addr zone=test:10m rate=500r/s
location /limit {
limit_req zone=test;
echo "123";
}
使用AB测试工具进行测试:并发数2个,总请求100个:
ab -n 100 -c 2 http://localhost/limit
注意:
①nginx需要安装echo-nginx-module这个模块才能使用echo指令
②如果是mac,请将ab测试中的localhost写为127.0.0.1
输入日志部分如下(access.log):
[1529508020.854]200 [1529508020.854]503 [1529508020.855]503 [1529508020.855]503 [1529508020.855]503 [1529508020.855]503 [1529508020.855]503 [1529508020.855]503 [1529508020.855]503 [1529508020.856]200 [1529508020.856]503 [1529508020.856]503 [1529508020.856]503 [1529508020.856]503 [1529508020.856]503 [1529508020.856]503 [1529508020.856]503 [1529508020.856]503 [1529508020.857]503 [1529508020.857]503 [1529508020.857]503 [1529508020.857]503 [1529508020.857]503 [1529508020.857]503 [1529508020.858]200 [1529508020.858]503 [1529508020.858]503 [1529508020.858]503 [1529508020.858]503 [1529508020.858]503 [1529508020.858]503 [1529508020.858]503
场景2
桶容量(burst)为3,非延迟模式, 限制每秒500个请求,即固定平均速率为2ms一个请求,配置如下:
limit_req_zone $binary_remote_addr zone=test:10m rate=500r/s
location /limit {
limit_req zone=test burst=3 nodelay;
echo "123";
}
使用AB测试工具进行测试:并发数6个,总请求100个:
ab -n 100 -c 6 http://localhost/limit
注意:
①nginx需要安装echo-nginx-module这个模块才能使用echo指令
②如果是mac,请将ab测试中的localhost写为127.0.0.1
输入日志部分如下(access.log):
[1529590111.538]200 [1529590111.538]200 [1529590111.538]200 [1529590111.538]200 [1529590111.539]503 [1529590111.539]503 [1529590111.539]503 [1529590111.539]503 [1529590111.539]503 [1529590111.539]503 [1529590111.539]503 [1529590111.539]503 [1529590111.539]503 [1529590111.539]503 [1529590111.539]503 [1529590111.540]200 [1529590111.540]503 [1529590111.540]503 [1529590111.540]503 [1529590111.540]503 [1529590111.540]503 [1529590111.540]503 [1529590111.540]503 [1529590111.540]503 [1529590111.540]503 [1529590111.540]503 [1529590111.540]503 [1529590111.541]503 [1529590111.541]503 [1529590111.541]503 [1529590111.541]503 [1529590111.541]503 [1529590111.541]503 [1529590111.541]503 [1529590111.541]503 [1529590111.541]503 [1529590111.541]503 [1529590111.541]503 [1529590111.541]503 [1529590111.541]503 [1529590111.542]200 [1529590111.542]503 [1529590111.542]503 [1529590111.542]503 [1529590111.542]503 [1529590111.542]503 [1529590111.542]503 [1529590111.542]503 [1529590111.542]503 [1529590111.542]503 [1529590111.542]503 [1529590111.543]503 [1529590111.543]503 [1529590111.543]503 [1529590111.543]503 [1529590111.543]503 [1529590111.543]503 [1529590111.543]503 [1529590111.543]503 [1529590111.543]503 [1529590111.543]503 [1529590111.543]503 [1529590111.543]503 [1529590111.544]200 [1529590111.544]503 [1529590111.544]503 [1529590111.544]503 [1529590111.544]503 [1529590111.544]503 [1529590111.544]503 [1529590111.544]503 [1529590111.544]503 [1529590111.544]503 [1529590111.544]503 [1529590111.544]503
可以看到,并发为6,但桶大小为3,则同时可处理(burst + rate)个请求,之后,桶满了,则还是按照固定频率去处理请求。这种情况,会允许一定的突发流量(桶的大小个)。
参考
Nginx模块开发时unknown directive "echo"的处理
Nginx - what is the meaning to define `burst` if there is the `nodelay` option
附测试中最简配置
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
log_format main '[$msec]'
'$status';
limit_req_zone $binary_remote_addr zone=test:10m rate=500r/s;
server {
listen 8080;
server_name localhost;
access_log logs/access.log main;
location /limit {
limit_req zone=test;
echo "123";
}
}
}
Last updated