Webシステムのパフォーマンス最適化|流量制限設計のベストプラクティスまとめ

はじめに

ITシステムがクラウド化・マネージドサービス化し、内部構造が見えにくいブラックボックス化が進む現代、インフラエンジニアの需要は縮小する、と言う人もいます。しかし、私は必ずしもそうは思いません。特にパフォーマンス分野のエンジニアは今後も必要不可欠な職種です。なぜなら、システムがどれだけブラックボックス化しても、各システム特性に応じたパフォーマンスチューニングは避けて通れないからです。その一方で、パフォーマンス設計には難易度が高く、設計時に参考になる体系的なノウハウが十分に整理されていないと感じます。そこで本記事では、パフォーマンス設計におけるベストプラクティスのひとつとして、流量制限設計のノウハウをまとめて紹介します。

流量制限の目的

流量制限とは、ユーザからのリクエストが集中した状況においてシステムを安定稼働させるために、処理するリクエスト数に制限をかける機能です。ピーク日に想定以上のリクエストが発生した場合や、外部からのDDoS攻撃・Botアクセスなどによって大量のリクエストが送られた場合、制限を設けずに受け付けると、レスポンスが遅延し、最悪の場合はリソース逼迫によってサーバがダウンしシステム全体が停止する恐れがあります。またクラウド環境では想定以上のリソース消費が発生し、高額な利用料金を請求されるリスクもあります。

こうした事態を防ぐためには、流量制限を適切に設定し、性能試験でその有効性を確認することが重要です。さらに、設計段階で「瞬間的な高トラフィックに対する制限なのか」「継続的な高トラフィックに対する制限なのか」といった目的を明確化することが、効果的な流量制限設計のポイントとなります。

流量制限設計の基本方針

流量制限は、単一のレイヤーだけで実施すれば十分というものではありません。システムの特性や目的に応じて、各レイヤーごとに適切な流量制限を設けることが重要です。なお、どのレイヤーで流量制限を実施するかはシステム構成によって異なります。本記事では、以下の図を用いてWebシステムにおける流量制限設計のポイントを解説します。

バーストトラフィックに対する流量制限

バーストトラフィック(瞬間的な高トラフィック)に対しては、できるだけフロントエンド側(ロードバランサやAPI Gatewayなど)で流量制限を行うことが重要です。制限を後段のレイヤーで行うと、その手前にある要素(アプリケーションサーバやデータベースなど)に負荷が集中し、システム全体に影響を及ぼす可能性があります。ただし、システムによっては流量制限を行えるレイヤーに制約がある場合もあります。ここでは、考えられるいくつかの選択肢を紹介します。

1. CDN(Content Delivery Network)におけるバーストトラフィック対策
基本的な考え方として、最もフロントに位置するCDNで流量制限をかけるのが効果的です。ただし、利用するCDN製品によっては、期待どおりの流量制限を行えなかったり、監視・運用の負荷が大きく実装が現実的でない場合もあります。そのため、導入するかどうかは慎重に検討してください。ここでは、CloudflareとAkamaiにおける流量制限の方法を簡単に紹介します。

  • Cloudflareによる流量制限
    Cloudflareは、特定のURLまたはドメイン全体に対する過剰なリクエストを自動的に検出し、L7レイヤで流量制限を適用できます。例えば、10分間に100,000件以上のリクエストが発生した場合に、それ以降のリクエストをブロックしてHTTPステータス403(Forbidden)を返すルールを作成できます。この際、閾値を超えたすべてのリクエストを一定時間ブロックすることも、超過分のみをブロックすることも可能です。また、ブロックではなく、レスポンスを遅延させるスロットリングを設定することもできます。Cloudflareの無料プランでも流量制限は可能ですが、ルール数が1つに限られる、閾値超過時のアクションがブロックのみであるなど制約があります。商用利用を想定する場合は有料プランの導入を検討してください。例えば、Businessプラン以上であれば、追加料金なしでWaiting Room機能(※)を利用できます。

    ※Waiting Room機能
    アクセスが集中した際、設定した同時接続数の上限を超えるユーザーをWaiting Room(待機室)にリダイレクトさせる機能です。待機ユーザーは順番待ちとなり、空きが出たタイミングで本番サイトにアクセスできます。一般的にクッキーやトークンを発行し、リクエスト時間に応じて順序を制御します。
  • Akamaiによる流量制限
    Akamaiでの流量制限の発動条件や閾値超過時の挙動は、基本的にはCloudflareと大きく変わりません。ただし、目的に応じて適切なAkamai製品を選択する必要があります。例えば、IPアドレス単位での流量制限を実装する場合はKona Site Defender、APIごとに詳細な流量制限を設定する場合はAPI Gatewayを利用します。Cloudflareと比べると設定はやや複雑で難易度が高いため、Akamaiのサポートと相談しながらチューニングを進めることをおすすめします。Waiting Room機能に相当するものとしては、Akamai Visitor Prioritizationを利用できます。ただし、これは各Edgeサーバごとに制限を行う仕組みであり、全体トラフィックが増加するとバックエンドの処理能力を超える可能性があります。そのため、リアルタイム監視を適切に導入することが重要です。Akamai全体の流量制御について知りたい場合は、以下の記事を参照ください。
    Demystifying API Rate Limiting | Akamai Blog

