Ограничение скорости nginx не работает должным образом
Я пытаюсь ограничить скорость соединений nginx, однако, похоже, это работает не так, как ожидалось. Я пытался протестировать это, используя 2 и 10 запросов в секунду.
Во-первых, 2 запроса в секунду
limit_req_zone $binary_remote_addr zone=myzone:10m rate=2r/s;
limit_req_status 429;
server {
listen *:80;
server_name 172.23.97.94;
root /var/www/html;
index index.html;
location / {
limit_req zone=myzone;
try_files $uri $uri/ =404;
}
}
Тестирование через Curl:
for i in {1..2}; do curl -I -s "http://172.23.97.94" | head -n 1; done
HTTP/1.1 200 OK
HTTP/1.1 429 Too Many Requests
Access.log подтверждает, что одновременно поступает только 2 запроса, однако второй запрос получает 429:
172.23.106.65 - - [08/Feb/2023:17:10:35 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.68.0"
172.23.106.65 - - [08/Feb/2023:17:10:35 +0000] "HEAD / HTTP/1.1" 429 0 "-" "curl/7.68.0"
Но если я сделаю тот же запрос со сном в 0,5 секунды, все пройдет хорошо:
for i in {1..2}; do curl -I -s "http://172.23.97.94" | head -n 1; sleep 0.5; done
HTTP/1.1 200 OK
HTTP/1.1 200 OK
Во-вторых, 10 запросов в секунду
limit_req_zone $binary_remote_addr zone=myzone:10m rate=10r/s;
limit_req_status 429;
server {
listen *:80;
server_name 172.23.97.94;
root /var/www/html;
index index.html;
location / {
limit_req zone=myzone;
try_files $uri $uri/ =404;
}
}
Тестирование через Curl:
for i in {1..10}; do curl -I -s "http://172.23.97.94" | head -n 1; done
HTTP/1.1 200 OK
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
Access.log подтверждает, что одновременно существует только 10 подключений, но только первое получает 200:
172.23.106.65 - - [08/Feb/2023:17:14:53 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.68.0"
172.23.106.65 - - [08/Feb/2023:17:14:53 +0000] "HEAD / HTTP/1.1" 429 0 "-" "curl/7.68.0"
172.23.106.65 - - [08/Feb/2023:17:14:53 +0000] "HEAD / HTTP/1.1" 429 0 "-" "curl/7.68.0"
172.23.106.65 - - [08/Feb/2023:17:14:53 +0000] "HEAD / HTTP/1.1" 429 0 "-" "curl/7.68.0"
172.23.106.65 - - [08/Feb/2023:17:14:53 +0000] "HEAD / HTTP/1.1" 429 0 "-" "curl/7.68.0"
172.23.106.65 - - [08/Feb/2023:17:14:53 +0000] "HEAD / HTTP/1.1" 429 0 "-" "curl/7.68.0"
172.23.106.65 - - [08/Feb/2023:17:14:53 +0000] "HEAD / HTTP/1.1" 429 0 "-" "curl/7.68.0"
172.23.106.65 - - [08/Feb/2023:17:14:53 +0000] "HEAD / HTTP/1.1" 429 0 "-" "curl/7.68.0"
172.23.106.65 - - [08/Feb/2023:17:14:53 +0000] "HEAD / HTTP/1.1" 429 0 "-" "curl/7.68.0"
172.23.106.65 - - [08/Feb/2023:17:14:53 +0000] "HEAD / HTTP/1.1" 429 0 "-" "curl/7.68.0"
Но если я сделаю тот же запрос со сном 0,01 секунды, у некоторых из них будет 200, а у других — 429:
for i in {1..10}; do curl -I -s "http://172.23.97.94/device/1" | head -n 1; sleep 0.01; done
HTTP/1.1 200 OK
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
HTTP/1.1 200 OK
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
HTTP/1.1 200 OK
Я делаю что-то неправильно? Или ограничение скорости просто не работает должным образом?
1 ответ
Я тоже столкнулся с этой проблемой — 10р/с — это действительно один запрос на каждую десятую долю секунды.
Вот связанное сообщение о переполнении стека: https://stackoverflow.com/questions/62262540/ideal-config-for-nginx-rate-limiting
Вот статья, на которую они ссылаются из nginx, рассказывая об этом: https://www.nginx.com/blog/rate-limiting-nginx/
Мне это кажется плохим решением, поскольку обычно на одной странице загружается несколько ajax-запросов, и из-за того, как это работает, они задерживаются при любом ограничении скорости.
Судя по статье, похоже, что есть способы обойти эту проблему с помощью опции «nodelay», а затем выполнить двухэтапное ограничение скорости.
limit_req zone=ip burst=12 delay=8;
Который разрешает 8 запросов одновременно, затем после этого он задерживает их до тех пор, пока в очереди не окажется 12, а затем начинает их отклонять.