Die Ratenbegrenzung von Nginx funktioniert nicht wie erwartet

Die Ratenbegrenzung von Nginx funktioniert nicht wie erwartet

Ich versuche, die Nginx-Verbindungen zu begrenzen, aber es scheint nicht wie erwartet zu funktionieren. Ich habe versucht, es mit 2 und 10 Anfragen pro Sekunde zu testen.

Erstens: 2 Anfragen pro Sekunde

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;
  }
}

Testen mit 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 bestätigt, dass es nur zwei Anfragen gleichzeitig gibt, die zweite Anfrage erhält jedoch 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"

Wenn ich die gleiche Anfrage jedoch mit einer Pause von 0,5 Sekunden mache, läuft es problemlos:

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

Zweitens, 10 Anfragen pro Sekunde

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;
      }
    }

Testen mit 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 bestätigt, dass es nur 10 Verbindungen gleichzeitig gibt, aber nur die erste erhält 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"

Wenn ich jedoch dieselbe Anfrage mit einer Pause von 0,01 Sekunden mache, sind einige davon 200, während andere 429 sind:

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

Mache ich etwas falsch? Oder funktioniert die Ratenbegrenzung einfach nicht wie erwartet?

Antwort1

Ich bin auch auf dieses Problem gestoßen – 10r/s ist eigentlich eine Anfrage pro Zehntelsekunde.

Hier ist ein zugehöriger Stack Overflow-Beitrag:https://stackoverflow.com/questions/62262540/ideale-config-for-nginx-rate-limiting

Hier ist der Artikel von Nginx, auf den sie sich beziehen und in dem es um dieses Thema geht:https://www.nginx.com/blog/rate-limiting-nginx/

Das scheint mir eine schlechte Entscheidung zu sein, da es üblich ist, dass für eine Seite mehrere Ajax-Anfragen geladen werden und diese bei einer Ratenbegrenzung verzögert werden.

Dem Artikel zufolge gibt es Möglichkeiten, dies mit der Option „Nodelay“ zu umgehen und anschließend eine zweistufige Ratenbegrenzung durchzuführen.

limit_req zone=ip burst=12 delay=8;

Dadurch werden acht Anfragen gleichzeitig zugelassen. Anschließend werden sie verzögert, bis sich 12 in der Warteschlange befinden, und dann beginnen sie, sie abzulehnen.

verwandte Informationen