如何在 NGINX 中進行速率限制

NGINX 中的速率限制是控制伺服器處理的流量的關鍵功能。它有助於防止您的伺服器在短時間內被過多的請求淹沒,而這種情況可能是由 DDoS 或高流量峰值等惡意攻擊造成的。實施速率限制可確保您的資源有效利用,合法使用者可以不間斷地存取您的服務。

本指南將示範如何在 NGINX 中配置速率限制,提供清晰的說明來幫助您有效地管理和控制傳入流量。

了解 NGINX 中的速率限制指令

主要 NGINX 速率限制指令

NGINX 使用特定指令設定速率限制,每個指令都有獨特的功能:

  • 限制請求區域: NGINX 中的 limit_req_zone 指令設定一個共享記憶體區域來儲存速率限制資訊。它位於 http 上下文中,確定允許的請求速率,有效地設定速率限制的基線。
  • 限制請求: 在位置上下文中使用的 limit_req 指令強制執行 limit_req_zone 設定的速率限制。它將這些限制應用於特定位置或 URL,從而控制存取這些端點的頻率。
  • 限制請求狀態: limit_req_status 指令位於位置上下文中,指定請求速率超過限制時傳回的 HTTP 狀態碼。當使用者或自動化系統超過允許的請求頻率時,這種回饋機制對於通知使用者或自動化系統至關重要。

建立速率限製配置

若要在 NGINX 中實施速率限制,請將適當的指令插入 NGINX 設定檔中。考慮這個基本範例:

http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/s;

    server {
        ...
        location / {
            limit_req zone=mylimit burst=10;
            ...
        }
    }
}

在此配置中,limit_req_zone 指令建立一個名為「mylimit」的記憶體區域,允許來自每個客戶端 IP 位址 ($binary_remote_addr) 的每秒 5 個請求 (5r/s)。 limit_req 指令隨後將此速率限制應用於根位置 (/),突發容量為 10 個請求,從而在嚴格的速率限制和合法流量峰值的靈活性之間提供平衡。

NGINX 中的速率限制:實例

基本限速配置

本節將探討 NGINX 中應用於伺服器範圍的基本速率限製配置。目的是限制使用者對伺服器的請求,確保效能穩定並降低過載風險。

範例:伺服器範圍的速率限制

考慮以下 NGINX 配置:

http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;

    server {
        listen 80;
        server_name example.com;

        location / {
            limit_req zone=mylimit burst=5;
            proxy_pass http://backend;
        }
    }
}

此配置為每個客戶端設定每秒 2 個請求的限制,由其 IP 位址定義($binary_remote_addr)。讓我們分解一下關鍵組件:

  • 限制請求區域:定義一個記憶體區域(mylimit),用於儲存速率限制狀態,大小為 10 MB。它將速率限制設定為每秒 2 個請求 (2r/s)。
  • 伺服器區塊:在連接埠 80 上偵聽 example.com 的傳入流量。
  • 位置區塊:對根 URL (/) 套用速率限制。突發參數允許突發最多 5 個請求,為流量的短暫峰值提供靈活性。 proxy_pass指令將請求轉送到指定的後端伺服器。
  • 突發參數:limit_req指令中的burst=5設定允許短期增加請求,最多可以在設定速率之上增加5個請求。此功能對於在不影響使用者體驗的情況下處理突然、合法的流量成長至關重要。
  • 代理通行證: proxy_pass http://backend;指令將流量轉送到後端伺服器。這通常用於負載平衡場景或 NGINX 充當反向代理時。

進階速率限制範例

不同地點的不同速率限制

在更複雜的場景中,您可能需要對不同應用程式部分應用不同的速率限制。當特定端點資源更加密集或容易被濫用時,這特別有用。

考慮以下配置:

http {
    limit_req_zone $binary_remote_addr zone=low:10m rate=1r/s;
    limit_req_zone $binary_remote_addr zone=high:10m rate=10r/s;

    server {
        listen 80;
        server_name example.com;

        location /api/low {
            limit_req zone=low burst=3;
            proxy_pass http://backend;
        }

        location /api/high {
            limit_req zone=high burst=20;
            proxy_pass http://backend;
        }
    }
}

此配置對 /api/low 位置套用較低的速率限制(每秒 1 個請求),對 /api/high 位置套用較高的速率限制(每秒 10 個請求)。

其他 Nginx 速率限制範例

基於請求類型的速率限制

您可以根據特定請求(例如 GET、POST 或 PUT 請求)設定速率限制。當您想要保護更容易被濫用或對伺服器資源影響更大的特定端點時,這特別有用。

您可以使用 if 指令和 $request_method 變數對特定請求類型套用速率限制。這是一個例子:

http {
    limit_req_zone $binary_remote_addr zone=get_limit:10m rate=5r/s;
    limit_req_zone $binary_remote_addr zone=post_limit:10m rate=2r/s;

    server {
        listen 80;
        server_name example.com;

        location / {
            if ($request_method = GET) {
                limit_req zone=get_limit burst=10;
            }

            if ($request_method = POST) {
                limit_req zone=post_limit burst=5;
            }

            proxy_pass http://backend;
        }
    }
}

在此配置中,我們設定了兩個單獨的速率限制:一個用於 GET 請求(每秒 5 個請求),一個用於 POST 請求(每秒 2 個請求)。

基於User-Agent的速率限制

另一種有用的技術是根據客戶端發送的用戶代理標頭應用速率限制。這可以幫助保護您的服務免受導致問題的特定機器人或爬蟲的侵害。

