アプリケーション インスタンス、個々のテナント、またはサービス全体が使用できるリソースを制限します。 これにより、システムは突然または持続的な負荷の下で機能し、サービス レベル目標 (SLO) を満たすことができます。
コンテキストと問題
クラウド アプリケーションの負荷は、アクティブなユーザーとそのアクティビティによって時間の経過と同時に変化します。 営業時間中にサインインするユーザーが増え、システムは毎月の終わりに計算コストの高い分析を実行します。 突然のバーストも発生します。 処理要求が使用可能な容量を超えると、システムの速度が低下するか、失敗します。 システムに合意されたサービス レベルがある場合、その障害は SLO に違反します。
アプリケーションのビジネス目標に応じて、さまざまな負荷を処理するいくつかの戦略があります。 1 つの戦略は 自動スケールです。これは、プロビジョニングされたリソースを現在の需要に一致させ、コストを制御します。 ただし、新しいリソースのプロビジョニングには時間がかかり、コストが増えます。 容量の増加または予算を超える需要により、リソース不足が生まれます。
ソリューション
自動スケーリングの代わりに、リソース使用量を上限とし、使用量がその上限を超えたときに要求を調整します。 ワークロードは、独自のリソース使用量を監視し、使用量がしきい値を超えたときに 1 人以上のユーザーからの要求を調整します。 システムは引き続き機能し、その SLO を満たします。
スロットリングは制御ループであり、単一の受け入れ判断ではありません。 システムには、インフラストラクチャ使用率、アプリケーションの状態、プリンシパルごとのカウンターの 3 つの層で低遅延の信号が必要です。 彩度を継続的に測定し、明確に定義された境界で制限を適用し、トラフィック パターンの変化に応じてそれらの制限を調整します。 オーバーロードは、成熟したシステムが検出して回復する通常の動作モードです。 スロットリングにより、ワークロードに自己保護機能を備えることができます。
システムは、スロットリングまたは関連戦略をいくつか実装できます。
プリンシパルごとのレート制限: 定義済みのウィンドウで既に構成されたレートを超えたユーザーからの要求を拒否します。 この戦略では、システムは、各要求をプリンシパルに属性付けし、そのプリンシパルに対してリソースの使用状況を測定する必要があります。 マルチテナント ワークロードについては、 各テナントの使用量の測定に関するページを参照してください。
グレースフル機能の低下: 重要な機能に十分なリソースが含まれるように、不要な機能をオフまたは低下させます。 この戦略は、可用性のために応答の完全性を交換します。 たとえば、ビデオ ストリーミング アプリケーションの解像度が低くなる場合があります。
負荷平準化:キューを使用してアクティビティ ボリュームを滑らかにします。 マルチテナント環境では、平準化によってすべてのテナントのパフォーマンスが低下します。 テナントのサービス レベル アグリーメント (SLA) が異なる場合は、価値の高いテナントの作業をすぐに処理し、バックログが緩和されるまで優先順位の低い作業を保持します。 優先順位キュー パターンを使用するか、優先順位レベルごとに個別のエンドポイントを公開して、このアプローチを実装します。
優先順位ベースの遅延: 優先順位の低いアプリケーションまたはテナントに代わって操作を延期します。 操作を中断または制限し、後で再試行するようにテナントに指示する例外を返します。
送信レート制限: 外部依存関係が失敗した場合やエラーが返された場合は、独自の送信呼び出しを制限します。 ログの大量発生を防ぎ、正常でない依存先に対する再試行コストを回避するために、処理中のリクエスト数を減らします。 依存関係の復旧後に通常の要求フローを復元します。 たとえば、 NServiceBus はこの機能を実装します。
次のグラフは、A、B、C というラベルが付いた 3 つの機能を使用するアプリケーションの、時間の経過に伴うリソース使用量 (メモリ、CPU、帯域幅、およびその他の要因の組み合わせ) を示しています。機能とは、特定の一連のタスクを実行するコンポーネント、複雑な計算を実行するコード、メモリ内キャッシュなどのサービスを提供する要素など、特定の機能領域です。
線グラフは、y 軸のリソース使用率を x 軸の時間に対してプロットします。 3 つの色付きの線は、フィーチャ A、フィーチャ B、およびフィーチャ C を表し、フィーチャ A のラインが最も低く、フィーチャ B のラインが中央に、フィーチャ C のラインが最も高くなっています。 グラフの上部付近の実線は最大容量を示し、その下の破線はリソース使用率のソフト制限を示します。 2本の縦の破線が、時刻T1とT2を示しています。 T1 より前では、3 本のフィーチャーラインはすべて変動しており、フィーチャー C のラインは上昇してソフトリミットを超えます。 T1 では、フィーチャー B はフィーチャー A とフィーチャー C のリソースを解放するために中断されるため、機能 B のラインは 0 に低下し、T2 まで 0 のままです。フィーチャー C のラインは T1 と T2 の間のソフト制限を下回り、フィーチャー A は通常どおり継続します。 T2 では、機能 B が再開され、3 つの行すべてがソフト制限を下回って変動し続けます。
グラフは積み上げ面グラフです。 フィーチャー A のラインの下の領域には、フィーチャー A が消費するリソース、フィーチャー A とフィーチャー B のラインの間の領域には、フィーチャー B が消費するリソースが表示され、フィーチャー B とフィーチャー C のラインの間の領域には、フィーチャー C が消費するリソースが表示されます。 機能 C の行はスタックの一番上に配置されるため、時間の経過に伴うシステム リソースの合計使用量も表示されます。
グラフは、機能が段階的に低下する様子を示しています。 時間 T1 の直前に、リソースの合計使用量がしきい値に近づき、使用可能な容量が不足するリスクがあります。 フィーチャー B はフィーチャー A またはフィーチャー C よりも重要度が低いので、システムはフィーチャー B をオフにしてリソースを解放します。 T1 と T2 の間、フィーチャー A とフィーチャー C は正常に続行されます。 時間 T2 では、リソースの合計使用量は、機能 B をオンに戻すのに十分な量低下します。
オートスケーリング、段階的な機能低下、スロットリングを組み合わせることで、アプリケーションの応答性を維持し、SLA の範囲内に収めることができます。 需要が高いままになると予想される場合は、調整によって安定性が維持され、システムがスケールアウトされます。スケーリングが完了すると、システムは完全な機能を復元します。
次のグラフは、時間の経過に伴うリソース使用量の合計と、調整が自動スケーリングやその他の補正コントロールとどのように組み合わされるかを示しています。
線グラフは、y 軸上のすべてのアプリケーションのリソース使用率を x 軸の時間に対してプロットします。 2 本の水平参照線は、自動スケール前のリソース使用率と最大容量のソフト制限を示します。 時刻 T2 で始まる高い水平線は、自動スケール後の最大容量をマークします。 使用ラインは、時間の経過と同時に上昇し、変動します。 時間 T1 のソフト制限を超えています。これは、自動スケールが開始されるポイントです。 T1 から T2 の間では、自動スケーリングが行われている間、システムはスロットリングされ、使用率は自動スケーリング前の最大容量を下回ります。 時刻T2で、オートスケーリングが完了し、スロットリングが緩和され、使用率を示す線が上方に跳ね上がり、新たに引き上げられた最大容量を下回る範囲で変動し続けます。
時刻 T1 では、システムはソフト制限に達し、スケールアウトを開始します。新しいリソースが時間内に到着しない場合、需要によって既存のリソースが使い果たされ、システムが失敗する可能性があります。 スロットリングでは、リソース使用量をハード制限以下に抑えるため、スケールアウト中は過剰なリクエストを拒否し、新たな処理能力が利用可能になると、その制限を解除します。
Tip
エッジ コントロールとスロットリング パターンは、それぞれ異なる問題に対処します。 Azure DDoS Protection や Web アプリケーション ファイアウォール (WAF) のレート制限規則などのエッジ コントロールは、ネットワーク境界で実行され、アプリケーションに到達する前にボリュームトラフィックまたは悪意のあるトラフィックがドロップされます。 調整パターンは、アプリケーション内で実行され、アプリケーション定義の制限に対して 正当な トラフィックを測定します。 両方のレイヤーを一緒に使用します。 DDoS 保護では、正当なユーザーがサービスを過負荷にするのを防ぎません。アプリケーションの調整では、ボリューム攻撃を吸収しません。
問題と考慮事項
このパターンを実装する方法を決定するときは、次の点を考慮してください。
スロットリングの判断は早い段階で行ってください。 調整は、システム全体に影響を与えるアーキテクチャ上の決定です。 後から導入するとコストがかかります。
スロットリング制限を、最初に飽和するコンポーネントに合わせます。
要求レートは、制限する最も使い慣れたディメンションですが、実際のボトルネックは、多くの場合、同時の実行中の要求、キューの深さ、CPU またはメモリの使用率、またはダウンストリームの依存関係の独自の制限です。 1 秒あたりの要求数の制限では、ボトルネックがファンアウト ポイントでのコンカレンシーであるシステムは保護されません。
ゲートウェイ、サービス、パーティション、下流の依存先など、スロットリングを適用する各境界で、どの要素が真っ先に飽和するかを特定し、その次元で制限を設定します。 ファンアウトポイントでの同時実行数を制限した保護については、スロットリングを補完する Bulkhead パターンを参照してください。
制限アルゴリズムを意図的に選択します。 保護するコンポーネントの許容範囲と一致させます。
アルゴリズム 動作と最適な適合 トークン バケット 構成されたサイズまでのバーストをサポートし、安定したリフィル レートを適用します。 短いスパイクを吸収する必要があるゲートウェイに使用します。 漏れバケット 一定のレートで出力します。 安定したイングレス レートを必要とするバックエンドに使用します。 固定ウィンドウ 実装は簡単ですが、ウィンドウの境界でバックツーバック バーストを許可します。 スライディング ウィンドウ 状態情報が増える代わりに、固定ウィンドウのウィンドウ境界問題を緩和します。 制限が影響を受けるユーザーを決定します。 リージョン ゲートウェイなどの大まかな単位でスロットリングを行うと、負荷を発生させているのがそのうちの少数のユーザーだけであっても、無関係な多くのユーザーに影響を及ぼす可能性があります。
1 つの制限が複数のノードにまたがる場合にカウンターが存在する場所を決定します。 ローカル カウンターは高速ですが、同じ呼び出し元が複数のレプリカに到達すると過小評価されます。 Redis などの共有ストア内の一元化されたカウンターでは、すべての要求が表示されますが、各決定に待機時間が追加されます。 グローバル レートを概算するには、レプリカ間で制限を分割し、定期的に調整します。
スロットリングの判断をすばやく行います。 システムは、負荷の上昇を検出し、反応し、負荷が緩和された後に正常に戻る必要があります。 このプロセスには、継続的なパフォーマンスインストルメンテーションが必要です。
崩壊寸前ではなく、先手を打って負荷を落とす。 コンポーネントが飽和した後でしかリクエストを拒否しないスロットルでは、呼び出し側がバックプレッシャーを受ける前にレイテンシが急増します。
使用率がハード上限に近づくにつれて、拒否するリクエストの割合を徐々に増やし始めます。 早期拒否は、呼び出し元にバックオフを促し、急激な制限がしばしば引き起こすレイテンシ崩壊を防ぎます。 プライマリ トリガーとして SLO に対する p99 待機時間を使用します。 p99 が既に侵害されている間、平均使用率は正常に見える可能性があります。
リクエストの価値を区別できる場合は、まず価値の低い作業や、より再試行しやすい作業から切り捨てます。 詳細については、「 優先順位キューパターン」を参照してください。
一時的な拒否が調整の結果であることをクライアントに通知する状態コードを返します。
- HTTP 429 (要求が多すぎます): 呼び出し元が、定義されたウィンドウで構成された要求レートを超えています。
- HTTP 503 (サービス利用不可): サービスは、多くの場合、予期しない負荷の急増のために、要求を処理できません。
クライアントが再試行戦略を選択できるように、
Retry-AfterHTTP ヘッダーを含めます。 呼び出し元が推測するのではなく、意図的に再試行するのに十分なコンテキストを返します。 たとえば、呼び出し元が超える制限に名前を付けたり、影響を受けるスコープを明確にしたり、成功するレートを提案したりします。 原因不明の拒否は、呼び出し元の適応には役立たない。依存関係からオーバーロードシグナルを吸収するのではなく伝達します。 呼び出し元をスロットリングするサービスは、自身の下流依存先から受け取るスロットリング応答も尊重しなければなりません。 サービスが暗黙的に再試行するか、一般的な HTTP 500 (内部サーバー エラー) 応答を返すことによってダウンストリーム 429 または 503 応答を非表示にした場合、呼び出し元は速度を下げず、増幅を再試行し、オーバーロードはアップストリームにカスケードバックします。 再試行 Storm のアンチパターンでは、このエラー モードについて説明します。 上流の呼び出し元にバックプレッシャーを返し、呼び出しチェーン全体で一体となって負荷を軽減します。
拒否にかかるコストを、それによって防げる作業のコストより低くする。 要求を拒否するときに、大量の認証、深い解析、または複雑なポリシー評価が必要な場合でも、拒否された要求が大量に発生しても、システムが飽和状態になる可能性があります。 要求パイプラインのできるだけ早い段階で拒否し、拒否パス自体をロード テストします。
スロットリングでは自動スケーリングに必要な時間を十分に稼げない場合に備えて計画を立てます。 需要の増加が新たな処理能力の稼働開始より速ければ、スロットル制御されたシステムであっても破綻する可能性があります。 そのような結果が許容できない場合は、より大きな予備容量を確保し、自動スケーリングをより積極的に設定します。
スロットリングの代替としてキャッシュを使用しないでください。 キャッシュにより、配信元の平均負荷は低下しますが、ピーク時の負荷はバインドされません。 すべてのキャッシュ ミスが配信元に渡され、大量のトラフィックの下で人気のあるキーの有効期限が切れると、多くの呼び出し元がそれを補充するために競合する可能性があります。 キャッシュを使用して通常時の負荷を軽減し、スロットリングで最悪の場合の影響を抑えます。 詳細については、 Cache-Aside パターンを参照してください。
通常、実行コストが等しくないため、さまざまな操作のリソース コストを正規化します。 たとえば、読み取り操作ではスロットリングの制限値が高くなる場合があり、書き込み操作では低くなる場合があります。 操作ごとのコストを無視すると、容量が枯渇し、攻撃ベクトルが作成される可能性があります。
スロットリング設定を実行時に変更できるようにします。 異常な負荷が到着したら、デプロイなしで制限を調整する必要があります。 デプロイは遅く、インシデントの間は危険です。 外部構成ストア パターンは、実行時に変更できるように構成を外部化します。
静的な制限ではなく、アダプティブ制限を検討してください。 一部のスロットリングSDKは、制限値が実際のコンポーネントの状態に追随するように、レイテンシやキュー深度のシグナルに反応します。 常に、アダプティブ リミッターを最大値に設定してペアリングします。
ワークロードの進化に合わせて制限を見直します。 アダプティブ リミッタは、SLO の変更、依存関係容量の変更、運用ごとのコストの変化など、あらゆる種類の誤差を追跡することはできません。 これらの入力に対して定期的なオペレーター レビューをスケジュールします。
このパターンを使用する場合
次のパターンを使用します。
システムをその SLO 内に保持するため。
1 つのテナントがアプリケーション リソースを独占しないようにするため。
アクティビティの急増に対応する。
システムに必要な最大リソース レベルを制限します。
高いグリッド炭素強度の期間中に低価値の計算を減らす。
ワークロード設計
ワークロードの設計においてスロットリング パターンをどのように使用して、Azure Well-Architected Framework の柱で扱われている目標と原則に対応するかを評価します。 次の表は、このパターンが各柱の目標をサポートする方法に関するガイダンスを示しています。
| 支柱 | このパターンが柱の目標をサポートする方法 |
|---|---|
| 信頼性設計の決定は、故障に対するワークロードの回復性を高め、障害の発生後にワークロードを完全な機能状態に回復させるために役立ちます。 | 誤動作を引き起こす可能性のあるリソース不足の発生を防ぐために、制限を設計します。 このパターンをグレースフル デグラデーション プランの制御メカニズムとして使用することもできます。 - RE:07 自己保護 |
| セキュリティ設計の決定により、ワークロードのデータとシステムの機密性、整合性、および可用性が確保されます。 | 自動処理によるシステムの不正使用が原因でリソース不足が発生するのを防ぐために、制限を設計できます。 - SE:06 ネットワーク制御 - SE:08 リソースの強化 |
| コストの最適化では、ワークロードの投資収益率の維持と向上に重点を置いています。 | 適用される制限により、コスト モデリングが通知され、アプリケーションのビジネス モデルに直接関連付けることができます。 また、使用率に明確な上限が設けられるため、それを考慮に入れてリソースのサイズを設定できます。 - CO:02 コスト モデル - CO:12 スケーリング コスト |
| パフォーマンス効率 は、スケーリング、データ、およびコードの最適化を通じて、ワークロード の需要を効率的に満たすのに役立ちます。 | システムが高需要下にある場合、このパターンは、パフォーマンスのボトルネックとなる可能性のある輻輳を軽減するために役立ちます。 また、うるさい隣人のシナリオを事前に回避するためにも使用できます。 - PE:02 容量計画 - PE:05 スケーリングとパーティショニング |
このパターンによって柱内にトレードオフが生じる場合は、他の柱の目標に照らして検討してください。
Example
次の図は、マルチテナントシステムにおけるスロットリングを示しています。
左側にラベル付けされた 3 人のユーザーは、マルチテナント Surveys アプリケーションのテナント (Adatum、Fabrikam、Contoso) を表します。 各ユーザーは、アプリケーションがテナントを識別するために使用するテナント固有のカスタム ドメインを介して要求を送信します。 Adatum は、surveys.adatum.com を通じて 1 秒あたり 5 つの要求を送信し、Fabrikam は 1 秒あたり 10 件の要求を surveys.fabrikam.com 経由で送信し、Contoso は 1 秒あたり 150 件の要求を surveys.contoso.com 経由で送信します。 右側の Surveys アプリケーション Web ロールは、各テナントの 1 秒あたりの要求率を測定します。 Adatum 要求フローと Fabrikam 要求フローがアプリケーションに渡されます。 Contoso のリクエスト フローは、要求レートがテナントごとの制限を超えているため、エラー: スロットリングされた応答によってブロックされています。
複数のテナント組織のユーザーは、クラウドでホストされているアプリケーションにアクセスして、アンケートに記入して送信します。 アプリケーションには、各テナントのユーザーが要求を送信する速度を監視するインストルメンテーションが含まれています。
1 つのテナントが他のテナントのユーザーの応答性と可用性を低下させるのを防ぐために、アプリケーションでは、1 つのテナントが送信できる 1 秒あたりの要求数のレートを制限します。 このアプリケーションは、制限を超える要求をブロックします。
次のステップ
関連するリソース
- 各テナントの消費量を測定する
- Azure での自動スケーリング
- Queue-Based 負荷平準化パターン
- 優先順位キュー パターン
- 外部構成ストレージパターン