見出し画像

NGINXの設定 Tips

はじめに

今回はNGINXの設定について書きたいと思います。
知っている方からすると「何を今更・・・」と思うかもしれませんが、意図して設定しているか怪しいケースを見かけたことがあったので、今回記事にすることにしました。

今回取り上げるのはリクエストレートに関する設定になります。

制限の種類

NGINXで設定可能な制限の種類としては以下のようなものがあります

  • キー毎の接続数

  • キー毎のリクエストレート

  • キー毎のレスポンスレート(帯域制限)

接続数・レスポンスレートについては複雑な設定もなく、マニュアルに記載された内容で理解できると思いますので説明対象とはしていません。

気になる方はNGINXの下記マニュアルを参照してみてください。

リクエストレートについて

リクエストレートはリーキーバケット方式で制御されています。
ざっくり説明すると、キュー(burst)があり、キューに溜まった処理を一定間隔(rate)で処理することで、平準化を実現しています。

設定方法

ここからはリクエストレートの設定に方法について記載します。

共有メモリの定義

まずキーとステータスを管理する共有メモリの設定を行います。

# 構文
limit_req_zone {key} zone={zone_name}:{memory_size} rate={rate} [sync];

# 設定例
## キーに"$tenant"変数を利用する
## 設定名は "req_tenant"とする
## 確保するメモリサイズは 10MB
## 秒間50リクエストの制限をかける
limit_req_zone $tenant zone=req_tenant:10m rate=50r/s;

マニュアルではサンプルとして"$binary_remote_addr"変数がキーとして利用されていますが、上記設定例のように独自の変数も利用可能です。

制限の適用

次に共有メモリとリクエストのバーストサイズなどを設定します。

# 構文
limit_req zone=name [burst=${num}] [nodelay | delay={num}];

# 設定例
## 制限を超えたリクエストは 150までキューに積む
limit_req       zone=req_tenant burst=150;

これでリクエストレートの設定が完了となります。

rate, burst, nodelayについて

続いてリクエストレートを設定する上で重要になる`rate`, `burst`, `nodelay`について説明します。

`rate`は単位時間あたりに処理するリクエストを設定する項目で、「rate=10r/s」と設定した場合、実際はミリ秒単位でレートの判定が行われるため「100ミリ秒毎に1リクエストを処理する」という動作になります。

`burst`は、rateを超えるリクエストがきた場合にキューイングする最大リクエスト数の設定になります。

burstが設定されていない場合、同時に複数のリクエストがきた場合、後続のリクエストはエラーとなってしまいます。
burstが設定されていると、後続のリクエストはキューイングされ、設定されたレートを満たす時間待たされた後、リクエストが処理されることになります。

`nodelay`は、burstに溜まったリクエストを即時処理するかの設定となります。
nodelayが設定されている場合、処理開始までの待ち時間がなくなるため、複数のリクエストがきた場合もキューから溢れない限り、遅延なく処理されます。
ただし、リクエスト処理後すぐにキューが解放されるわけではなく、rateを満たす時間経過するまでは、キューは占有された状態になります。

上記を踏まえて、burst, nodelay設定有無による動作の違いを以下にまとめます。

  • burst + nodelayなし

    • rateを満たすように後続リクエストはキューに登録され、rateとの差分だけ遅延した後、リクエストが処理される

    • 処理が終わるとキューは解放される

    • キューが全て埋まっている状態で新しくリクエストが来るとエラーとなる

    • 遅延が発生するので、スループットはrateで指定された値に近しい値となる(リクエストの多重度をあげても大きく変わらない)

  • burst + nodelayあり

    • burstに指定した数だけ処理のキューが確保される

    • rateを超える場合も、即時処理されるが、リクエスト処理キューが1つ占有される

    • リクエストキューはrateを満たす時間毎に1つ解放される(リクエストが処理完了してもすぐに解放されない)

    • 処理キューが全て埋まっている状態で新しくリクエストが来るとエラーとなる

最後に

一般的なウェブアプリケーションであれば、burstとnodelayを併せて設定するのが良いのではないかと思います。
ただし、burst, nodelayはデフォルトでOFFになっているため、NGINXを利用中の場合、あらためて設定を確認していただくと良いかもしれません。
(過去にburstのみでnodelayが設定されていないケースは見かけたことがありました)

おまけ

リクエストレートに関する設定で、運用する上で設定しておいた方が良いと思うものなどについても少し触れたいと思います。

  • limit_req_status

    • レートを超過してエラーとなった場合に返すステータスコードで、デフォルトは「503」となってしまい他のエラーと区別しづらいため「429 」(Too Many Requests)などに変更しておくと、アクセスログから判断しやすくなります

  • IPでの制限を行いたい場合、「$remote_addr」ではなく「$binary_remote_addr」を利用した方がキーのサイズが小さくなります

  • 共有メモリで指定したサイズを超えると超えた分のリクエストはエラーとして処理されます

  • 1.17.7からは、商用版(NGINX Plus)のみですが、共有メモリの状態をAPIで操作・確認することができます

    • 商用版で利用できるAPIについては"ngx_http_api_module"を参照してください

この記事が気に入ったらサポートをしてみませんか?