2. ネットワーク機器におけるバーストトラフィック対策
CDNによる流量制限が難しい場合、その先にあるネットワーク機器(NW機器)で制限をかけることも可能です。NW機器には、ルータ、ファイアウォール、ロードバランサ、UTM、スイッチなど様々な種類がありますので、システム構成に合わせて導入を検討してください。ただし、NW機器での流量制限は主にL4(トランスポート層)以下のレイヤーで行われます。L7レイヤの流量制限に比べると、ユーザに詳細なエラー応答を返せないため、ユーザ側でリトライが発生しやすくなる可能性があります。そのため、他の機器での流量制限と併用することを推奨します。導入する機器によりますが、一般的なネットワーク機器で設定可能な主な帯域制限は以下のとおりです。

  • 分類(Classification)/マーキング(Marking)
    分類機能では、IPアドレスやMACアドレス、ポート番号などの情報を使ってトラフィックをグループ分けできます。分類ごとに優先度を設定し、それに基づいて帯域制限を行うことが可能です。
    また、ネットワークトラフィックに特定のQoS(Quality of Service)情報を付与して、優先度を制御することもできます。
  • ポリシング(Policing)
    ポリシングは、事前に設定したトラフィック量の上限を超えたパケットを破棄する方法です。データ欠落が発生しますが、通信遅延が少ないため、リアルタイム性が求められる音声通信などに適しています。
  • シェーピング(Shaping)
    シェーピングは、トラフィック量の上限を超えたパケットをバッファに蓄積し、順番に送信する方法です。遅延は発生しますが、パケットロスが少ないため、ファイル転送などデータ欠落が許容できないサービスに適しています。

3. API Gatewayにおけるバーストトラフィック対策
API Gatewayでバーストトラフィックを制御する一般的な方法はスロットリングの設定です。スロットリングとは、一定時間内に受け付けるリクエスト数を制限する仕組みです。主要なAPI製品ごとにスロットリングの挙動が異なるため、各製品の仕様を正確に理解した上で設定することが重要です。ここでは、Amazon API GatewayとApigeeの例を紹介します。

  • Amazon API Gatewayにおけるバーストトラフィック対策
    Amazon API Gatewayでは以下の4つの単位でスロットリングを設定できます。
    – AWSリージョン(変更不可)
    – アカウント単位(変更可能だが上限変更の申請が必要)
    – APIのステージ(例:dev、prod)・メソッド(例:GET、POST)
    – クライアント(ユーザーやアプリケーション単位)

    一般的にはAPIのステージ・メソッドやクライアント単位で設定することが多いです。設定はAWSマネジメントコンソールのAmazon API Gatewayの「スロットリング設定」ページから行い、バースト制限の値を指定してください。スロットリング設定はレート制限とも連動します。例えば、バースト制限が10リクエスト/秒、レート制限が5リクエスト/秒の場合、最初の10リクエスト/秒は許可され、その後は1秒あたり最大5リクエストまで許可されます。それを超えるリクエストは制限されます。

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

4. Webサーバにおけるバーストトラフィック対策
Webサーバでは、バーストトラフィック(瞬間的なアクセス集中)に対して流量制限を行う際、同時接続数の制限が一般的です。ここでは代表的なミドルウェアにおける流量制限の方法を紹介します。

  • Nginxにおけるバーストトラフィック対策
    Nginxには複数の流量制限関連モジュールがあり、それぞれの機能は以下の通りです。

    – limit_conn(同時接続数制限)
    特定のキー情報に対する同時接続数を制限するモジュールです。多数のユーザーからの同時接続を制御することで、バックエンドサーバのリソースを保護できます。
    ・キーとしてIPアドレスを指定すれば特定の送信元からの接続を制限可能。
    ・キーとしてURIを指定すればURIごとに接続数を制限可能。

    – worker_processes / worker_connections(サーバ全体の同時接続数制限)
    limit_connは特定キー単位での制限のみ可能ですが、サーバ全体の同時接続数を制限するにはworker_processesとworker_connectionsを組み合わせます。

    最大同時接続数は以下の式で求められます。
    最大同時接続数 = worker_processes × worker_connections

     ・worker_processes:Nginxが生成するワーカープロセス数。サーバのCPUコア数に応じて調整、またはautoで自動設定。
     ・worker_connections:ワーカープロセス1つあたりの最大接続数。

    ※さらに、ワーカープロセスが開けるファイルディスクリプタの上限値(worker_rlimit_nofile)も合わせてチューニングが必要です。

    – limit_req(リクエスト数制限)
    特定のキー情報に対するリクエスト数を制限します。短時間に集中するリクエストを抑制し、バックエンドサーバの負荷を軽減します。
     ・limit_conn同様、IPアドレスやURIをキーとして設定可能。

    – limit_rate(帯域幅制限)
    1つの接続あたりの通信速度を制限します。特定ユーザーによる帯域の独占を防ぎ、他ユーザーの帯域を確保できます。速度はBytes/Second単位で設定可能です。

    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全体の同時接続数を制限できます(Apache 2.4以前ではMaxClients)。Apacheではこのほかにも流量制限関連のパラメータがあり、例えばListenキュー数を制御するListenBacklogなどがあります。以下はMaxRequestWorkersとListenキューの関係を示すイメージです。

