はじめに
先日、Nginxでレートリミットを設定する機会があったので、内容を備忘録としてまとめておきます。
設定方法
limit_req_zone
まず、どのキーでどれくらいの速さで制限するかというゾーンを定義します。
server や location ではなくhttp ブロックに書く点に注意してください。
http {
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
}
| 要素 | 意味 |
|---|---|
$binary_remote_addr |
IPアドレス(バイナリ形式) |
zone=mylimit:10m |
状態を保存する共有メモリゾーン。名前(任意) mylimit、サイズ 10MB |
rate=1r/s |
許可するレート。1r/s は「1秒に1リクエスト」 |
limit_req
定義したゾーンを server または location ブロックに適用します。
server {
...
location / {
limit_req zone=mylimit burst=5 nodelay;
}
}
| パラメータ | 意味 |
|---|---|
zone=mylimit |
適用するゾーン名 |
burst=5 |
rateを超えた分を最大5件まで受け入れる |
nodelay |
待たせずに即時処理する(後述) |
動かしてみる
実際に動かして挙動を確認します。
nginx.conf を用意
rate=1r/s(1秒に1リクエスト)という設定にします。
events {}
http {
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
server {
listen 80;
root /usr/share/nginx/html;
location / {
limit_req zone=mylimit;
}
}
}
Nginx起動
docker run --rm -d --name nginx-test \
-p 8080:80 \
-v “$(pwd)/nginx.conf:/etc/nginx/nginx.conf” \
nginx:latest
# 動作確認
curl -s -o /dev/null -w “%{http_code}\n” http://localhost:8080
# => 200
burst なしパターン
burst を指定しない場合、rate を超えた瞬間に拒否されます。
location / {
limit_req zone=mylimit;
}
10本同時にリクエストを投げて確認します。
time (seq 10 | xargs -P 10 -I{} curl -s -o /dev/null -w “%{http_code}\n” http://localhost:8080 | sort)
結果
200
503
503
503
503
503
503
503
503
503
---- real 0.040 sec ----
1秒に1リクエストしか許可されないので即拒否されます。
burstありパターン
location / {
limit_req zone=mylimit burst=5;
}
time (seq 10 | xargs -P 10 -I{} curl -s -o /dev/null -w “%{http_code}\n” http://localhost:8080 | sort)
結果
200
200
200
200
200
200
503
503
503
503
---- real 5.054 sec ----
通る本数が 1 → 6 に増えました(rate分の1本 + burst分の5本)。
また、注目すべきは完了までの時間です。burst だけだと、burst分の5本はすぐに処理されるのではなく rate(1秒に1本)のペースで順番に処理されるため、完了まで約5秒かかります。
burst + nodelayパターン
location / {
limit_req zone=mylimit burst=5 nodelay;
}
time (seq 10 | xargs -P 10 -I{} curl -s -o /dev/null -w “%{http_code}\n” http://localhost:8080 | sort)
結果
200
200
200
200
200
200
503
503
503
503
---- real 0.039 sec ----
通る本数はburstありパターンと同じ6本ですが、待ち時間がほぼゼロになりました。
nodelay は burstを待たせるのではなく即座に処理します。消費した枠は rate のペースで少しずつ回復していきます。直後にもう一度叩くと、枠がまだ回復していないので拒否が増えるはずです。
# 上のテスト直後に実行すると200の数が減っている
time (seq 10 | xargs -P 10 -I{} curl -s -o /dev/null -w “%{http_code}\n” http://localhost:8080 | sort)
200
503
503
503
503
503
503
503
503
503
---- real 0.037 sec ----
参考