ITシステムがブラックボックス化している現代においてインフラエンジニアの需要は縮小していくという人もいますが、私は必ずしもそうではないと考えています。特にパフォーマンス分野のエンジニアは今後もなくならない職種のひとつだと言えると考えています。なぜならシステムがいくらブラックボックス化したとしても各システムの特性に適した難易度のパフォーマンスチューニングが必要不可欠だからです。しかしその分難易度も高く、どういった設計をしたらよいのか一般的なノウハウがあまりないように思いましたので、本記事にてパフォーマンス設計のベストプラクティスをまとめてご紹介しようと思います。今回はレート制限設計に関するノウハウをお伝えします。
1. 流量制限の目的
流量制限とは、ユーザからのリクエストが集中した状況においてシステムを安定稼働させるために、システムで処理するリクエスト数に制限をかける機能となります。サービスのピーク日におけるリクエスト数が想定以上であった場合や、外部からのDDoS攻撃、Botアクセスなどにより大量のリクエストが来た際に、何の制限もなくリクエストを受け付けしてしまうと、リクエストに対するレスポンスが大幅に遅延したり、状況が悪化するとリソース高騰によりサーバ機器などがダウンしてシステムの全面停止につながることがあります。または、クラウド環境を使っている場合は想定以上のリソース使用量になって高額な利用料金の支払いが必要になる可能性もあります。このような事態に陥らないように流量制限を適切に設定し、性能試験にて流量制限が機能することを確認しましょう。
また、どういった流量制限をかけたいかということによっても設計が変わってきますので、もう少し具体的な目的を検討した方が良いと思います。例えば瞬間的な高トラフィックに対する制限なのか、それとも継続的な高トラフィックに対する制限なのか、この辺りを明確にして設計していくことがポイントとなります。
2. 流量制限設計の基本方針
流量制限はどこかひとつのレイヤーで設計すれば良いというものではなく、それぞれのレイヤーで目的に応じた流量制限を導入する必要があります。システム構成によって流量制限を導入するレイヤーが変わってきますが、例として下図のようなwebシステムにおける流量制限のポイントを説明します。

