NGINXのRate Limitingの設定調査メモ
Webサーバーで流量制御をしたいとフワッと要望があったので下調べした結果をメモ。
インフラの切り口では、NGINXを使ってRate Limitingを設定するのが適当そうであった。
NGINXのRate Limiting設定
NGINXのconfファイルで以下のような感じで設定する模様。
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
#...
location /search/ {
limit_req zone=one;
}
}
}
limit_req_zone
とlimit_req
の2つのディレクティブで設定を行う。
-
limit_req_zone
: httpブロックに記述
流量制御の定義 -
limit_req
: serverブロックまたはlocationブロックに記述
どの定義を使って、流量制御を行うか。また流量制御の挙動を設定する
後述するburst
,nodelay
で流量制御の挙動を調整する
Rate Limitingの設定項目と挙動
-
設定ファイルの作成
デフォルトの/etc/nginx/nginx.conf
では、httpブロックでinclude /etc/nginx/conf.d/*.conf;
とincludeする記述があるので、default.confを作ってlimit_req_zone
とserverブロックを定義する。作成したdefault.confを/etc/nginx/conf.d/default.conf
に配置してやればよい。# limit_req_zone <key> zone=<name>:<size> rate=<rate> r/s or r/m; limit_req_zone lrz_key_all zone=lrz_all:50m rate=200r/s; server { listen 80; listen [::]:80; server_name _; root /var/www/html; index index.html index.htm index.nginx-debian.html; location / { limit_req zone=lrz_all burst=1000 nodelay; proxy_pass http://localhost:8080; } error_page 404 /404.html; # redirect server error pages to the static page /50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
-
ざっくりとした設定の解釈
-
limit_req_zone
:-
key
: 流量制御の対象 -
zone
: 流量制御の定義名 -
rate
: 流量制御の程度
200r/sとかだと1秒間に200件のリクエストを受け付けるという意味合いになる。
-
-
limit_req
-
zone
: 使用する流量制御の定義名 -
burst
:
rate=200r/sとした場合、burstなしでは、5ミリ秒(1000÷200r/s)以内に次のリクエストが来るとそのリクエストは、Rate Limitingによりエラーとされる。burstはキューのようなもので、burstを設定するとリクエストは待機状態となり、5ミリ秒経過後に待機中のリクエストを1つ処理するという挙動をするようである。
burstの設定数をキューのサイズと見立てれば良いと思う。 -
nodelay
:
burstの設定だけだと、リクエストをrateに応じた間隔でシリアル処理することになる。nodelayを設定することで待機ではなく並列処理するように挙動が変わるようである。
並列処理の多重度がburst
の設定値(※)になることを理解しておくことが必要。並列処理固有の多重度を設定して、残りをキューに溜めておくような設定はできない。
※厳密にはburst
+1となるようで、+1のスロットをnodelay
なしとして使う。
-
-
-
limit_req_zone
のkey
流量制御の対象は、$binary_remote_addr
とした場合は、特定のアクセス元からの大量アクセスに制限をかけるということになる。
$binary_remote_addr
のような変数値($で開始)ではなく、定数値
とするとリクエスト全体が対象となるようである。今回はリクエスト全体を対象に流量制御を考えていく。
-
limit_req
のburst
とnodelay
どのような、制御を行いたいかは、burst
とnodelay
の設定が肝となってくるので、burst
とnodelay
の扱いを掘り下げて考える必要がある。
Rate Limitingの設定について
参考にしたBLOGでは、burst
とnodelay
の設定を推奨しており、前節の挙動なのであれば納得はできるが、安直に設定すればいいものではないとも思う。burst
とnodelay
の設定次第では、rate
で設定した数値より多数のリクエストを受け付ける場合もあり、それはバックエンドにあるアプリケーションが受け付けた数のリクエストを捌くことができるかどうかという話になる。つまりアプリケーションがリクエストを捌けるかどうかを設定値検討に含めることが肝要である。
-
burst
設定+nodelay
あり
burst
設定値を大きな値にするとアプリケーション側には大量のリクエストが殺到することになるので、バックエンドにあるアプリケーション側でもburstに見合ったキューの大きさ・流量制御が実装されていることが必須と言える。
burst
をアプリケーション側の都合での処理可能な多重度として扱ってしまうと(burst
の値を小さくすると)、リクエストがラッシュした場合、多くのリクエストがRate Limitingで弾かれてしまうことになる。
-
burst
設定+nodelay
なし
バックエンドのアプリケーションから見るとリクエストの発生間隔を平準化してくれる。アプリケーションが処理可能なリクエスト量(アプリケーションの処理能力やホストのスペックによる)をもとにrate
の設定値を決めていく。
nodelay
なしにするのは、アプリレーション側で流量制御を実装していないアレ(自粛)な場合に使用せざるを得ないってシナリオだろうか。
別にnodelay
なしも悪いわけではない、システムとして処理可能なリクエスト量やレスポンスタイムが目標値を満たせる/許容できる範囲に収まればよいという考えが根底にあるはず。
基本方針としては、burst
設定+nodelay
ありとして、アプリケーションサイドと話し合って設定値を決めていく必要があるなと思いました。
まだドキュメントベースの机上の話なので検証ができたら改訂したいと思いまする。NGINXのインスタンス数も考慮しなくてはならないし、、、
おわりに
NGINXでの流量制御では、リクエストの閾値を設定してアプリケーションサーバー側に過剰な負荷がかからないようにリクエストを弾くものであり、システム全体で見るとNGINXの流量制御だけでは片手落ちでWebサーバーの後ろにあるアプリケーション側でも流量制御の仕組みが必要であると考える。
参考にしたドキュメントとBLOG
Discussion