マルチテナントの SaaS 製品を、多くのチームがどんなシステムでも描くのと同じやり方で描くと、シングルテナントのシステムとまったく同じ見た目になります。ゲートウェイ、いくつかのサービス、データベース、という具合です。システムで最も重要な性質、つまりどの顧客のデータがどこに置かれうるのかは、図のどこにも現れません。しかし、まさにこの性質が最も難しい判断を左右します。テナントをどう分離するか、大口顧客にどう対応するか、オンボーディングをどう進めるか、そしてノイジーネイバー(noisy neighbor)が何を壊しうるか、です。
このガイドでは、マルチテナンシーをアーキテクチャ図で見えるようにする方法を紹介します。用語、図に描くべきこと、サイロ(silo)、プール(pool)、ブリッジ(bridge)の各モデル、そして共有リソースと専用リソースの両方を含む例を順に取り上げます。
用語
以下の用語は、AWS の SaaS ガイダンスをはじめ、SaaS アーキテクチャに関する文書で広く使われています。
- テナント(tenant)。 自社のユーザーとデータを持つ顧客組織です。
- コントロールプレーン(control plane)。 製品を提供するのではなく、テナントを管理するサービス群です。オンボーディング、テナントレジストリ(tenant registry)、ID 管理、メータリング、請求が含まれます。
- アプリケーションプレーン(application plane)。 製品そのもの、つまりテナントが日々使うサービスとデータストアです。
- テナントコンテキスト(tenant context)。 各リクエストとともに受け渡されるテナント ID です。通常はアクセストークンのクレームとして運ばれます。
- サイロ。 1 つのテナント専用のリソースです。個別のデータベースや、スタック一式がこれにあたります。
- プール。 多数のテナントが共有し、ポリシーとテナント ID で区切られるリソースです。
- ブリッジ。 両者の組み合わせです。たとえば、コンピューティングは共有しつつ、一部のテナントには専用データベースを用意します。
図に描くべきこと
- テナントコンテキストの出どころ。 ID プロバイダーと、テナント ID を運ぶトークンのクレームです。
- 分離を強制する場所。 「コードの中」ではなく、具体的な場所を示します。行レベルセキュリティのポリシー、テナントごとのスキーマ、個別のデータベース、IAM ポリシーなどです。
- どのリソースが共有で、どれが専用か。 各データストアとサービスに、プール型かサイロ型かをラベルで示します。
- リクエストがリソースを見つける方法。 テナントを正しいデータベースやスタックに振り分けるルーティングやルックアップです。
- テナントの作成方法。 レジストリに書き込み、必要に応じて専用リソースをプロビジョニングするオンボーディングのフローです。
サイロ、プール、ブリッジ
| モデル | 共有するもの | 長所 | コスト |
|---|---|---|---|
| サイロ | アプリケーションプレーンでは何も共有しない | 強い分離、テナントごとのチューニング、コンプライアンス上の説明がシンプル | テナントあたりのコストが高い、運用するデプロイが増える |
| プール | コンピューティングとデータ(テナント ID で区切る) | テナントあたりのコストが低い、デプロイは 1 つ | 分離がすべてのクエリとポリシーに依存する、ノイジーネイバー |
| ブリッジ | 一部のレイヤーは共有、一部は専用 | 重要な箇所に絞って分離にコストをかけられる | 構築、テスト、作図すべき経路が 2 つになる |
多くの製品はプールから始め、のちに最大規模の顧客や規制の厳しい顧客をサイロに移します。こうしてシステムはブリッジになります。図ではこの分かれ目をはっきり示すべきです。
例: プールのテナントとエンタープライズ向けのサイロ 1 つ
ある B2B 分析製品には、数百の標準テナントと、専用データベースを必須とするエンタープライズ顧客の Globex がいます。
- ユーザーは、テナントを識別できる ID プロバイダー でサインインします。アクセストークンには
tenant_idが含まれます。 - API ゲートウェイ がトークンを検証し、テナントコンテキストを 分析 API に渡します。
- 分析 API は、テナントのティア(tier)とデータベースを テナントレジストリ で調べます。
- 標準テナントは プール型の PostgreSQL データベース を共有し、行レベルセキュリティがすべてのクエリを
tenant_idで絞り込みます。 - Globex には、テナント作成時に オンボーディング サービスがプロビジョニングした 専用データベース があります。
ダイアグラムの内容
- Control plane
- Application plane
- Identity provider
- Tenant registry
- Onboarding
- Tenant A and B users
- Globex users (enterprise)
- API gateway
- Analytics API
- Pooled DB · RLS by tenant_id
- Silo DB · Globex only
- JWT tenant_id
- validate token
- tenant context
- tier and database
- standard tenants
- Globex only
- create tenant
- provision silo
2 つのフレームがコントロールプレーンとアプリケーションプレーンを分け、データストアのラベルがどの分離モデルを適用しているかを示します。これでレビュアーは的確な質問ができます。レジストリが落ちたらどうなるのか、テナントのティアを変更できるのは誰か、といった質問です。
マルチテナント図のルール
テナントではなくティアを描く
顧客ごとにボックスを描いてはいけません。ティアやデプロイモデルごとに経路を 1 つ描き、理解の助けになるなら、上の Globex のように例となるテナントの名前を添えます。
エッジにテナントコンテキストを書く
各ホップでテナントをどう識別しているかを書きます。たとえば JWT tenant_id、header X-Tenant-Id set by the gateway、tenant_id in the message です。バックグラウンドジョブやイベントコンシューマーにもテナントコンテキストが必要で、最も抜け落ちやすいのがこの部分です。
分離を強制する仕組みを図に載せる
「テナント ID で分離」は約束にすぎず、行レベルセキュリティのポリシー、テナントごとのスキーマ、個別のアカウントこそが仕組みです。その仕組みをデータストアのラベルに書くか、隣にポリシーノードを置きます。
テナントごとの制限を示す
テナントごとのレート制限、クォータ、同時実行数の制限は、プール型のシステムがテナント同士を守るための手段です。ゲートウェイと、それらを適用するサービスに書き添えます。
メータリングと請求はコントロールプレーンに置く
テナントごとの使用量イベントは、メータリングと請求の入力になります。これらをコントロールプレーンに描くことで、アプリケーションプレーンはリクエストの処理に専念できます。
よくある間違い
- コントロールプレーンがない。 オンボーディング、テナントレジストリ、ID 管理は、管理用ツールではなくアーキテクチャの中核です。
- 慣習頼みの分離。 「すべてのクエリはテナントで絞り込む」と書いたメモは、統制にはなりません。それを強制するポリシーを示しましょう。
- 見えないルーティング。 一部のテナントが別のリソースを使うなら、それを決めるルックアップを描きます。
- 忘れられた非同期経路。 テナント ID を失うキュー、スケジュールジョブ、分析データのエクスポートは、典型的な漏えいの原因です。
- 巨大な 1 枚の図。 データレジデンシー(リージョン)、デプロイ、論理ビューは別々の図にします。
Archboard で作る
- Google または GitHub でサインインし、図を作成します。
- 基本パックから フレーム ノードを 2 つ追加し、
Control planeとApplication planeという名前にします。 - 基本パックの ボックス ノード 2 つ(標準ユーザー用と Globex のユーザー用)、セキュリティパックの IDプロバイダー、クラウドパックの APIゲートウェイ、そして C4 モデルパックの コンテナ ノード(オンボーディングサービス用と分析 API 用)を追加します。
- データパックの Postgres ノードを、テナントレジストリ、プール型データベース、専用データベース用に追加し、ラベルに分離モデルを書きます。
- エッジにテナントコンテキストのラベルを付け、プロビジョニングのエッジを破線にします。
この例で使う図のノードは 11 個で、Free プランの範囲に収まります。その下にあるクラウドとネットワークの層については、AWS VPC の構成図とクラウドのユースケースページを参照してください。
よくある質問
どの分離モデルを選ぶべきですか? 顧客の要件と、テナントあたりのコストから考えます。運用コストが最も低いのはプール、セキュリティレビュアーに最も説明しやすいのはサイロ、両方を提供できるのがブリッジです。選んだ理由は図に書いておきましょう。
数百のテナントはどう表せばよいですか? 表しません。各ティアやデプロイモデルを 1 回ずつ描き、テナントの一覧は本来の置き場所であるレジストリに任せます。
テナントごとに図が必要ですか? いいえ。アーキテクチャごとに図を 1 枚用意し、そこにティアを描きます。サイロ型のエンタープライズテナントが別のアカウントやリージョンで動いているなら、そのテナント用のデプロイ図を別に用意してもよいでしょう。
データレジデンシーはどう表せばよいですか? 別のデプロイ図にリージョンのフレームを置き、それぞれに、そのリージョンにとどまる必要があるテナントのスタックやデータベースを入れます。
テナントごとの暗号鍵はどこに置きますか? 保護するデータストアの隣に、セキュリティパックのノードかメモとして置き、鍵を保管する鍵管理サービスも一緒に描きます。