2.1 バーストトラフィックに対する流量制限
バーストトラフィック(瞬間的な高トラフィック)に対しては、なるべくフロント側で流量制限をかけることがポイントです。制限をかけるレイヤーを後ろにしてしまうと、制限をかけたレイヤーよりフロントにある要素が影響を受けてしまう可能性が高くなるからです。とはいえ、システムによって流量制限をかけられるレイヤーに制約があることもあると思いますので、いくつか選択肢を説明させていただきます。
1. CDN(Contents Delivery Network)におけるバーストトラフィック対策
シンプルに考えると最もフロントに位置しているCDNで流量制限かけるのがよいと思うのですが、使っているCDN製品によっては思ったような流量制限をかけられなかったり、監視運用が大変で実装が現実的でなかったりするので、導入要否を慎重に検討いただければと思います。今回はCloudflareとAkamaiにおける流用制限について簡単にご紹介します。
□Cloudflareによる流量制限
特定のURLに対する過剰なリクエスト、またはドメイン全体に対する過剰なリクエストを自動的に特定し、L7レイヤで流量制限をかけることができます。例えば、評価期間10分間の間に100,00件以上のリクエストが発生した場合は、リクエストをブロックしてHTTPステータス403(Forbidden)を返却するといったルールを作成できます。この際、閾値を超えたら10分間は全リクエストをブロックするという挙動にもできますし、閾値を超えた分のリクエストだけブロックするといったこともできます。またブロックするのではなく、スロットリングといってレスポンスを遅延させるようなことも可能です。
Cloudflareの無料枠でも流量制限をかけることができますが、ルール数が1つに限られていたり、閾値超過時のアクションがブロックだけであったり、できることが限られるので、商用適用する際には有料版のプラン導入も検討いただけると良いかと思います。例えばBusinessプラン以上であればWaiting Room機能(※)を追加料金なしで使うことが可能です。
※Waiting Room機能
大量アクセスがきた場合、あらかじめ設定した同時接続数の上限を超えるユーザーをWaiting Room(待機室)にリダイレクトさせる機能となります。Waiting Roomで順番待ちさせ、空きができたタイミングで本番サイトにアクセスできるようになります。クッキーやトークンを発行したり、リクエストの時間に応じて順番を制御するロジックが一般的です。
Cloudflareの流量制限に関する詳細情報はは下記のサイトを参照ください。
https://cloudflare.zendesk.com/hc/ja/articles/115001635128-Cloudflare%E3%83%AC%E3%83%BC%E3%83%88%E5%88%B6%E9%99%90%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B
□Akamaiによる流量制限
流量制限の発動条件や閾値超過時の挙動の設定についてはCloudflareと大きな違いはないかと思いますが、適切なAkamai製品を選択する必要があります。IPアドレスによる流量制限を実装したい場合はKona Site Defender、APIごとに詳細な流量制限を設定するためにはAPI Gateway製品を選択します。ただしCloudflareと比べると設定が複雑で少し難しいので、サポートに相談しながら最適な設定にチューニングしていく必要があるかと思います。
AkamaiにおいてWaiting Room機能を適用するためには、Akamai Visitor Prioritizationというサービスを使うことで実現できます。ただし各Edgeサーバに対する制限となりますので、全体的にトラフィックが増えてしまうとバックエンドで処理できない量のトラフィックになってしまう可能性があるので、リアルタイム監視を適切に導入する必要がありそうです。下記のサイトにAkamai Visitor Prioritizationに関する注意点が記載されていたので共有します。
CDNと流量制御で高トラフィックからシステムを守る – kashinoki38 blog
また、Akamaiについては下記のサイトがまとまってて見やすかったです。
https://www.akamai.com/blog/developers/demystifying-api-rate-limiting
2. NW機器におけるバーストトラフィック対策
CDNによる流量制限実装が難しい場合、その先のNW機器で制限をかけることも可能です。NW機器といっても、ルータ、ファイアウォール、ロードバランサ、UTM、スイッチなどいろいろあるかと思いますので、システム構成に合わせて導入を検討してみてください。ただし、NW機器においてはL4レイヤ以下の制限がほとんどとなります。L7レイヤの流量制限と比較すると詳細なエラー応答をユーザに返却することができず、ユーザのリトライ処理を誘発してしまう可能性があることを認識いただければと思います。ですので、他の機器の流量制限と併用するのを推奨します。
導入する機器にもよりますが、一般的なNW機器にて設定できる主な帯域制限は下記となります。
・分類(Classification)とマーキング(Marking)
分類機能により、IPアドレスやMACアドレス、あるいはポート番号などで分類をし、分類ごとの優先度に基づいて帯域制限を設定することができます。また、ネットワークトラフィックに対して特定のQoS情報を付与することで優先度を制御することも可能です
・ポリシング(Policing)
事前に設定したトラフィック量の最大値を超過したパケットを破棄する方法となります。データの欠落は起きてしまいますが、通信の遅延は発生しにくいという特徴があります。音声通信などのリアルタイム性が求められるサービスに適用するのが推奨です。
・シェーピング(Shaping)
事前に設定したトラフィック量の最大値を超過したパケットをバッファに蓄積し、順番に処理をさせる方法となります。遅延は起きてしまいますがパケットのロスが少ないという特徴があります。ファイル転送などのデータの欠落が許容できないサービスに適用するのが推奨です。
3. API Gatewayにおけるバーストトラフィック対策
API Gatewayにおいてバーストトラフィックに対して流量制限をかけるためには、スロットリングを設定するのが一般的です。スロットリングとは、一定時間内に受信可能なリクエスト数を制限する仕組みとなります。代表的なAPI製品に対するスロットリングの設定方法をご説明します。製品によってスロットリングの挙動が微妙に異なりますので、正確に製品仕様を抑えたうえで制限をかけることが重要となります。
□Amazon API Gatewayにおけるバーストトラフィック対策
スロットリング設定を行います。スロットリングが適用されるタイプとしては、AWSリージョン、アカウント、APIのステージ(dev/prodなど)およびメソッド(GET/POSTなど)、クライアント(ユーザ/アプリなど)の4つがあります。AWSリージョンのスロットリングは変更不可、アカウントごとのスロットリングは変更できますが上限変更の申請が必要となります。ですので一般的にはAPIのステージ・メソッドやクライアント単位のスロットリングを設定するのが一般的かと思います。マネジメントコンソールからAmazon API Gatewayの「スロットリングの設定」ページを開いて、バーストの項目を設定してください。
具体的な挙動は、スロットリングに加えてレート制限の設定も影響してきます。例えば、バースト制限が10リクエスト/秒、レート制限が5リクエスト/秒の場合の挙動は下図のようになります。バースト制限以内の10リクエスト/秒が許可され、その次に来たレート制限以内の5リクエスト/秒は許可されますが、それ以上のリクエスト/秒は制限される挙動となります。

