Opened 2 weeks ago

Closed 2 weeks ago

#2253 closed enhancement (invalid)

ngx_http_limit_req_module: incorrect work logic with minute time range interval

Reported by: phoedos16@… Owned by:
Priority: minor Milestone:
Component: nginx-module Version:
Keywords: Cc:
uname -a: Linux 44f64ef706d8 4.14.193-149.317.amzn2.x86_64 #1 SMP Thu Sep 3 19:04:44 UTC 2020 x86_64 GNU/Linux
nginx -V: nginx -V
nginx version: nginx/1.21.0
built by gcc 8.3.0 (Debian 8.3.0-6)
built with OpenSSL 1.1.1d 10 Sep 2019
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -fdebug-prefix-map=/data/builder/debuild/nginx-1.21.0/debian/debuild-base/nginx-1.21.0=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie'

Description

Made a sample configuration with limit_req directive

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/m;

server {

location / {

limit_req zone=mylimit;
limit_req_status 444;
proxy_pass http://my_upstream;

}

}

Actual result: nginx re-calculate rate=10r/m to 10/60=0.16r/s and return RC=444 for 3rd request in the same second.

Expected result: nginx should pass 10 requests per IP in a minute interval; 11th request should came with RC=444. Nginx should't re-calculate request rate to seconds interval range, it should also work properly with minute iterval range (in case if minute range specified)

Agree that documentation illustrate this moment: http://nginx.org/en/docs/http/ngx_http_limit_req_module.html
"The rate is specified in requests per second (r/s). If a rate of less than one request per second is desired, it is specified in request per minute (r/m). For example, half-request per second is 30r/m."
But think this logic is incorrect: nginx should support minute range interval

access.log
1.2.3.4 - - [07/Oct/2021:04:32:32 +0000] myserver.example.com 172.17.0.4 GET / HTTP/2.0 200 642 490 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36 OPR/79.0.4143.72" "-" 0.000 - -
1.2.3.4 - - [07/Oct/2021:04:32:33 +0000] myserver.example.com 172.17.0.4 GET /favicon.ico HTTP/2.0 444 0 118 "https://myserver.example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36 OPR/79.0.4143.72" "-" 0.000 - -

error.log
2021/10/07 04:32:33 [error] 169#169: *335 limiting requests, excess: 0.944 by zone "mylimit", client: 1.2.3.4, server: myserver.example.com, request: "GET /favicon.ico HTTP/2.0", host: "myserver.example.com", referrer: "https://myserver.example.com/"

Change History (1)

comment:1 by Maxim Dounin, 2 weeks ago

Resolution: invalid
Status: newclosed

There is no "range intervals" in limit_req, there is a rate, which can be specified in different units. Regardless of the units used, the rate is the same, and always maintained. Similarly to how 60 kilometers per hour speed limit always applies, and you get a ticket once your speed is above the limit, and not after driving more than 60 kilometers within an hour.

To make sure reasonable amount of the requests are allowed for clients, consider using the burst= parameter of the limit_req directive. Also consider reading description of the algorithm to better understand how limiting works. Hope this helps.

Note: See TracTickets for help on using tickets.