マルチテナント ソリューションでのコンピューティングのアーキテクチャに関するアプローチ
ほとんどのクラウドベース ソリューションは何らかの種類のコンピューティング リソースで構成されています。たとえば、Web およびアプリケーション層、バッチ プロセッサ、スケジュール済みジョブ、さらに場合によっては GPU やハイパフォーマンス コンピューティング (HPC) などの特殊なリソースもあります。 マルチテナント ソリューションでは、多くの場合、共有コンピューティング リソースが活用されます。インフラストラクチャに対するテナントの密度が高いほど、運用コストと管理が削減されるためです。 分離の要件と、共有インフラストラクチャの影響を考慮する必要があります。
この記事では、ソリューション アーキテクトがマルチテナント コンピューティング レベルを計画する際に考慮する必要がある考慮事項と要件に関するガイダンスを提供します。 これには、コンピューティング サービスにマルチテナント機能を適用するための一般的なパターンと、回避すべきいくつかのアンチパターンが含まれます。
主な考慮事項と要件
マルチテナント機能と選択する分離モデルは、コンピューティング リソースのスケーリング、パフォーマンス、状態管理、セキュリティに影響を及ぼします。 このセクションでは、マルチテナント コンピューティング ソリューションについて計画するときに判断が求められる、いくつかの重要な決定事項を確認します。
スケール
システムは、変化する要求に合わせて適切に動作する必要があります。 テナントの数とトラフィックの量が増えていくと、増加するテナント数に対応し、許容できるパフォーマンス率を維持するために、リソースの増量が必要になる場合があります。 同様に、アクティブ ユーザーの数やトラフィックの量が減少した場合、コスト削減のために自動的にコンピューティング容量を減らす必要がありますが、容量の削減はユーザーへの影響を最小限に抑えて実施する必要があります。
テナントごとに専用のリソースをデプロイすると、各テナントのリソースを個別にスケーリングする柔軟性が得られます。 コンピューティング リソースが複数のテナント間で共有されるソリューションの場合、それらのリソースをスケーリングすると、すべてのテナントが新しいスケールを利用できます。 ただし、スケールが全体的な負荷の処理に不十分な場合、すべてが影響を受けることにもなります。 詳細については、 ノイズのある近隣の問題に関する記事を参照してください。
クラウド ソリューションを構築する場合、 水平方向と垂直方向のどちらでスケーリングするかを選択できます。 テナントの数が増加しているマルチテナント ソリューションでは、水平方向にスケーリングすると柔軟性が向上し、全体的なスケールの上限が高くなります。
多くの場合、パフォーマンスの問題は、アプリケーションに負荷がかかるまで検出されません。 Azure Load Testing などのフル マネージド サービスを使用して、ストレスのかかった状態でアプリケーションがどのように動作するかを確認できます。
スケーリング トリガー
どちらのアプローチでスケーリングする場合も、通常は、コンポーネントをスケーリングするためのトリガーを計画する必要があります。 共有コンポーネントを使用している場合は、リソースを使用するすべてのテナントのワークロード パターンを検討することで、プロビジョニングする容量が必要合計容量を満たせるようになり、テナントに ノイズのある近隣の問題が発生する可能性が最小限になります。 また、テナントの数を考慮してスケーリング容量を計画できる場合もあります。 たとえば、100 テナントの処理に使用するリソースを判断している場合、追加のテナントをオンボードする際に、100 テナントを追加するたびにリソースが 2 倍になるようにスケーリングを計画できます。
State
コンピューティング リソースは "ステートレス" にすることも "ステートフル" にすることもできます。 ステートレス コンポーネントでは、要求と要求の間にあるデータは維持されません。 スケーラビリティの観点では、多くの場合、ステートレス コンポーネントは簡単にスケール アウトできます。新しいワーカー、インスタンス、またはノードをすばやく追加でき、要求の処理をすぐに開始できるためです。 アーキテクチャ上可能であれば、あるテナントに割り当てられているインスタンスを用途変更して、別のテナントに割り当てることもできます。
ステートフル リソースは、維持する状態の種類に基づいてさらに細分化できます。 "永続的な状態" は、永続的に保存する必要があるデータです。 クラウド ソリューションでは、コンピューティング層に永続的な状態を保存しないようにします。 代わりに、データベースやストレージ アカウントなどのストレージ サービスを使用します。 "一時的な状態" は一時的に保存されるデータであり、読み取り専用のメモリ内キャッシュと、ローカル ディスク上の一時ファイルのストレージが含まれます。
一時的な状態は、多くの場合、バックエンド ストレージ サービスに対する要求の数を減らすことで、アプリケーション層のパフォーマンスの向上に役立ちます。 たとえば、メモリ内キャッシュを使用すると、データベースに接続せず、また、最近別の要求を処理したときに実行した集中型クエリを実行せずに、読み取り要求を処理できます。
待機時間の影響を受けやすいアプリケーションでは、キャッシュのハイドレーションのコストが増大するおそれがあります。 テナントごとに異なるデータをキャッシュする必要がある場合、マルチテナント ソリューションによってこの問題が悪化するおそれがあります。 この問題を軽減するために、一部のソリューションでは "セッション アフィニティ" を使用して、特定のユーザーまたはテナントに対するすべての要求が同じコンピューティング ワーカー ノードによって処理されるようにしています。 セッション アフィニティを使用すると、アプリケーション層でキャッシュをさらに効率的に使用できるようになる反面、スケーリングすることや、ワーカー間でのトラフィック負荷のバランスをとることが難しくなります。 このトレードオフは慎重に検討する必要があります。 多くのアプリケーションでは、セッション アフィニティは必要ありません。
Azure Cache for Redis などの外部キャッシュにデータを格納することもできます。 外部キャッシュは、データ取得の待機時間を短くするように最適化されている一方で、状態をコンピューティング リソースから切り離したままにすることで、別個にスケーリングおよび管理できます。 多くのソリューションでは、外部キャッシュを使用することで、コンピューティング層をステートレスに維持しつつ、アプリケーションのパフォーマンスを向上できます。
重要
メモリ内キャッシュや状態を維持するその他のコンポーネントを使用する場合は常に、テナント間でデータのリークが起こらないようにしてください。 たとえば、データがテナントごとに分離されるように、すべてのキャッシュ キーにテナント識別子を付加するようにします。
分離:
通常、マルチテナント コンピューティング層を設計する場合、テナント間の分離レベルについて考慮するオプションが多く存在します。たとえば、すべてのテナントによって使用される 共有コンピューティング リソースのデプロイ、テナントごとの 専用コンピューティング リソース のデプロイ、 これら両極端の中間にあるオプションなどです。 各オプションにはトレードオフがあります。 ソリューションに最適なオプションを判断するために、分離に関する要件を検討してください。
テナントの論理的な分離について、および各テナントに適用される管理の責任またはポリシーをどのように分離するかが懸念される場合があります。 または、特定のテナントに別々のリソース構成をデプロイすることが必要な場合もあります。たとえば、テナントのワークロードに合わせて特定の仮想マシン SKU をデプロイするといったことです。
選択する分離モデルにかかわらず、コンポーネントが使用できない場合や誤動作した場合でも、テナント データが適切に分離された状態で維持されるようにします。 定期的な自動テスト プロセスの一環として Azure Chaos Studio を使用して、実際の障害をシミュレートするエラーを意図的に起こし、ソリューションによってテナント間でデータがリークされず、負荷のある状態でもソリューションが正常に機能することを確認してください。
考慮すべきアプローチとパターン
自動スケール
Azure コンピューティング サービスには、ワークロードをスケーリングするためのさまざまな機能が用意されています。 多くのコンピューティング サービスでは自動スケーリングがサポートされています。この場合、スケーリングのタイミングと、スケーリングの最小および最大のレベルを考慮する必要があります。 スケーリングに使用できる具体的なオプションは、使用するコンピューティング サービスによって異なります。 次のサービスの例を参照してください。
- Azure App Service: 要件に基づいてインフラストラクチャをスケーリングする、 自動スケーリング ルールを指定 します。
- Azure Functions: 関数によって実行する処理に基づいて自動的にスケーリングするイベントドリブン スケーリング モデルなど、 複数のスケーリング オプションから選択します。
- Azure Container Apps: 実行する処理と現在の負荷に基づいてアプリケーションをスケーリングする、 イベントドリブン自動スケーリング を使用します。
- Azure Kubernetes Service (AKS): アプリケーションの需要に対応するために、 ワークロードを実行するノードの数を調整する必要が生じる場合があります。 さらに、AKS クラスターでアプリケーション ワークロードをすばやくスケーリングする場合は、 仮想ノードを使用できます。
- 仮想マシン: 仮想マシン スケール セットでは、アプリケーションを実行する VM インスタンスの数を自動的に増減 できます。
デプロイ スタンプ パターン
デプロイ スタンプ パターン を使用してマルチテナント ソリューションをサポートする方法の詳細については、 概要に関する記事を参照してください。
コンピューティング リソース統合パターン
コンピューティング リソース統合パターン を利用すると、基になるコンピューティング リソースを共有することで、コンピューティング インフラストラクチャに対するテナントの密度を高めることができます。 コンピューティング リソースを共有すると、多くの場合、それらのリソースの直接コストを削減できます。 また、多くは、管理するコンポーネントが少なくなるため管理コストも低くなります。
ただし、コンピューティング リソースを統合すると、 ノイズのある近隣の問題が発生する可能性が高まります。 テナントのワークロードによって、使用できるコンピューティング容量が過剰に消費されるおそれがあります。 通常、このリスクを軽減するには、ソリューションを適切にスケーリングし、クォータや API 制限などのコントロールを適用してテナントがそれぞれの適正な割り当てを超える容量を消費しないようにします。
このパターンは、使用するコンピューティング サービスに応じて、さまざまな方法で実現されます。 次のサービスの例を参照してください。
- Azure App Service と Azure Functions: ホスティング サーバー インフラストラクチャを表す共有 App Service プランをデプロイします。
- Azure Container Apps: 共有 環境をデプロイします。
- Azure Kubernetes Service (AKS): マルチテナント機能対応アプリケーションを使用して共有ポッドをデプロイします。
- 仮想マシン: すべてのテナントで使用する 1 つの仮想マシン セットをデプロイします。
テナントごとの専用のコンピューティング リソース
テナントごとに専用のコンピューティング リソースをデプロイすることもできます。 専用リソースを使用すると、すべてのテナントのコンピューティング リソースが他から分離されることで、 うるさい隣人の問題のリスクが軽減されます。 また、それぞれの要件に基づいて、テナントのリソースごとに個別の構成をデプロイすることもできます。 ただし、リソースに対するテナントの密度が低いため、専用リソースは通常、コストが高くなります。
使用する Azure コンピューティング サービスに応じて、次のようなさまざまな専用リソースをデプロイする必要があります。
- Azure App Service と Azure Functions: テナントごとに個別の App Service プランをデプロイします。
- Azure Container Apps: テナントごとに個別の環境をデプロイします。
- Azure Kubernetes Service (AKS): テナントごとに専用のクラスターをデプロイします。
- 仮想マシン: テナントごとに専用の仮想マシンをデプロイします。
半分離コンピューティング リソース
半分離アプローチでは、ソリューションの側面を分離された構成にデプロイしつつ、他のコンポーネントは共有する必要があります。
App Service と Azure Functions を使用する場合は、テナントごとに個別のアプリケーションをデプロイし、共有の App Service プランでアプリケーションをホストできます。 このアプローチでは App Service プランが請求単位を表すため、コンピューティング層のコストが削減されます。 また、各アプリケーションにそれぞれ異なる構成とポリシーを適用することもできます。 ただし、このアプローチでは ノイズのある近隣の問題が発生するリスクが生じます。
Azure Container Apps を使用すると、複数のアプリケーションを共有環境にデプロイし、Dapr などのツールを使用して各アプリケーションを個別に構成できます。
Azure Kubernetes Service (AKS) と Kubernetes では、以下を含め、マルチテナント機能のさまざまなオプションをより広範囲に用意しています。
- 共有のクラスターとノード プールにデプロイされるテナント固有のリソースを論理的に分離するための、テナント固有の名前空間。
- 共有クラスター上のテナント固有のノードまたはノード プール。
- 同じノード プールを使用する可能性があるテナント固有のポッド。
AKS を使用すると、 ノイズのある近隣の問題を軽減するために、ポッドレベルのガバナンスを適用することもできます。 詳細については、「Azure Kubernetes Service (AKS) でリソースを管理するアプリケーション開発者のベスト プラクティス」を参照してください。
また、Kubernetes クラスター内の共有コンポーネントと、それらのコンポーネントに対するマルチテナント機能の影響についても理解しておくことが重要です。 たとえば、Kubernetes API サーバーは、クラスター全体で使用される共有サービスです。 テナント固有のノード プールを用意してテナントのアプリケーション ワークロードを分離する場合でも、テナント全体で多数の要求が発生すると、API サーバーで競合が起こるおそれがあります。
回避すべきアンチパターン
うるさい隣人のアンチパターン
テナント間で共有されるコンポーネントをデプロイするときは常に、 ノイズのある近隣の問題 のリスクが生じる可能性があります。 テナントのコンピューティング ワークロードが他のテナントのアクティビティに影響されるリスクを軽減するために、リソースのガバナンスと監視を含める必要があります。
テナント間でのデータ漏えい
コンピューティング層は、適切に扱われていない場合、テナント間でのデータ漏えいの対象になるおそれがあります。 通常、Azure でマルチテナント サービスを使用している場合は、これについて考慮する必要はありません。Microsoft がプラットフォーム レベルでの保護を用意しているためです。 ただし、独自のマルチテナント アプリケーションを開発する場合は、共有リソース (ローカル ディスク キャッシュ、RAM、外部キャッシュなど) に、別のテナントが誤って表示または変更できるデータが含まれているかどうかを検討してください。
ビジー状態のフロントエンドのアンチパターン
ビジー状態のフロントエンドのアンチパターンを回避するには、アーキテクチャの他のコンポーネントまたは層によって処理される可能性のある多くの作業が、フロント エンド層で実行されないようにします。 このアンチパターンは、マルチテナント ソリューションの共有フロントエンドを作成する場合に特に重要です。ビジー状態のフロントエンドによって、すべてのテナントのエクスペリエンスが低下するためです。
代わりに、キューやその他のメッセージング サービスを利用して、非同期処理を使用するようにします。 このアプローチでは、それぞれの要件に基づいて、さまざまなテナントに "サービスの品質" (QoS) コントロールを適用することもできます。 たとえば、すべてのテナントが共通のフロント エンド層を共有していても、 より高いサービス レベルの料金を支払っている テナントには、キュー メッセージから作業を処理するためにより高いレベルの専用リソース セットが提供される場合があります。
柔軟性のない/不十分なスケーリング
マルチテナント ソリューションが、バースト スケール パターンの影響を受けることがあります。 共有コンポーネントは、特にこの問題の影響を受けやすくなります。使用パターンが異なるテナントの数が多いほど、バーストの範囲が高まり、影響も大きくなるためです。
必ず、クラウドの柔軟性とスケールを適切に活用してください。 水平方向と垂直方向のどちらのスケーリングを使用するかを検討し、自動スケールを使用することで負荷の急増に自動的に対処します。 ソリューションをテストし、さまざまな負荷レベルでどのように動作するかを把握します。 必ず、運用環境で予想される負荷ボリュームと予想される増加量を含めます。 Azure Load Testing などのフル マネージド サービスを使用して、ストレスのかかった状態でアプリケーションがどのように動作するかを確認できます。
キャッシュ不使用のアンチパターン
キャッシュ不使用のアンチパターン とは、要求間で再利用される可能性のある情報が、アプリケーション層で繰り返し要求または再計算されるためにソリューションのパフォーマンスが低下する場合のことです。 テナント間または 1 つのテナント内のユーザー間で共有できるデータがある場合、バックエンド/データベース層への負荷を軽減するためにそれをキャッシュすることができます。
不要な状態保持
キャッシュ不使用のアンチパターンから判断できることは、不要な状態をコンピューティング層に格納することも避ける必要があるという点です。 状態を維持する場所とその理由を明確にします。 ステートフルなフロントエンドまたはアプリケーション層を使用すると、スケーリングできなくなるおそれがあります。 通常、ステートフルなコンピューティング層ではセッション アフィニティも必要になります。これによってワーカーまたはノード間でのトラフィックの負荷分散を効率的に実施できなくなるおそれがあります。
コンピューティング層に維持する各状態のトレードオフと、それによって、テナントのワークロード パターンが変化したときにスケーリングまたは拡張の可否が影響を受けるかどうかを検討してください。 また、Azure Cache for Redis などの外部キャッシュに状態を格納することもできます。
共同作成者
この記事は、Microsoft によって保守されています。 当初の寄稿者は以下のとおりです。
プリンシパルの作成者:
- Dixit Arora | FastTrack for Azure のシニア カスタマー エンジニア
- John Downs | プリンシパル ソフトウェア エンジニア
その他の共同作成者:
- Arsen Vladimirskiy | FastTrack for Azure のプリンシパル カスタマー エンジニア
次のステップ
コンピューティング サービスに関するサービス固有のガイダンスを確認します。