詳細は下記をご参照ください。
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-request-throttling.html
□Apigeeにおけるバーストトラフィック対策
Spike Arrestというスロットリング設定を適用することで急激なアクセス増加を防ぐことができます。たとえばレートを1秒あたり10と設定すると、100ミリ秒(1秒÷10)に1件のリクエストが許可されるようにレートが平準化されます。下図のようなイメージとなります。

詳細は下記をご参照ください。
https://docs.apigee.com/api-platform/reference/policies/spike-arrest-policy?hl=ja#example-1
4. Webサーバにおけるバーストトラフィック対策
Webサーバーにおいてバーストトラフィックに対して流量制限をかけるためには、同時接続数を制限するのが一般的です。代表的なミドルウェアの流量制限方法をご紹介します。
□Nginxにおけるバーストトラフィック対策
Nginxには流量制限に関するモジュールがいくつかありますのでそれぞれご紹介します。
– limit_conn (同時接続数制限)
特定のキー情報に対する同時接続数を制限するモジュールとなります。多数のユーザからの同時接続を制限することで、バックエンドサーバのリソースを守ることができます。特定のIPアドレスをキー情報することで特定のリクエスト元からのリクエストを制限したり、特定のURIを指定してURIごとに接続数を制限することができます。
– worker_processes/worker_connections(同時接続数制限)
上述の通り、limit_connにより特定のキー情報に対する同時接続数を制限することはできますが、nginxサーバー全体の同時接続数を制限することはできません。そこで有効なのがworker_processes/worker_connectionsの設定となりまして、下式の通りに最大同時接続数を設定することができます。
最大同時接続数 = worker_processes × worker_connections
worker_processes :nginxが生成するワーカープロセスの数となります。nginxサーバーのCPU数に応じてチューニングするか、あるいはコア数を自動で判断して設定するauto設定を指定して下さい。
worker_connections:ひとつのワーカープロセスにおける最大接続数となります。
※上記の設定に加えて、ワーカープロセスが開くことができるファイルディスクリプタの最大数の上限値(worker_rlimit_nofile)もチューニング対象となりますのでご留意ください。
– limit_req (リクエスト数制限)
特定のキー情報に対するリクエスト数を制限するモジュールとなります。過剰な短時間のリクエストを制限することで、バックエンドサーバーのリソースを守ることができます。limit_connモジュールと同様で、IPアドレスやURIをキー情報に指定することでリクエスト数を制限可能です。
– limit_rate (帯域幅制限)
ひとつの接続に対して通信速度を制限することができます。一部のユーザーが通信帯域を占有するのを防ぐことで、他のユーザーに対する帯域を確保することができます。通信速度をBytes/Secondで制限可能です。
参考にしたサイトを共有します。
Tuning NGINX for Performance
□Apacheにおけるバーストトラフィック対策
– MaxRequestWorkers(同時接続数制限)
MaxRequestWorkersを設定することで、Apache全体としての同時接続数に制限をかけることができます。MaxRequestWorkersはバージョン2.4以前はMaxClientsと呼ばれていた設定になります。ただし、Apacheの流量制限に関しては、Listenキュー数を制限するListenBacklogなど、他にもいろいろ設定すべきパラメータがあります。参考までにMaxRequestWorkersとListenキューのイメージを記載します。

