![nginx 速率限制未如預期般運作](https://rvso.com/image/1684440/nginx%20%E9%80%9F%E7%8E%87%E9%99%90%E5%88%B6%E6%9C%AA%E5%A6%82%E9%A0%90%E6%9C%9F%E8%88%AC%E9%81%8B%E4%BD%9C.png)
我正在嘗試限制 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
我也遇到了這個問題 - 10r/s 實際上是每十分之一秒一個請求。
這是相關的 Stack Overflow 貼文: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 個請求,然後它將開始拒絕它們。