要實現基於User-Agent的速率限制,可以使用map指令和$http_user_agent變數。

這是一個例子:

http {
    map $http_user_agent $limit_bots {
        default 0;
        ~*(Googlebot|Bingbot) 1;
    }

    limit_req_zone $binary_remote_addr zone=bot_limit:10m rate=1r/s;

    server {
        listen 80;
        server_name example.com;

        location / {
            if ($limit_bots) {
                limit_req zone=bot_limit burst=2;
            }

            proxy_pass http://backend;
        }
    }
}

在此範例中,我們定義了一個對應指令,如果 User-Agent 標頭與「Googlebot」或「Bingbot」匹配,則將 $limit_bots 變數設為 1。然後,我們對這些機器人的請求套用每秒 1 個請求的速率限制。

將 IP 列入白名單以進行速率限制

有時,您可能希望使特定 IP 位址(例如受信任的合作夥伴或內部服務)免受速率限制。為了實現這一點,您可以使用 geo 指令以及 if 指示。

這是一個例子:

http {
    geo $rate_limit {
        default 1;
        192.168.0.0/24 0;
        10.0.0.0/8 0;
    }

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

    server {
        listen 80;
        server_name example.com;

        location / {
            if ($rate_limit) {
                limit_req zone=mylimit burst=10;
            }

            proxy_pass http://backend;
        }
    }
}

分散式環境中的擴展速率限制

當多個 Nginx 執行個體在分散式環境中執行時,您可能想要確保所有執行個體的速率限制保持一致。您可以使用 Redis 等集中式資料儲存來管理速率限制以實現此目的。這樣做可以讓您維持所有 Nginx 執行個體共享的全域速率限制。

若要使用 Redis 設定速率限制,您必須安裝並設定 nginx-module-redis 模組。安裝模組後,您可以更新 Nginx 設定以使用 Redis 進行速率限制。

這是一個例子:

load_module modules/ngx_http_redis_module.so;

http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/s;

    upstream redis_server {
        server 127.0.0.1:6379;
        keepalive 32;
    }

    server {
        listen 80;
        server_name example.com;

        location / {
            limit_req_redis zone=mylimit burst=10 redis_server=redis_server;
            proxy_pass http://backend;
        }
    }
}

在此範例中,我們為 Redis 伺服器定義了一個上游區塊,並更新了位置區塊以使用 limit_req_redis 指令而不是標準 limit_req 指令。此組態可確保使用共用 Redis 資料儲存體強制執行速率限制,從而在多個 Nginx 執行個體之間提供一致的速率限制。

動態速率限制

在某些情況下,您可能希望根據某些條件或伺服器上的目前負載動態調整速率限制。例如,您可能希望在高峰流量期間套用更嚴格的速率限制,以便更好地管理伺服器資源。

若要實現動態速率限制,您可以使用 map 根據特定條件定義速率限制的指令。

這是一個例子:

http {
    map $http_x_traffic $dynamic_rate {
        default "5r/s";
        high "2r/s";
    }

    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=$dynamic_rate;

    server {
        listen 80;
        server_name example.com;

        location / {
            limit_req zone=mylimit burst=10;
            proxy_pass http://backend;
        }
    }
}

在此配置中,我們使用從自訂標頭 X-Traffic 派生的 $http_x_traffic 變數。根據此標頭的值,我們動態設定速率限制。當標頭值為「高」時,我們會應用更嚴格的速率限制,即每秒 2 個請求。否則,我們使用每秒 5 個請求的預設速率。

請注意,此範例假設您的後端伺服器或基礎架構中的其他元件會根據您所需的條件設定 X-Traffic 標頭。

測試 NGINX 配置中的速率限制

使用curl驗證速率限制

使用curl進行簡單請求測試

為了驗證 NGINX 中速率限制設定的有效性,curl(一種用於發送 HTTP 請求的命令列工具)已被證明非常有用。它可以快速向您的伺服器發送多個請求,幫助您評估速率限制是否有效。

for i in {1..10}; do curl -I http://example.com; done
  • 此命令向您的伺服器發出 10 個 HEAD 請求,目標為 http://example.com。
  • 分析這些請求的 HTTP 回應標頭以驗證速率限制功能。
  • 當請求率超過指定限制時,NGINX 應傳回 429 Too Many Requests 狀態碼。

使用 Apache Bench 進行測試 (ab)

使用 Apache Bench 對伺服器回應進行基準測試

Apache Bench (ab) 是一種有效的基準測試工具,非常適合透過模擬高流量條件來測試速率限制。它有助於了解您的 NGINX 伺服器在請求激增的情況下如何表現。

ab -n 100 -c 10 http://example.com/
  • 此命令指示 ab 向 http://example.com 發送 100 個請求,並發等級為 10。
  • ab 的輸出提供了對速率限制有效性的深入了解。
  • 重點關注輸出中失敗請求的數量,該數量應與 NGINX 速率限製配置的設定保持一致。

採用最佳方法來測試您的 NGINX 配置可確保您的速率限制規則能如預期運作。

結論

透過在 NGINX 中配置速率限制,您可以保護您的伺服器免受過多流量和潛在濫用的影響。這有助於維護服務的效能和可用性,確保合法用戶獲得更好的體驗。定期監控和調整您的速率限制設置,以平衡安全性和可訪問性。實施這些控制對於有效管理伺服器資源至關重要。

Joshua James
跟我來
Joshua James 的最新帖子 (看全部)

發佈留言