Apache流量制限の詳細については別の記事に記載しているので、興味ある方はご参照ください。
【初心者向けApache入門】:並列処理の基本とパフォーマンス改善のコツ

継続的な高トラフィックに対する制限

バーストトラフィックについては、前述のとおりフロントの機器で制限を行いますが、継続的な高トラフィックに対する流量制限も重要です。特に、システムの中核であるデータベースサーバに想定以上の負荷がかからないよう、バックエンドでも適切な設定を検討することが重要です。

5. APサーバレイヤにおける高トラフィック対策
APサーバで制御すべきポイントは、主にスレッドプール、アプリケーション、DB接続の3つです。

  • スレッドプールによる高トラフィック対策
    Tomcatを例に、流量制限に関する主要なパラメータをご説明します。キューは2段階構造になっており、それぞれに適切な値を設定する必要があります。

    – acceptCount
    すべてのworkerスレッドが使用中の場合に受付可能な最大キュー長。キューがあふれると、受信した要求は拒否されます。
    – maxConnections
    サーバが同時に受け入れて処理できる最大接続数。上限に達した場合、接続自体は受け付けますが、workerスレッドによる処理は行われず待機状態となります。
    – maxThreads
    リクエストを処理するworkerスレッドの上限(最大同時実行数)。HTTPやAJPなど、各コネクタごとに設定可能です。

詳細は下記にまとめていますので、興味のある方はぜひご覧ください。
【Tomcat】コネクションプールのチューニングによる流量制限の方法をまとめてみた。

  • アプリケーションによる高トラフィック対策
    高トラフィックが発生する環境では、アプリケーションレベルで流量制限(Rate Limiting)を実装することも可能です。ただし、一般的にはネットワークやサーバレイヤで制御する方法が推奨されます。アプリケーションでの制限は実装の手間が増えるため、必要な場合にのみ検討すると良いでしょう。
    参考として、Java向けのライブラリ「Resilience4j」を使うと、簡単にレートリミッターを実装できます。公式ドキュメントには具体的なサンプルも掲載されていますので、興味がある方は確認してみてください。
    https://resilience4j.readme.io/docs/ratelimiter
  • DB接続に関する高トラフィック対策
    高トラフィック環境では、データベースへの同時接続が増えすぎると、接続待機やタイムアウトが発生することがあります。Tomcatでは、DB接続プールの設定を適切に調整することで、この問題に対応できます。

    – MaxTotal
    同時にプールに存在できるコネクションの最大数。これを超えるリクエストは待機またはタイムアウトととなる。
    – MaxWaitMills
    利用可能なコネクションがない場合に、コネクションが返却されるまで待機する最大時間(ミリ秒)。この時間を超えると例外が発生する。

詳細は下記にまとめているので興味ある方は見てみて下さい。
【Tomcat】コネクションプールのチューニングによる流量制限の方法をまとめてみた。

まとめ

Webシステムにおける流量制限のベストプラクティスの紹介は以上です。考慮すべきポイントが多く、設計の難易度は高いですが、システムの安定運用に欠かせない重要な要素です。そのため、性能試験を実施し、適切な設計に基づいてチューニングすることを推奨します。

他にもパフォーマンスに関する情報をまとめていますので、興味のある方はぜひご覧ください。
Webシステムのパフォーマンス設計に関するベストプラクティス(システム構成・ハードウェア要素編)
Webシステムのパフォーマンス設計に関するベストプラクティス(仮想化要素編(VMware))
Webシステムのパフォーマンス設計に関するベストプラクティス(ネットワーク要素編)

参考文献

第1回 チューニング① 多重度・流量制御の最適化 | gihyo.jp
現在のWebシステム開発・運用では、特に大規模化するシステムの安定稼働、パフォーマンスの向上、システムのスケールアップやスケールアウトの実現が求められます。
3.6 流量制御について :  Hitachi Application Server V10 ユーザーズガイド(UNIX®用)

コメント