Apache流量制限の詳細については別の記事に記載しているので、興味ある方はご参照ください。
【初心者向けApache入門】:並列処理の基本とパフォーマンス改善のコツ
3.継続的な高トラフィックに対する制限
バーストトラフィックに対しては上記で説明したようにフロントの機器で制限をしますが、継続的な高トラフィックに対する流量制限をかけることも重要です。特にシステムの要であるデータベースサーバに対して想定以上の負荷がかからないようにバックエンドでも適切な設定を検討しましょう。
5. APサーバレイヤにおける高トラフィック対策
APサーバにおける制限設定箇所は主にスレッドプール、アプリケーション、DB接続の3か所となります。

□スレッドプールによる高トラフィック対策
tomcatを例に流量制限パラメータをご説明します。下図の通りキューが2段階構造になっているのでそれぞれ適切値を設定しましょう。

– acceptCount
すべてのworkerスレッドが使用されているときに受付可能な最大キュー長。キューがあふれた場合は受信した要求は拒否される。
– maxConnections
サーバが受け入れて処理できる最大接続数。上限に達した場合は接続を受け付けはするが、workerスレッドによる処理はされず待ちとなる。
– maxThreads
リクエストを処理するworkerスレッドの上限(最大同時実行数)。HTTP、AJPなどのコネクタごとに上限が設定される。
詳細は下記にまとめているので興味ある方は見てみて下さい。
【Tomcat】コネクションプールのチューニングによる流量制限の方法をまとめてみた。
□アプリケーションによる高トラフィック対策
あまり詳しくないのですが、アプリケーションで流量制限することもできるみたいです。ただし一般的な方法ではないと思いますので、ほかのレイヤで制限がかけられるのであればアプリケーションにおける実装は無理にやらなくても良いかなと個人的には考えています。一応、例としてJava向けの流量制限のライブラリがあったのでリンクを記載しておきます。
https://resilience4j.readme.io/docs/ratelimiter
□DB接続に関する高トラフィック対策
こちらもtomcatにおける設定例をご説明します。DBに対する最大コネクション数と、DB接続の最大待機時間を適切な値に設定してください。フロントから漏斗型に制限をかけるのが原則なので、DBに対する最大コネクション数(MaxTotal)が同時接続数(MaxThreads)よりも小さくなるように設定します。

– MaxTotal
同時にプールに存在可能なコネクションの最大数
– MaxWaitMills
利用可能なコネクションが存在しない場合、例外を投げる前にコネクションが戻されるのを待機する最大時間(ms)
詳細は下記にまとめているので興味ある方は見てみて下さい。
【Tomcat】コネクションプールのチューニングによる流量制限の方法をまとめてみた。
まとめ
Webシステムにおける流量制限のベストプラクティスのご紹介は以上となります。考慮するポイントが多くてなかなか難易度が高い設計要素かと思いますが、システムの安定運行に直結する重要な要素となりますので、性能試験を実施して適切な設計にチューニングすることを推奨いたします。
他にもパフォーマンス関連の情報をまとめているので興味のある方は見てみて下さい。
Webシステムのパフォーマンス設計に関するベストプラクティス(システム構成・ハードウェア要素編)
Webシステムのパフォーマンス設計に関するベストプラクティス(仮想化要素編(VMware))
Webシステムのパフォーマンス設計に関するベストプラクティス(ネットワーク要素編)
参考文献

コメント