NGINX 頻寬與連線數控制

對於負載量比較高的伺服器,可以設定每一位使用者可使用的資源上限,例如同時間最大連線數、連線頻率(每秒或每分鐘連線次數)以及下載速度。

同時間最大連線數

若要限制同時間最大連線數,首先要使用 limit_conn_zone 定義一個 key 與 zone 參數:

limit_conn_zone $binary_remote_addr zone=addr:10m;

這裡定義一個名為 addr 的 zone,空間大小是 10MB,worker 行程會使用這個 zone 所配置的共享記憶體空間來儲存 key 的計數值。這裡的我們使用 $binary_remote_addr 來作為判斷來源 IP 的依據(key),會使用這個二進位的變數來作為 key 是因為它跟一般的字串比起來,會比較省空間,如果 zone 所配置的共享記憶體空間用完了,那伺服器就會回傳 503(Service Temporarily Unavailable)的錯誤訊息。

接著再使用 limit_conn 指定一個 IP 同時間可以允許的最大連線數:

location /download/ {
  limit_conn addr 1;
}

以上的設定只有對於來源 IP 做限制,如果要設定整台伺服器所有連線的上限值,可以這樣設定:

http {
  limit_conn_zone $server_name zone=server:10m;

  server {
    limit_conn server 1000;
  }
}

這樣就可以把伺服器同時能夠接受的連線數上限設定為 1000

由於在 NAT 之內的所有設備會共享一個對外 IP 位址,若以 IP 位址限制使用資源的方式,會造成 NAT 之下的所有設備共享單一 IP 位址的資源限制,這一點在制定規則時需要納入考慮。

連線頻率

若要限制連線頻率,首先也是一樣要用 limit_req_zone 定義 key 與 zone 參數:

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

這裡除了定義 zone 的名稱與大小之外,還加上了一個 rate 指定連線頻率的上限,單位可以使用每秒的連線次數(r/s)或是每分鐘的連線次數(r/m),例如若要指定每分鐘不可超過 30 次連線,則設定為 30r/m

然後在需要限制連線頻率的地方加上 limit_req 的設定:

location /search/ {
  limit_req zone=one burst=5;
}

這裡的 zone 就指定成剛剛上面定義的 zone 名稱,如果使用者所發出的連線頻率超過上限時,多出來的連線會先被放在伺服器的佇列中,等候一小段時間之後再處理,維持整體的連線頻率不會超過設定的上限,而 burst 參數是設定這個佇列的長度,如果連線數多到連佇列都放不下時,就會產生 503 的錯誤。

如果不想讓放在佇列中的請求延遲處理,可以加上 nodelay

limit_req zone=one burst=5 nodelay;

下載速度

若要限制每個連線的頻寬,可以使用 limit_rate

location /download/ {
  limit_rate 50k;
}

在這樣的設定之下,每一個連線的下載速度最高不可超過每秒 50KB,但一個使用者可以同時開啟多條連線,如果需要限制連線數,可再加上 limit_conn 的限制條件:

location /download/ {
  limit_conn addr 1;
  limit_rate 50k;
}

如果要讓使用者可以先下載一部份的資料,再進行連線頻寬的限制,可以使用 limit_rate_after

limit_rate_after 500k;
limit_rate 20k;

這樣的設定可以讓使用者先下載 500KB 的資料之後,再進行限速,這通常會用在線上影音串流的網站,先讓使用者快速下載影音檔的表頭,然後再以正常的速度傳送串流資料,確認使用者是以串流的形式觀看,而不是直接下載。

以下是一個實際應用的範例,這個設定可讓一般的網頁同時可以接受 5 條連線(一般的瀏覽器通常最多使用 3 條),而在下載 /download/ 之下的檔案時,一次只能下載一個檔案,1MB 以下的檔案不限速,超過 1MB 的檔案則限速每秒 50KB。

http {
  limit_conn_zone $binary_remote_address zone=addr:10m

  server {
    root /www/data;
    limit_conn addr 5;

    location / {
    }

    location /download/ {
      limit_conn addr 1;
      limit_rate_after 1m;
      limit_rate 50k;
    }
  }
}

參考資料:NGINX