タスクと呼び出すサービスの間のバッファーとして機能するキューを使用します。 この方法では、サービスが失敗したり、タスクがタイムアウトしたりする可能性がある断続的な負荷がスムーズになります。これは、タスクとサービスの可用性と応答性に対する需要ピークの影響を最小限に抑えるのに役立ちます。
コンテキストと問題
クラウド内の多くのソリューションは、サービスを呼び出すタスクを実行します。 この環境では、断続的に大きな負荷が発生すると、サービスのパフォーマンスや信頼性の問題が発生する可能性があります。
サービスは、それを使用するタスクと同じソリューションの一部である場合もあれば、頻繁に使用されるリソースへのアクセスを提供するパートナー サービスである場合もあります。 このような種類のサービスの例としては、キャッシュサービスやストレージ サービスなどがあります。 複数のタスクが同時に実行され、同じサービスを使用する場合、要求の量をいつでも予測することは困難です。
サービスでは、要求のピークが発生して過負荷になり、サービスが要求に迅速に応答できなくなる可能性があります。 大量の同時リクエストをサービスに送り込むと、それらのリクエストによって生じる競合に対処できない場合、サービスに障害が発生する可能性もあります。
ソリューション
タスクとサービスの間にキューを配置します。 タスクとサービスを非同期に実行します。 タスクは、サービスがキューに必要とするデータを含むメッセージを投稿します。 キューはバッファーとして機能し、サービスがメッセージを取得するまでメッセージを格納します。 サービスはキューからメッセージを取得し、それらを処理します。 高い変動率で生成できる複数のタスクからの要求は、同じメッセージ キューを介してサービスに渡すことができます。 次の図は、キューがサービスの負荷を平準化する方法を示しています。
キューは、同時タスクが大量の要求を生成した場合でも、サービスが独自のペースでメッセージを処理できるように、サービスからタスクを切り離します。 また、キューにメッセージを投稿するときにサービスを使用できない場合、タスクは遅延しません。
このパターンには次のような利点があります。
サービスの遅延はすぐには発生せず、アプリケーションに直接影響するため、可用性を最大化するのに役立ちます。 サービスが利用できない場合や現在メッセージを処理していない場合でも、アプリケーションはキューにメッセージを投稿し続けることができます。
キューの数とサービスの数は需要に応じて異なる可能性があるため、スケーラビリティを最大化するのに役立ちます。
ピーク時の負荷ではなく、平均負荷の要件を満たすのに十分なサービス インスタンスしか必要ないため、コストを制御するのに役立ちます。
Note
一部のサービスでは、システム障害の原因となる可能性のあるしきい値に需要が達したときに調整が実装されます。 スロットリングにより、利用できる機能が制限される場合があります。 これらのサービスに負荷平準化を実装して、需要がこのしきい値に達しないようにします。
問題と考慮事項
このパターンを実装する方法を決定するときは、次の点を考慮してください。
ターゲット リソースの過負荷を回避するために、サービスがメッセージを処理する速度を制御するアプリケーション ロジックを実装します。 システムの次のステージで需要が急増しないようにしてください。 負荷がかかっているシステムをテストして、必要な平準化が提供されていることを確認します。 必要な平準化を実現するには、キューの数と、メッセージを処理するサービス インスタンスの数を調整します。
メッセージ キューは一方向の通信メカニズムです。 タスクでサービスからの応答が必要な場合は、サービスが応答を送信するために使用できるメカニズムを実装することが必要になる場合があります。 詳細については、「Azure の
Asynchronous メッセージング オプション」を参照してください。 コンシューマー全体のダウンストリームへの総レートを制限せずに自動スケーリングしても、過負荷を下流の依存先に移すだけです。 このオーバーロードにより、これらのサービスが共有するリソースの競合が増加し、負荷を平準化するためにキューの有効性が低下する可能性があります。
プロデューサーの平均レートがコンシューマー レートを超えると、キューは増加し続け、待機時間が長くなります。 キュー長を監視し、安全な範囲内でコンシューマー数をスケールさせるか、プロデューサー側で処理を減らしてください。
このパターンは、メッセージの損失を防ぐためにキューの持続性に依存します。 ブローカーが永続ストレージにメッセージを保持しない場合、クラッシュまたは容量の制限により、コンシューマーが処理する前にエンキューされたデータが失われる可能性があります。 ディスクまたはレプリケートされたストレージにメッセージを保持するキュー サービスを選択し、そのサイズクォータとリテンション期間の制限を理解します。 リージョン障害時にもメッセージを保持する必要があるワークロードについては、geo-disaster recovery オプションを評価してください。
ほとんどのキュー サービスは、少なくとも 1 回のセマンティクスでメッセージを配信します。つまり、コンシューマーは同じメッセージを複数回受信できます。 同じメッセージを複数回処理しても同じ結果になり、重複レコードや二重課金などの問題を回避できるよう、コンシューマーロジックを べき等 に設計します。
一部のメッセージは、形式が正しくないデータが含まれているか、不足しているリソースを参照しているか、永続的なエラーをトリガーするため、処理できません。 これらのメッセージを無期限に循環させてキューをブロックするのではなく、 配信不能キューにルーティングします。 配信不能キューの深さを監視して、運用チームが障害を調査し、基になる問題を修正し、必要に応じてメッセージを再送信できるようにします。
プロデューサーとコンシューマーの間でキューを導入しても、特に複数のコンシューマーがメッセージを並行して処理する場合、すべての条件下で元の送信順序が保持されるわけではありません。 ワークロードで厳密な順序付けが必要な場合は、Azure Service Busで message セッションなどの機能を使用します。 厳密な順序付けが必要ない場合は、メッセージを任意の順序で処理するようにコンシューマーを設計し、スケーリングを簡略化します。
このパターンを使用する場合
このパターンは次の状況で使用します。
ワークロードが断続的に急増し、ダウンストリーム サービスに過大な負荷がかかることがあります。
回復性とコスト管理を向上させるには、要求の取り込みを処理スループットから切り離す必要があります。
このパターンは、次の場合に適さない場合があります。
呼び出し元には、待機時間の短い同期応答が必要です。
ワークロードボリュームは予測可能なほど低く安定しているため、キューの複雑さを増やすとメリットはほとんどありません。
ワークロード設計
ワークロードの設計において、キュー ベースのロード レベリング パターンをどのように使用して、Azure Well-Architected Framework の柱で取り上げられている目標と原則に対処できるかを評価します。 次の表は、このパターンが各柱の目標をサポートする方法に関するガイダンスを示しています。
| 柱 | このパターンが柱の目標をサポートする方法 |
|---|---|
| 信頼性設計の決定は、故障に対するワークロードの回復性を高め、障害の発生後にワークロードを完全な機能状態に回復させるために役立ちます。 | このパターンで説明するアプローチでは、タスクの到着を処理から切り離すことで、需要の急激な急増に対する回復性を提供できます。 また、キュー処理の誤動作を分離して、摂取に影響を与えないようにすることもできます。 - RE:06 スケーリング |
| コストの最適化では、ワークロードの投資収益率の維持と向上に重点を置いています。 | 要求やタスクの取り込みと負荷処理が分離されているため、このアプローチを使用すると、ピーク時の負荷を処理するためのリソースをオーバープロビジョニングする必要を軽減できます。 - CO:12 スケーリング コスト |
| パフォーマンス効率 は、スケーリング、データ、およびコードの最適化を通じて、ワークロード の需要を効率的に満たすのに役立ちます。 | この方法では、要求の取り込みを処理速度と関連付ける必要がないため、スループット のパフォーマンスを意図的に設計できます。 - PE:05 スケーリングとパーティショニング |
このパターンによって柱内にトレードオフが生じる場合は、他の柱の目標に照らして検討してください。
Example
Web アプリでは、外部データ ストアにデータを書き込みます。 Web アプリの複数のインスタンスが同時に実行される場合、データ ストアは要求に十分な速さで応答できない可能性があります。これにより、要求がタイムアウトになったり、調整されたり、失敗したりする可能性があります。 次の図は、アプリケーションのインスタンスからの同時要求に圧倒されるデータ ストアを示しています。
この問題を解決するには、キューを使用して、アプリケーション インスタンスとデータ ストアの間の負荷を平準化します。 Azure Functions アプリは、Service Bus キューからメッセージを読み取り、データ ストアに対する読み取り/書き込み要求を実行します。 Azure Functionsは、構成されたスケーリング境界内でターゲット ベースのスケーリングを使用して、Service Busバックログに基づいてインスタンスをスケーリングできます。 トリガーコンカレンシー設定を調整して、データ ストアを保護することもできます。 実装ガイダンスについては、「 ターゲット ベースのスケーリング と スケールアウトの制限」を参照してください。このチューニングを行わないと、ワーカー レイヤーはバックエンドの競合を再導入できます。
テクノロジのバリエーションとして、Azure FunctionsではなくAzure Container Appsを使用して同じパターンを実装できます。 この方法では、コンテナー化されたワーカーが Service Bus からのメッセージを使用してデータ ストアに書き込みます。 Container Apps は、キュー関連のスケール ルールに基づいて、構成された最小レプリカと最大レプリカの間でワーカーをスケーリングします。 イベント ソースとして Azure Queue Storage を使用して、同じアプローチを実装することもできます。 実装ガイダンスについては、「 Container Apps でスケーリング ルールを設定する」および「Container Apps を 使用してイベント ドリブン ジョブをデプロイする」を参照してください。
次のステップ
このパターンを実装する場合は、次のガイダンスも関連する場合があります。
Azure の非同期メッセージング オプション: メッセージ キューは本質的に非同期です。 タスクがサービスと直接通信する場合は、タスクのアプリケーション ロジックの再設計が必要になる場合があります。 同様に、メッセージ キューからの要求を受け入れるようにサービスをリファクタリングする必要がある場合があります。
Azure メッセージング サービス間の選択: Azure アプリケーションでメッセージングとキューのメカニズムを選択するのに役立つ詳細情報を取得します。
バックグラウンド ジョブを開発するための推奨事項: このパターンをバックグラウンド ジョブに適用して、アプリケーションで負荷が高い場合にメッセージ キューにバックグラウンド タスクの要求を格納できるようにします。
WebQueue-Worker アーキテクチャ スタイル: Web と worker の両方がステートレスです。 セッション状態は、分散キャッシュに格納することができます。 ワーカーは実行時間の長い作業を非同期的に行い、キュー上のメッセージによってトリガーすることも、バッチ処理のスケジュールに従って実行することもできます。
関連するリソース
競合コンシューマー パターン: 負荷平準化キューからメッセージ コンシューマーとして機能するサービスの複数のインスタンスを実行できる場合があります。 この方法を使用して、メッセージを受信してサービスに渡す速度を調整することができます。
調整パターン: サービスに調整を実装する簡単な方法は、キューベースの負荷平準化を使用し、すべての要求をメッセージ キューを介してサービスにルーティングすることです。 サービスは要求を処理できる速度で、必要なリソースを使い果たせず、競合の可能性の量を減らします。