re:Invent 2024: AWSが提案するCell-based SaaSアーキテクチャの実践
はじめに
海外の様々な講演を日本語記事に書き起こすことで、隠れた良質な情報をもっと身近なものに。そんなコンセプトで進める本企画で今回取り上げるプレゼンテーションはこちら!
📖 AWS re:Invent 2024 - SaaS meets cell-based architecture: A natural multi-tenant fit (SAS315)
この動画では、マルチテナントSaaSアーキテクチャにおけるCell-based Architectureの可能性について詳しく解説しています。AWS Solutions ArchitectのTod Goldingが、従来のSiloedモデルやPooledモデルに加えて、Cell-basedアプローチがもたらす新しい価値を説明します。特に、Noisy Neighbor問題の影響範囲を限定できることや、マルチリージョン展開時の柔軟性向上といったメリットが強調されています。また、Cellの実装方法として、事前プロビジョニングモデルと負荷ベースのプロビジョニングモデルの2つのアプローチが紹介され、それぞれのトレードオフについても具体的に解説されています。Cell-basedアーキテクチャの採用を検討する際の判断基準や、実装時の注意点なども包括的にカバーされています。
※ 画像をクリックすると、動画中の該当シーンに遷移します。
re:Invent 2024関連の書き起こし記事については、こちらのSpreadsheet に情報をまとめています。合わせてご確認ください!
本編
Cell-based Architectureの概要と本セッションの目的
ありがとうございます。re:Inventにご参加の皆様、ようこそ。本日はこのようにたくさんの方にお集まりいただき、大変うれしく思います。スライドにもありますように、私はAWSのSolutions ArchitectのTod Goldingです。この8、9年間、SaaS分野に特化して活動してきました。様々な分野のチーム、お客様、パートナー企業と協力しながら、AWS上でのSaaSソリューションの構築、提供、最適化に取り組んでまいりました。
この8、9年の間、私たちエンジニアはSaaSの分類体系をどのように説明するか、多くの時間を費やしてきました。SaaSには「これが正解」という単一の形はないことがわかりました - 組織によって独自のデプロイメントモデルやニーズ、要件があります。そこで、より体系的な構造が必要となり、テナントごとに専用リソースを持つSiloedモデルや、リソースを共有するPooledモデル、そしてその中間的なバリエーションを定義しました。また、EKS上でこれらのパターンを実現する方法や、Serverlessで実装する場合の様子など、様々な技術スタックについても検討を重ねてきました。
私たちは、優れたリファレンスアーキテクチャやコンテンツを通じて、これらの異なる技術戦略の実装方法について、re:Inventで十分な情報を提供できていると思います。しかし最近、Cell-based Architectureへの関心が大きく高まっているのを実感しています。Cell-based Architectureは長年存在している概念で、スケーラビリティとレジリエンスを実現するための優れた戦略であり、多くの優れた論文も発表されています。
人々は、マルチテナントSaaSの様々な概念 - デプロイメント、テナント分離、階層化、その他のアーキテクチャ上の考慮事項 - をCell-based Architectureとどのように組み合わせればよいのか疑問を持っています。Cell-based Architectureとこれらのマルチテナントの原則を組み合わせて、新しいデプロイメント戦略を生み出すことは可能でしょうか?このモデルについて、もっと早くから議論すべきだったと思います。アイデアは存在し、一部のお客様は既に実装していましたが、Cell-basedテクノロジーをSaaS環境に適用することについては、あまり議論されてきませんでした。
これが本日のトークの目的です。マルチテナンシーの原則とCell-basedの戦略がどのように交わるのか、その点について理解を深めていただきたいと思います。最も重要なポイントは、SaaSのデプロイメントモデルを検討する際に、より多くの方々にCell-based Architectureを選択肢の一つとして考慮していただき、自分たちの環境に適しているかどうかを検討していただきたいということです。これまで提唱してきた戦略もCell-basedモデルに組み込むことができますが、Cellsによって新しい次元が加わるのです。
これは300レベルのセッションです。今日はIDEを開いたりコードを見ていったりはしません。Cellsアーキテクチャの論理的な構造について見ていきます。まずはCellsアーキテクチャとは何か、どのように適合するのかを理解することから始めて、その後で実装やメカニズムに進んでいく必要があるからです。正直に申し上げますと、これは非常に広大な領域であり、Cell-basedアーキテクチャを検討する方法は数多く存在します。私はそれを刺激的だと感じていて、来年同じ講演をする機会があれば、きっと多くの新しい内容を追加することになるでしょう。
マルチテナントSaaSアーキテクチャの課題
Cell-basedアーキテクチャの詳細に入る前に、現在の状況を見ていく必要があります。 現在、マルチテナントSaaSアーキテクチャの構築方法を見てみると、これは非常に困難な領域です。SaaSの真の可能性を実現するアーキテクチャを構築するのは本当に難しいのです。確かに、マルチテナントアーキテクチャを稼働させ、これまで話してきたパターンのいくつかを実装することはできますが、運用効率とスケールメリットを全て実現するのは本当に困難です。
その理由の一つは、私たちの顧客やテナントのワークロードプロファイルが時として非常に多様だからです。顧客やテナントのワークロードパターンは大きく異なります。システムの一部のみを使用するテナントもいれば、一日の特定の時間帯にリソースを消費するテナントもいます。新しいテナントが参加し、既存のテナントが離れていく中で、環境の状況が常に変化しているため、適切なスケーリング戦略、レジリエンスアプローチ、分離方法を決定するのが難しくなっています。
技術面では、コンピュートスタックを検討する際にマルチテナンシーに関する多くの考慮事項があります。 Amazon EKSでは、Carpenterの使用、テナントごとのNamespaceの実装、Node Groupsの活用など、様々なオプションを検討する必要があります。適切なスケールとレジリエンス戦略を決定するための設定オプションは無数にあり、これらのパラメータの調整は非常に困難です。 ストレージについても同様の複雑さがあります。テナントストレージの分離方法、パーティショニングの扱い方、適切なサイジングの決定を考慮しなければなりません。RDSを使用する場合、Serverlessを使用しない場合は特定のインスタンスサイズを選択する必要がありますが、それらの選択は今日は適切でも明日には不十分となり、RDSのリサイジングが必要になる可能性があります。
ストレージのサイジングは、スケールメリットと効率性を追求しながらビジネスニーズに合わせようとする際に大きな課題となります。そして、ビジネスの現実も考慮しなければなりません。 どのようなドメイン要件があるでしょうか?どのようなコンプライアンスや規制上のニーズに直面しているでしょうか?これらの要因は設計にどのような影響を与えるでしょうか?さらに、Noisy Neighbor状態への対処、様々なパラメータにわたる分離の管理、実際のテナントのアクティビティにインフラリソースを合わせる消費の最適化など、考慮すべき様々な原則があります。
SaaSは非常に魅力的で興味深い分野だと感じていますが、多くの人がアーキテクチャに関するこれらの要件を全て満たすことに苦労していることも認識しています。影響を考慮して過剰なプロビジョニングを行ったり、最適な結果よりも単純さを重視して特定のテクノロジーを選択したりといった妥協をすることがよくあります。私たちはこれらの課題を分解してより管理しやすくするよう取り組んでいますが、依然として困難な状況が続いています。
従来のデプロイメントモデルとその複雑さ
デプロイメントモデルは、さらなる複雑さを加えています。 従来のSaaSの考え方では、私たちがプールド環境と呼ぶものでは、全てのテナントが全てのインフラストラクチャとストレージを共有します。これは単一のスケーリングターゲットを提供しますが、テナントの負荷が常に変化するため、効果的なスケーリングは依然として困難です。実際には、このようなシンプルなプールド環境だけで済むことは稀です。設計上の理由か顧客要件によって、通常はこれらの環境を異なるデプロイメントモデルにセグメント化する必要があります。 例えば、SLAの考慮事項、コンプライアンス要件、あるいはNoisy Neighborの問題により、分離が必要なAnalyticsサービスを除いて、テナント間で全てを共有するというケースがあります。このような場合、プレミアムティアのテナントにはそのサービスのスタンドアロンバージョンを提供することがあります。
また、あまり議論されない現実として、一部のテナントには完全にスタンドアロンな専用環境(Full-stack siloと呼んでいます)も提供しています。これは、組織に対して大きな財務的コミットメントを行う意思のある顧客向けに提供されるものです。 このような多様な環境では、新しいサービス、テナント、あるいはティアが導入される際に調整が必要となる、ターゲットを絞ったスケーリングとレジリエンスの戦略が求められます。
これら全体にわたる広範なニーズを見ると、さらなる複雑さが見えてきます。 どのデプロイメントモデルにおいても、プールされたリソースはレジリエンス、分離、そしてBlast radiusの観点から課題を提示します。全てのテナントを1つの環境に配置してコンピュートリソースを共有する場合、これらの側面を効果的に管理することは非常に複雑になります。
この共有環境では、テナントのコンピュートリソースは全ての処理で共有され、どのような種類の障害でも潜在的に全てのテナントに波及する可能性があります。新しいテナントが常に追加され、ワークロードが一日中変化している状況で、どのようにサイジングすればよいのでしょうか?Auto-scalingの利点を得るために、スケールアップとスケールダウンのための動的なスケーリングポリシーを設定することはできますが、非常に効率的な配信を実現するようなポリシーを作成することは本当に困難です。そのため、人々は選択の余地がないため、過剰なプロビジョニングを行うことになります。これは防御的な戦術として行われますが、何か問題が発生した場合の影響は障害につながり、それはSaaSにとって避けるべきアンチパターンとなります。
これらの環境のデプロイメントモデルも、ますます複雑になってきています。 リソースの一部がSiloで、一部がPooledという状態は、どういう意味を持つのでしょうか?オンボーディングや開発者のデプロイメントライフサイクルにおいて、これらの環境のインフラをプロビジョニングしてセットアップする方法について、異なる観点から考える必要があります。Kubernetesの例を見てみると、Argo、Flux、Helm Chartなどを使用して、異なるテナントの設定を追跡し、それらの設定を適切なエクスペリエンスにマッピングしようとしています。これはかなり複雑です。私たちはA/Bリリースやターゲットを絞ったリリースなども実施したいと考えていますが、このように分散化が進む中で、どのようにそれを導入すればよいのでしょうか?
最後に、最近特に顕著になってきているのが、 チームがソリューションの分散フットプリントを持ちたいと考えていることです。単一のリージョンだけでなく、新しいリージョンにビジネスを拡大したり、自分たちのリージョンでより多くのワークロードを実行したいと考えています。現在のフットプリントを超えて展開範囲を拡大するための適切なデプロイメントの単位が必要です。マルチリージョン運用になったからといって、DevOpsライフサイクル全体をやり直したり、環境の管理・運用方法を見直したりすることなく、どうすれば効果的に実現できるでしょうか?
これらはすべて、Cell-based Architectureを検討する際に考慮すべき点です。私にとって、これが今回の講演の動機であり、この全体的な考え方の背景にあるものです。Cell-based Architectureは、これらの課題に対処するためのよりシンプルな方法となる可能性があるのでしょうか?確かに、すべてがポジティブというわけではないトレードオフは生じますが、一部の組織にとって、Cell-basedアプローチは複雑さを軽減し、スケーリングやポリシー戦略に関する取り組みを変更し、ビジネスの柔軟性を高める良いソリューションとなるのでしょうか?これが、今日皆さんに持ち帰っていただきたい考えです。
Cell-based Architectureの基本概念と戦略
今日の従来の環境におけるCellについて考えると、すべてのテナントが1つの環境にいると考えています。確かに、一部はSilo化され、一部はPooledかもしれませんが、一般的に、それらを集合的にグループ化し、集合的に対処するポリシーや戦略を持つと考えています。Cell-based Architectureに移行すると、 テナントのグループをどのように取り、デプロイメントとスケールの単位として、それらを一緒にまとめて分離できるかを考え始めます。
これは論理的な構成です - お客様に「あなたはCell 2またはCell 1に配置されています」とは言いません。これは、アーキテクトとして、テナントをこれらのCellやグループに配置することで特定の利点が得られると言うためのメカニズムです。これらの利点は、現在の戦略よりもシンプルな方法で、あるいは場合によっては複雑さを増すかもしれませんが、より良いビジネス価値にマッピングされる形で、スケール、可用性、レジリエンスに対応します。このCell-based戦略の多くは、Cellに対してどのような戦略を使用するか、どのテナントをどのCellに配置するか、Cellがどのように稼働するか、マルチCell環境でのスケーリングが何を意味するかを決定することに関係します。CellがテナントのためのVPCやアカウントなのかと人々は尋ねますが、グループ化の構成は皆さん次第です。これは単なるタグ付けされた関係性かもしれません。
リソースのセットに対して、あるいはCell自体がCellを管理・実行するインフラストラクチャを持つような状況も見られます。ここには幅広い可能性があり、それを実現するための技術も多岐にわたります。戦略を選ぶという考え方について見ていきましょう。これは非常にオープンな領域だと思います。Cell戦略を選ぶための3つのステップをここでお伝えできれば良いのですが、それは難しいですね。それぞれのビジネスに適したCell戦略を決めるには、一対一で1時間くらいの議論が必要だと感じています。ただし、いくつかの極端なケースをご紹介することで、どのようなCell戦略を選ぶべきかのヒントにしていただけると思います。
一つの極端なケースは、Siloテナントを取り、それぞれを独自のCellに配置するというものです。Siloテナントをセルに配置することは、スケーリング機能ではなく、デプロイメントとグループ化の機能です。なぜなら、そのテナントは既に完全に分離されたリソースを持っているからです。つまり、突然スケーラビリティが向上したり、より耐障害性が高まったり、より分離されたりするわけではありません。ここでは、Cellをグループとしての管理や配置を行うための手段として使用します。
次に、インフラストラクチャを共有するPoolテナントについて考えます。図の左側にあるCell 1から始めましょう。Poolテナントをある制限に達するまでそこに配置していきます。制限とは何でしょうか?テナント数かもしれませんし、そのプール内のリソース消費量かもしれません。Cellが満杯とみなされる条件には様々なパラメータがあり得ます。そしてCell が満杯になったら、新しいCellを追加します。Cell 2を追加して、このプロセスを繰り返します。より多くのテナントを追加し、制限に達し、Cellが拡張の単位となっていきます。
ここで注目すべき点は、後ほど詳しく説明しますが、そのPoolセル、つまりCell 1のスケーリングは、そのCell内のテナントだけに限定されるということです。そのCell内のテナントがどのような振る舞いをしようとも、そのCell特有のスケールを構築するだけで済みます。Noisy Neighborの問題についても、全テナントにわたって考える必要はなく、特定のCell内のコンテキストでのみ考えれば良いので、Noisy Neighbor問題の複雑さがかなり軽減されます。 そして当然、これをTier戦略にマッピングすることもできます。これらはPremium Tierのテナント、これらはBasic Tierのテナントというように。Tieringとセルのグループ化には自然な相関関係があることが多いためです。
もう一つのアプローチとして、Siloテナントのグループをセルに配置するという方法があります。Siloテナントのグループをセルに配置する場合でも、各テナントは独自のインフラストラクチャ、つまり専用のインフラストラクチャを持つという前提があります。そのため、ここでもNoisy Neighborのスケールについてはあまり心配する必要がありません。Cell型アーキテクチャに移行した結果、何千ものCellができてしまうような事態は避けたいので、より多くのSiloテナントを1つのCellにまとめる方が現実的でしょう。Cellの数があまりにも多くなると、Cell自体の管理が新たな複雑さを生む要因となってしまいます。そのため、どのような戦略を選択する場合でも、その戦略が新しいCellの作成にどのような影響を与えるかを考慮する必要があります。
これについて別の考え方をすると - おそらく多くの方がこちらの方が理解しやすいと思いますが - まずは1つのCellを用意して、そこにすべてのテナントを配置することから始めます。 SiloテナントとPoolテナントがある場合、そのCellの中に両方を一緒に配置します。この例では、Silo Tenant 1用のVPCとSilo Tenant 2用のVPCがあります。ここではVPCを分離の仕組みとスケーリングの仕組みとして使用しています - すべてのリソースがそのVPC内にあり、独立してスケールします。そして、PoolテナントもVPCに配置し、この環境に追加していきます。このCellには、PooledとSiloedのテナントを任意の組み合わせで配置できますが、このCellがどの時点で飽和状態に達するかを定義するポリシーを、少し複雑にする必要があります。
Cell-based Architectureの実装と課題
ところで、多くの人が勘違いしがちなのですが、必ずしもパフォーマンスの基準に基づいてCellをスケールする必要はありません。つまり、ある一定のレベルに達したら収容しきれなくなるので移動しなければならない、というわけではないのです。そのCell内でも効果的にスケールすることは可能です。大量のテナントを追加しても、必ずしもCellに影響を与えるわけではありません。その代わりに起こることは、Pool VPC内で、Noisy Neighborの問題によってテナント同士が互いに影響を及ぼし始める可能性があるということです。そして、単にスケールの限界に達したからではなく、複雑性の観点から、環境に新しいCellを追加することになります。
新しいCellを追加する判断は、むしろ自社のポリシーと、そのCell内にどれだけのテナントを許容するかという判断に基づいています。これはそのCellのBlast Radiusに影響を与えるためです。Cell 1で障害が発生し、何らかのMicroserviceがダウンしてCell全体、あるいは少なくともPoolテナントがダウンしてしまった場合、それは望ましくない状況です。そのため、多くの場合、新しいCellが必要かどうかを判断する際は、そのCellにどの程度のフットプリントを許容するかを決めることが重要になります。この点について明確な基準をお示しできればよいのですが、これは境界を見極め、必要なCell数を決定することに関わる問題です。
このスライドは少し議論を呼ぶ可能性があるため、削除することも考えましたが、異なるCell Typeごとに異なるサイジングポリシーを持つことができるのではないかと考えました。つまり、システムに3つのティアがあり、それぞれにCell Type 1、Cell Type 2、Cell Type 3があるとして、それぞれに独自のサイジングポリシーを作成できるのではないかということです。ここでのポイントは、Cell Type 1に対して非常に具体的なサイジングポリシーを定義できますが、Cell Type 1のインスタンスは1つだけではないということです。Cell Type 1、Cell Type 2などの複数のインスタンスが存在する可能性があります。スケーリングポリシーについては、依然として3つのポリシーだけで済むため、何百ものスケーリングポリシーを管理する必要はありません。
最初に見たような状況、つまりMicroserviceレベルでのスケーリングポリシーを持つことになり、ポリシーが爆発的に増えてしまうという課題に対して、このモデルでは、Cell Typeとそれに対応するスケーリングポリシーさえあれば、それらの特定のポリシーを適切に調整するだけで済みます。ここで別々のサイジングポリシーは不要だという意見もあるかもしれませんが、Cell-basedモデルならではの利点として、他の環境では得られない柔軟性があると考えています。
これを実際のアーキテクチャに当てはめてみると、実装自体は大きく変わらないことに正直驚きました。Serverlessのリファレンスアーキテクチャを例に、Cell内部の仕組みとその構築方法を見てみると、今日のマルチテナントアーキテクチャとほぼ同じように構築されています。既存のリファレンスアーキテクチャをほぼそのまま流用できるんです。左側のFull-stack Poolでは、Pool型テナント用のCellがあり、Amazon API Gatewayと、Order、Product、Catalogの共有Microservicesがあります。Gatewayがこの環境内の特定のCellにトラフィックを振り分けます。
Silo型の方がより興味深いところで、テナントごとに専用のMicroservices、つまりLambda関数の個別コピーを持っています。これにより、スケールと遅延の面で効率化が図れます。この環境では、API Gatewayがどのシロにルーティングするかを判断する必要があります。Cell内部での間接参照という考え方がここでの重要なポイントになります。つまり、ルーティングの判断に必要な情報をどれだけCellに持たせるか、それともCellの外側に置くかという問題です。
同じことをAmazon EKSで実装する場合も、EKSのリファレンスアーキテクチャからの移行で済みますが、若干の違いがあります。通常のバージョンでは、Pool型が1つのNamespaceに、Silo型が別々のNamespaceにある1つのClusterになりますが、この場合は、Full-stack Pool環境用に別のClusterを作成しています。右側では、Silo型テナントごとに個別のNamespaceを用意しています。トラフィックのルーティングは、使用している任意のIngress Controller(NginxやIstioなど)に任せることができます。Cellsの良いところは、アーキテクチャを完全に作り直す必要がないことです。むしろ、既存のアーキテクチャをCells内にどう配置し、必要な調整をどう行うかが重要になります。
もう1つの概念として、Cellsのグループ化という問題があります。これは必ず出てくる話だと思うので含めました。グループ化の別の単位は必要でしょうか?グループの上にグループを重ねているような感じがしますが、Cellsのグループ化が必要になるケースもあるでしょう。左側では、Cellsのセットの周りにAWSアカウントを配置しています。
この考え方は、スケーリング時のアカウント制限を管理するためにCellsのセットが役立つというものです。アカウント制限に直面してCellsをスケールアウトする場合、別のAWSアカウントを立ち上げて、そこに次のCellsのセットを配置することができます。これにより、どのテナントがどのCellsやグループにいるかを追跡する必要が出てくるため、さらなる間接参照のレベルが追加されます。Virtual Private Cloud(VPC)も、このグループ化の概念を実装するもう1つのアプローチとなります。
Cell-based architectureの最も説得力のある活用例の1つが、マルチリージョン展開です。 マルチリージョン展開について議論する際、Cell-based architectureがよく話題に上がります。Cellは本質的に展開の単位であり、私たちがアーキテクチャを構築し、それをヨーロッパやカナダ、あるいは他のリージョンに展開したい場合、すでにテナントのグループとしてのCellを構築する作業は完了しています。それを機能させるためのDevOpsコンポーネントはすべて整っており、あとはそのCellを別のリージョンに展開するだけです。マルチリージョン展開のサポートには作業が必要で、DevOpsやオペレーションに影響を与えますが、Cellが別のリージョンに展開する単なるコンポーネントとなるため、移行はずっと簡単になります。同じ方法でオペレーションやDevOpsの経験に統合されるのです。
では、これらのCellを実際に活用する方法 と、それらをスケーリングし、実行時に管理する戦略について見ていきましょう。 私は可能性の連続体を表す2つの具体的なアプローチを特定しました。1つ目は、事前プロビジョニングCellと呼ぶものです。事前プロビジョニングCellモデルでは、この例では3つの空のCellを事前に作成します。環境のセットアップの一部として、Cellを事前にプロビジョニングして設定します。 その後、テナントが環境にオンボードする際に、各テナントをどこに配置するかを決定します。 オンボーディングプロセスでは、テナントのプロファイル、Tier、そしてCellの現在の構成を評価して、最適な配置を決定します。 このパターンは、事前プロビジョニングされたCell群全体にわたってテナントを戦略的に配置することで続きます。
Cell-based Architectureのオンボーディングとデプロイメント
もう1つのアプローチは、負荷ベースのCell プロビジョニングで、これはより動的な水平スケーリングCellに近いものです。このモデルでは、1つのCellから始めて、そのCellに対して定義された制限に達するまで完全に負荷をかけます。その制限に達すると、 次のCellをオンデマンドでプロビジョニングし、次のテナントセットをそこに配置します。 事前プロビジョニングCellでも、最終的にはすべてのCellが満杯になり、次のセットをいつ追加するかを考える必要が出てきます。重要な考慮事項は、スケーリング戦略と、事前プロビジョニングされたCellでアイドル状態のリソースを持つことが許容できるか、あるいはCellが空の状態で最小限の実行コストで済むかどうかです。
Cellに関してよく見落とされる側面は、Cellが静的ではなく、ライフサイクルを持っているということです。 ある時点でCell1とCell2が高密度に populated され、Cell3が部分的に埋まっているというスナップショットがあるかもしれませんが、テナントは出入りする可能性があります。テナントがシステムを離れたり、ワークロードが変化したりすると、Cellの再バランスに関する問題が発生します。例えば、あるCellのテナントの半分が離れた場合、そのCellをそのまま維持するか、何らかの対策を取るかを決める必要があります。この例では、Cell1に大きな空き容量があり、Cell2が埋まり始めています。私はCell2からCell1にテナントを移動させようと思います。
より良い例として、Noisy neighborの状況があります。最初は小規模で、あまり活動していなかったテナントをCell1に配置したとします。そのテナントが現在、大量のリソースを消費し、Cell内でNoisy neighborの状況を引き起こしています。私のCellは過密状態なので、 そのテナントを別のCellに移動させて、問題を軽減する必要があるかもしれません。これを実装するメカニクスは、アーキテクチャやテナントがCellにどのように紐付けられているかによって簡単ではありません。これは無料で得られる概念ではなく、機能させるには作業が必要です。しかし、これらのCellの全体的なライフサイクルと、時間とともにどのように進化していくかについて考えることが重要だと私は考えています。
シャーディングについて話しましたので、テナントのオンボーディングが実際に何を意味するのか、より具体的に見ていきましょう。 まずControl Planeから始めます。私たちの講演をご覧になった方はご存知かと思いますが、私たちはSaaSを2つの部分に分けて考えています。常にControl Planeについて説明しますが、これはマルチテナント環境を管理する横断的な部分を扱います。そしてApp Planeという概念に進みますが、これはアプリケーションの実際のスケーリングと分離が実現される場所です。オンボーディングはControl Plane内で行われ、私たちの例では常にControl Plane内でのオンボーディングの概念が示されています。このオンボーディングによって、SaaSアーキテクチャのすべての動く部分を自動化し、摩擦を取り除き、システムに新しいテナントを導入する際のスムーズな方法を提供します。
新しいテナントを導入する際、私たちのオンボーディングではCellについて、そしてそれが実装にとって何を意味するのかを考慮する必要があります。 テナントがシステムにオンボードしようとする際、このテナントをどこに配置すべきかを決定する必要があります。これは可能な実装アプローチの1つに過ぎません。Control Plane内にCell Insightsサービスを設置することができます。これは新しいサービスで、テナントの現在の作業プロファイルを分析します。すべての情報とテナントのプロファイルに基づいて、その特定のテナントに最適な配置戦略を教えてくれます。 すべてが問題ない既存のCellに配置するよう単純に指示するかもしれませんし、あるいは新しいCellをプロビジョニングしてそこにテナントを配置する必要があると判断するかもしれません。
シンプルですが見落としがちな側面として、テナントをCellに配置した後、その配置場所を記憶しておく必要があります。なぜなら、ルーティングやその他の操作の多くがこの情報に依存しているからです。 テナントの状態やポリシー、その他のテナントデータを保持するテナント管理の一部として、新たに管理・保存すべきポリシーデータが追加されます。それがテナントとCellのマッピングです。このマッピングは、どのテナントがどのCellに対応しているかを追跡し、さらにURLエントリーポイントやテナントへのアクセスやデプロイ時に必要な他の情報も潜在的に含みます。
このオンボーディングの話は、このトピックのより議論の余地がある、物議を醸す部分へと私たちを導きます。Cellを持つControl Planeがあり、このControl PlaneがこれらのCellをプロビジョニングしてセットアップします。通常、Cellのないサービスでは、Control PlaneとApp Planeがあり、そのApp Planeには何らかのものが配置されます。それがテナントごとのNamespaceであれ、個別のServerless関数であれ、ECSであれ、テナントごとの個別のアカウントであれ、通常はControl Planeと統合された1つの論理的なApp Planeが存在します。 Control PlaneはApp Planeからテレメトリを受け取ります。しかしCellがある場合、それぞれが独自のApp Planeを持つ必要があるため、そのApp Planeを作成する責任の所在を決める必要があります。通常であれば、ベースラインのプロビジョニングの一部としてApp Planeを1回作成するだけですが、Cellの場合、誰かがそのApp Planeを作成しなければなりません。オンザフライでCellを作成する場合、オンボーディング中に新しいApp Planeを作成する必要があり、これにより責任の分配が変わります。今やCellがその議論と、これらのものがどのように生成されるかというライフサイクルに新たな層を追加しています。
Control Planeはオンボーディングの一部を所有し、Application Planeはオンボーディングの別の部分を所有しており、これについては多くの議論があります。そこで、これについて考える方法をいくつか見ていきましょう。
1つのアプローチとしては、Cellは論理的な構成単位だということです。どのCellに何が属しているかは把握していて、これをスケールの単位として使用しますが、Control PlaneからApplication Planeの観点では、ただのネイティブな相互作用です。現在と同じように、単一のApplication Planeではなく、複数のApplication Planeと通信するだけです。あらゆる面で、CellはControl PlaneとApplication Planeの統合において最小限の役割しか果たしていません。
次に、もう1つのアプローチを見てみましょう。ここから少し複雑になってきますが、Cellがテナントを稼働させるために必要なリソースのライフサイクルをカプセル化するかどうかという点です。その責任の一部をCellに委ねることはできるでしょうか?これは、Cellが単なるグループ化の構成要素ではなく、実際にインフラストラクチャやサービスを持ち、場合によってはGatewayも持つことを意味します。ここで判断が必要になります:このアプローチを進めていく中で、CellはただのDestinationや組織的な構成要素から、Cell内の機能の一部を実際にカプセル化して所有する存在へと変化するのでしょうか?
この場合、CellにAPIを設置し、Cellがオンボーディングイベントを受け取り、Cell内のサービスがそれをどのように実現するかを決定します。また、テレメトリーもそこを通じて送信され、その方法はCellが収集すると決めたものに従います。Cell単位のテレメトリーがある場合、Cellとテナントの両方のテレメトリーを取得するためにこれらのサービスが必要になるかもしれません。私の考えでは、この選択に正解も不正解もありません。最初は左側のアプローチから始めて、最終的に右側のアプローチを選択することもあるでしょうが、Cell-basedモデルにおいては重要な選択となります。
Cell-based Architectureのルーティングと分散フットプリント
この同じ問題が興味深くなるもう1つの領域は、デプロイメントを考える時です。Cellがあり、新しいMicroserviceをデプロイする必要がある場合、開発チームが新しいMicroserviceを作成し、これらのサービスにデプロイする必要があります。シンプルな見方をすれば、パイプラインが持っているCellに関する情報や、そのマッピング、環境内のCell数を把握していて、3つのCellすべてにデプロイするだけです。しかし実際には、それらのCell内では、採用したデプロイメント戦略に応じて、SiloedリソースとPooledリソースが混在する環境があり、それは動的な関係にあります。固定的な確実性はありません。今日は2つのSiloedと1つのPooledがあるかもしれませんが、明日には4つのSiloedといくつかのテナントがPoolに存在するかもしれません。Cell内の構成は常に変化する可能性があります。
では、このデプロイメントの責任は誰にあるのでしょうか?CellがSiloedとPooledの判断を行うのでしょうか?なぜなら、デプロイメントモデルでは、新しいMicroserviceをデプロイする際に、これら2つのSiloとこのPoolにデリバリーする必要があることを知っておく必要があるからです。その責任はCell内にあるのか、それともパイプラインがそのマッピングを知っているのでしょうか?そのマッピングを外部に押し出せば押し出すほど、Cellの実装は他に分散されることになりますが、単純すぎて問題にならないかもしれません。しかし、それについて考え、デプロイメントマップ全体にどのように分散されるかを把握する必要があります。
セル内に何かが存在する場合にどのような状況になるのか、極端な例を挙げてご説明しましょう。セル内に実装を配置することにしたとします。この場合、セルにはアプリケーション層とは別個のインフラストラクチャとサービスが提供されます。このシナリオでは、セルが満杯になっています。オンボーディングプロセスに進み、この新しいテナントの配置のために何をすべきかを確認するためにCell Provisioningを確認します。適切な配置場所と方法を判断するために、InsightsとMetricsを参照することになります。
この例では、新しいセルが必要だと判断したとしましょう。新しいセルを作成する際、単にセル2とそのマッピングを作成するだけではありません。テナントが存在する前に、そこに必要な他のセル固有のインフラストラクチャも実際にプロビジョニングする必要があります。アプリケーション層のプロビジョニングは必要でしょうか?セル内のルーティングを処理するGatewayのセットアップは必要でしょうか?セル内のテナントの配置にマッピングする方法を判断するための特定のデプロイメントメカニズムのセットアップは必要でしょうか?これは極端な例で、このような大規模なクラスターインフラストラクチャは避けたいところですが、そのような知識の一部をクラスターに組み込むことは現実的な選択肢かもしれません。これにより、テナントをオンボードする際に、残りのプロセスを効率的に完了できます。
セルとその他のコンポーネントが準備できれば、新しいセル内にテナントを配置することができます。このプロセスには2つの段階があります:1つ目はセルのプロビジョニングとインフラストラクチャのセットアップ、2つ目はそのスペースへのテナントのプロビジョニングです。今後、チームでこの境界とベストプラクティスについて詳しく議論することになるでしょう。 開発者はこのデプロイメント側に関わることになり、つまりオンボーディング部分とデプロイメント部分があるということです。
次に検討すべきは、セルがルーティングにどのような影響を与えるかということです。Cell-basedアーキテクチャやマルチテナントアーキテクチャを見たことがある方なら、ルーティングが広範な議論を必要とする分野であることをご存知でしょう。セルが全くない状態で、単にNamespaceとテナントのサブドメインを持つEKS環境だけがあったとしても、そのテナントのサブドメインから特定のテナントのNamespaceへの経路を確立する必要があります。これは避けられない課題です。 常にこの作業が必要になります。しかし今は、テナントがセルの中にあるため、もう一段階の間接参照が必要になります。 つまり、どのインフラストラクチャにマッピングするかを知るだけでなく、どのセルにマッピングするかも知る必要があります。
Amazon API Gateway、Istio Ingress、nginxなど、どのようなルーティングツールを使用する場合でも、テナントとセルのマッピングを理解し、サブドメインや独自ドメインからのルーティングを実現する何かが必要です。 この文脈では、テナントコンテキストを渡す方法としてJWTについてよく話題に上ります。テナントコンテキストがセルに流れ込む際、Pooled環境であれば、単純にセルに流れ込んで完了し、すべてが上手く機能します。しかし、これらの環境内にSiloedワークフローがある場合はどうでしょうか? これは、さらに別のレベルの間接参照の問題につながります。
ここで問題となるのは、このルーティングがどの程度存在するのか - つまり、ルーティングがCell内にあるのか、それとも外層のルーティングがCellの中のインフラストラクチャーや各テナントを把握してマッピングを行うのか、ということです。これは先ほど議論した問題と全く同じです。私は明らかにルーティングからルーティングへの接続や、このような多層のルーティングは好ましくないと考えています。しかし、特にSilo化された環境を構築する場合、Cell-basedの世界ではこの決断を避けて通れません。 これをシンプルなバージョンで考えると、このアーキテクチャーはCellの有無にかかわらず、非常によく似た形になります。EKSのリファレンスアーキテクチャーを見ると、API Gatewayをファンクションの前に配置し、適切なファンクションにルーティングする環境が構築されています。
このモデルも同様です。API Gatewayがありますが、違いは直接ファンクションの前ではなく、Cellの前に配置されているということです。問題は、Cell内にもう1つAPI Gatewayが必要かどうかです。私としては、それは避けたいところです - Pooledモデルなら問題ありませんが、Siloモデルだと複雑になってきます。 最近では、システムの一部や特定のテナントを、自社で管理していない環境で実行する必要があるという企業が増えています。それは別のAWSアカウントかもしれませんし、オンプレミスかもしれません。メディアパターンでは、これを「SaaS Anywhere」と呼んでいますが、リモートとローカルの分散フットプリントに対応しなければならない企業が増えています。Cell-basedアーキテクチャーはこれに完璧に対応できるわけではありませんが、特に別のアカウントで実行する必要のあるテナントグループがある場合、Cellはその移行を自然に実現する方法となります。
Cell-based Architectureの利点とオペレーション
さて、最後に取っておいた論理的かつベストケースのシナリオですが - マルチテナンシーにおけるCell-basedアーキテクチャーの明らかな利点についてです。その1つが、明らかにNoisy Neighborの問題です。マルチテナント環境でのNoisy Neighbor問題への対処を考えると、非常に厄介です。なぜなら、今日のNoisy Neighborが明日もNoisy Neighborとは限らないからです。このような問題に対処するために、常にオーバープロビジョニングを行うのを避けるにはどうすればよいでしょうか?Noisy Neighborの影響範囲をCellに限定できるということは、Noisy Neighbor問題がそれほど深刻な問題ではなくなるということです。Cell内でもNoisy Neighborは発生する可能性がありますが、その範囲、性質、露出度ははるかに小さくなります。発生したとしても、それはCell内に限定され、すべてのテナントには影響しません - そのCell内のテナントにのみ影響します。多くの場合、この理由だけでCell-basedアーキテクチャーをマルチテナンシーに採用する企業もあります。なぜなら、Noisy Neighborへの対処ポリシーがはるかにシンプルになるからです。
Cell-basedアーキテクチャーについて語る人々を見ていると、Cellをテナント間の境界として使用し、環境内にもう1つの分離レイヤーを提供する方法として活用しています。 主な利点は、ルーターを導入してルーティングを行う際に、テナントのコンテキストとCellのコンテキストの両方を持つことができる点です。
Cellをプロビジョニングする際、これまで議論していなかった新しい要素として、Cell分離ポリシーを作成することがあります。これは従来、VPCをセットアップしてそのVPCの分離ポリシーを確立するのと同様です。 今度は、使用しているグルーピング構造に応じて、Cell用にこれを行う必要があります。プロビジョニング時にCellポリシーを設定する際は、Cell間の越境が不可能であることを確認します。マルチテナント環境では、あらゆるレイヤーで境界を越えることを防止したいと考えています。
このケースでは、Cell単位での分離によって、粗粒度の分離モデルを実装することができます。また、従来のテナント分離ポリシーも持っています。 これらはデプロイ時に分離されたリソースとして機能し、Lambdaの一部である個々の関数にIAMポリシーを付与することができます。これにより、Cell内でのクロスオーバーも防ぐことができます。これは、以前から使用している従来の手法を、単にCell modelの中で実現したものです。
そして、Cell-basedの境界を扱う多くの伝統的な純粋主義者が最も重要視する側面が、レジリエンスです。Cell-based Architectureの興味深い点は、自然とスコープされたレジリエンスが得られることです。これらのテナントを1つのCellにまとめて配置し、そのCell内で何か問題が発生した場合、その影響範囲はそのCellに限定されます。これは、レジリエンスのBulkheadモデルです。船のBulkhead(隔壁)のように、一区画に水が入っても、問題がその1つのBulkheadに封じ込められているため、船は沈まずに済むのです。
これは、人々がこのアプローチを選ぶもう1つの基本的な理由です。障害が発生した際に影響を封じ込めたい場合や、デプロイメントが誰かに影響を与える場合でも、それを1つのCellに限定したいのです。Wave deploymentやA/Bロールアウトを考える際、Cellは今やデプロイメントをより慎重にターゲティングする手段となり、デプロイメントの問題に対するレジリエンスをCell単位で適用することができます。
また、Cellが組織のオペレーションにどのように影響するかも考慮する必要があります。Cellには2つの側面があります。1つ目は、Cellからのテレメトリーとデータの集約には、私たちの経験上、新しいデータの表面化が必要だということです。Cellから経験データを送信する新しい方法が必要となり、そのための配管作業を実装する追加のオーバーヘッドが発生します。2つ目は、組織内でのオペレーションの可視性の単位としてCellを追加する必要があるということです。Cellのパフォーマンス、Cellの不安定性、Noisy neighborアクティビティの有無、新規テナントに対してCellをシャットダウンする必要があるかどうかを把握したいところです。
基本的に、マルチテナント環境のダッシュボードにCellを表示させ、動作について質問したり、問題を予測したりできるようにしたいのです。これにより、Cellのシャーディング戦略が機能しているか、スケーリング戦略が効果的かどうかを判断できます。一般的に、アプローチは大きく進化していくものですが、これらのインサイトがなければ、何が機能していて何が機能していないのかを把握することはできません。
Cell-based Architecture採用の判断と今後の展望
最も難しい部分は、Cell戦略の決定です。このような領域に参入してCell型デプロイメントを実装する場合、まずCellがあなたのサービス体験にもたらす価値から逆算して考える必要があります。単にCellが最新の技術だからとか、レジリエンスの側面が気に入ったからという理由で選択するのではありません。本当に重要なのは、スケーリングの性質、環境内のテナント数、そして組織のスケーリングの性質から逆算して考えることです。マルチリージョンへの展開を目指していますか?すでに予測されているNoisy Neighbor問題がありますか?あるいは、組織内で何らかのティア戦略がありますか?
これらのビジネス上の質問を、まずCell採用の前に検討する必要があります。
アーキテクトとして、ビジネスサイドからCell型アーキテクチャが必要だと言われることはないでしょう。Cell型アーキテクチャが適切な選択である理由を説明するのは、依然としてあなたの役割です。なぜCell型アーキテクチャを検討すべきか、どのような要因が関係しているのか、そしてビジネスにどのような価値をもたらすのかを明確に説明する必要があります。これをうまく説明できれば、特定の組織にとって非常に適したソリューションになると考えています。
私自身、Cell型アーキテクチャについてもっと話すべきだったと反省しています。というのも、数万のテナントを抱えておらず、複雑なスケーリングやデプロイメント技術を必要としない組織と関わることがあったからです。そのような組織にCell型モデルをより積極的に提案していれば、複雑さを軽減し、多くの課題を単純化できたかもしれません。すべての組織がCellを必要とするわけではなく、Cellが適さない場合もあって、それは全く問題ありません。これまで提唱してきた戦略はすべて有効で機能します。私たちはただ、Cell型アーキテクチャをこれに加え、検討すべき選択肢の一つとして提案したいのです。
現在、私たちが環境について説明する際には、Silo、Pool、Bridge、またはCellのどれを使用するか、そしてそれらの組み合わせのどれが最適かを議論します。 ここでスケールを描いていますが、これは天秤が特定の方向に傾くということを意味しているわけではありません。トレードオフについて考えていただきたいだけです。明らかに技術的およびビジネス的なトレードオフが存在します。Cellは過剰プロビジョニングモデルになる可能性があります。完全に統合された環境では、ポリシーを完璧に設定し、より細かなチューニングや、より的確なチューニングが可能で、より良い効率性が得られるかもしれません。ただし、それを機能させるために必要な労力とエネルギーは覚悟しなければなりません。
現在の環境よりも柔軟なデプロイメントが必要かどうか、マルチリージョン展開を検討しているか、あるいは環境のプロビジョニングプロセスが複雑すぎないかを考慮する必要があります。これらすべての要素を比較検討して、自身で判断する必要があります。 ここで、いくつかの重要なポイントをまとめてみましょう。 Cellという概念は必ずしも新しいものではありませんが、私が期待を寄せている興味深い可能性を秘めていることをご理解いただけたと思います。
Cellは新たな間接層や経験をもたらすことを認識しておく必要があります。これらはすべてが無償で得られるものではありません。Cell型でない環境でも、SiloやPod環境による多くの間接層が存在します。ここでは、Cellにアクセスし、さらにCell内の特定のリソースにアクセスする方法についても考慮が必要です。 Cellは、Noisy Neighborの制限やアカウント制限などの実際のスケール課題に対して、本質的に優れた対処能力を持っています。 リージョナルおよびリモートデプロイは、新しいデプロイメントユニット、つまり自己完結型のデプロイメントユニットとして機能し、テナントの配置に関して新しい柔軟性とオプションを提供します。
これは論理的な構成概念であることを意図的に強調しています - 実際の実装方法やその効果は、Cellのグループ化方法によって異なってきます。これらの構成がどうあるべきかについて、さらに多くのパターンを提供できると考えています。必ずしもVPCやアカウントである必要はないということです。 どのようなグループ化の単位を採用するかを決める必要があります。Cellを採用するかしないかという議論全体を通じて、常に複雑さと価値のバランスを考慮する必要があります。
アーキテクチャトラックで、Microservicesの適切なサイジングについての別の講演も行っていますが、その多くは複雑さに対する見返りをどのように得るかについて議論しています。何百ものMicroservicesがあっても、それらすべてが管理するには複雑すぎる場合、環境の複雑さに見合った見返りが得られていません。ここでも同じ考え方を適用する必要があります。 終わりに近づいていますが、ここではまだ多くのセッションが行われています。水曜日に私が話す予定のSaaS Builder Toolkitセッションと、アーキテクチャトラックの他のいくつかのブレイクアウトセッションも宣伝させていただきます。 また、Cell型アーキテクチャに興味のある方向けのワークショップも用意されています。
以上です。Multi-tenant SaaSについての本も出版していますが、これは決して宣伝ではありません。というのも、この本にはこの概念についてより詳しい内容が含まれているからです。アンケートへのご記入をお願いします。特にこのような新しいトピックについては、皆さんの共感を得られているか、そうでないかを知ることができる非常に有用なデータとなります。ご参加いただき、ありがとうございます。残りのre:Inventもお楽しみください。
※ こちらの記事は Amazon Bedrock を利用することで全て自動で作成しています。
※ 生成AI記事によるインターネット汚染の懸念を踏まえ、本記事ではセッション動画を情報量をほぼ変化させずに文字と画像に変換することで、できるだけオリジナルコンテンツそのものの価値を維持しつつ、多言語でのAccessibilityやGooglabilityを高められればと考えています。
Discussion