ソリューション
分離とスケールを前提に設計するマルチテナントSaaSプラットフォーム
私たちは、SaaSプロダクトを支えるプラットフォームを構築します。テナンシーモデル、ID管理、課金、オンボーディング、リリースの仕組みは、100社目の顧客を最初の1社と同じ安全性で迎えられるかどうかを左右します。
課題の全体像
SaaSプロダクトは2つのシステムからなります。1つは顧客が目にするアプリケーションです。もう1つは、テナントをプロビジョニングし、ユーザーを認証し、プランを適用し、利用量を計測し、請求を行い、各テナントのデータを他のテナントから隔てるプラットフォームです。後者がロードマップに載ることはまれですが、ユニットエコノミクス、エンタープライズ対応力、そして成長に伴う苦労の大きさを決めるのはこちらです。
土台となる判断はテナンシーモデルです。プールモデルでは全テナントがコンピュートとストレージを共有します。効率が高く運用も単純ですが、厳格な論理分離が求められます。サイロモデルでは各テナントが専用リソースを持ちます。分離性は高い一方、運用とリリースのコストが上がります。ブリッジモデルはこの2つを組み合わせたもので、コンピュートは共有しつつデータベースやスキーマを分ける構成や、標準プランはプール型のインフラ、最大規模の顧客には専用スタックという構成が一般的です。いずれを選んでも、コスト、コンプライアンスに関する協議、ノイジーネイバーのリスク、デプロイの複雑さに影響が及びます。
私たちは、テナンシーに関する判断が明示され、コードで強制され、合理的な範囲で後から変更できるようにプラットフォームを設計します。テナントコンテキストはエッジで一度だけ確定し、すべてのサービス、クエリ、キャッシュキー、キューメッセージ、ログ行に引き継ぎます。プラットフォームのその他の部分はすべて、この保証の上に成り立ちます。
なぜ難しいのか
エンジニアリング上の課題
開発者の規律に依存するテナント分離
すべてのクエリがテナントフィルターを忘れずに付けることに分離が依存していると、条件が1つ漏れただけで、ある顧客のデータが別の顧客に露出します。これはSaaSプロダクトにとって最も深刻な障害です。分離は、行レベルセキュリティ、範囲を絞った認証情報、あるいは別々のストアによって、アプリケーションコードより下の層で強制しなければなりません。そうすれば、フィルターを忘れても全件ではなく0件が返ります。
ノイジーネイバー
共有インフラでは、1つのテナントの一括インポートや暴走したレポートがデータベース接続を使い果たし、他の全テナントのサービスを劣化させることがあります。テナント単位のレート制限、クォータ、ワークロード分離がなければ、最大の顧客が最小の顧客の体験を決めてしまいます。
エンタープライズのID要件
エンタープライズの購買担当者は、SAMLまたはOIDCによるシングルサインオン、SCIMプロビジョニング、多要素認証の強制、自社ディレクトリからのロールマッピングを当然のものとして求めます。これらを自前のユーザー名・パスワードテーブルに後付けするのは時間がかかり、誤りも起きやすく、しかも調達審査の場で阻害要因として表面化しがちです。
請求書と一致しないメータリング
従量課金では、課金対象のイベントをすべて正確に1回だけ数える必要があります。負荷時に欠落したイベント、リトライで二重に数えられたイベント、誤った期間に計上されたイベントは、顧客が異議を唱える請求書を生みます。メータリングは、課金連携の問題である以前に、データ整合性の問題です。
多数のテナントにまたがるリリース
大きなテーブルをロックするスキーママイグレーションは、全テナントを一度に停止させます。サイロ型のテナントでは問題が逆になり、数百のスタックがそれぞれ異なるバージョンへと乖離していきます。どちらの場合も、後方互換のマイグレーション、段階的なロールアウト、自動化されたフリート管理を含む、意図的なリリース設計が必要です。
テナント単位で見えない稼働状況
集計されたダッシュボードでは、あるテナントのリクエストが1時間失敗し続けている事実が埋もれます。サポートは顧客の問い合わせに答えられず、エンジニアリングはプラットフォーム全体の障害とテナント固有の障害を見分けられません。テレメトリーには、最初のリクエストからテナントの識別子を持たせる必要があります。
構築の進め方
アーキテクチャ
プラットフォームは、テナントを管理するコントロールプレーンと、テナントにサービスを提供するデータプレーンに分かれます。テナントコンテキストはエッジで一度だけ解決し、その下のすべての層で強制します。
- 01
コントロールプレーン
サインアップ、プロビジョニング、プランの割り当て、設定、利用停止、オフボーディングというテナントのライフサイクルを、一連のサービスが管理します。プロビジョニングは冪等なワークフローであるため、途中で失敗しても、作りかけのテナントを残すことなくリトライできます。どのテナントが存在し、そのリソースがどこにあるかについては、コントロールプレーンが唯一の信頼できる情報源となります。
- 02
テナント解決・分離層
テナントは、ゲートウェイで検証済みのトークンクレームまたはドメインから特定し、リクエストコンテキストとして伝播させます。PostgreSQLを用いたプール型の設計では、行レベルセキュリティのポリシーがすべてのクエリをそのテナントに束縛します。ブリッジ型やサイロ型の設計では、ルーティング層がテナントのスキーマ、データベース、またはクラスターを選択します。キャッシュキー、オブジェクトストレージのプレフィックス、メッセージトピックも同じ方法でスコープを限定します。
- 03
IDとアクセス管理
認証は、SAMLとOIDCによるテナントごとのSSO接続、SCIMプロビジョニング、設定可能なMFAポリシーに対応した、標準規格ベースのIDプロバイダーに委譲します。認可はテナントスコープのロールを用いたロールベースとし、中央のポリシーコンポーネントで評価するため、ルールはサービス間で一貫します。プラットフォーム運用担当者によるテナントデータへのアクセスは別途統制し、時間制限を設けてログに記録します。
- 04
メータリングと課金
各サービスは、冪等キーを付けた利用イベントを耐久性のあるストリームに送出します。集計パイプラインが重複を排除してテナントおよび請求期間ごとに集計し、その合計を、請求書発行、税務処理、代金回収を担う課金プロバイダーに連携します。生のイベントは保持するため、請求書のどの明細行も再構成して説明できます。
- 05
エンタイトルメントとフィーチャーフラグ
プランはエンタイトルメント、つまりテナントがどの機能を利用でき、どの上限が適用されるかとして表現します。各サービスはプラン名をハードコードせず、ローカルキャッシュを併用しながらエンタイトルメントサービスに問い合わせます。フィーチャーフラグは段階的ロールアウトのための別の仕組みです。これにより、コードをリリースすることと、ある顧客に機能を有効化することは、独立した判断になります。
- 06
リリース・マイグレーションパイプライン
デプロイはローリングまたはブルーグリーン方式で行い、自動ヘルスチェックとロールバックを備えます。スキーマ変更はexpand and contractパターンに従うため、ロールアウト中も新旧のアプリケーションバージョンが同じデータベースに対して動作します。サイロ型のテナントについては、Infrastructure as Codeとフリートオーケストレーターが、社内テナントや低リスクのテナントから順に、ウェーブに分けて変更を適用します。
- 07
テナント単位のオブザーバビリティ
ログ、メトリクス、トレースにはテナント識別子を持たせます。これにより、サービスレベル目標(SLO)、エラー率、コストをテナント単位で報告できます。クォータとレート制限は、ゲートウェイに加え、コネクションプールやキューといった共有リソースでも強制します。アラートは、プラットフォーム全体の平均値だけでなく、テナント単位の劣化に対しても発報します。
テナント対応エッジ
- カスタムドメイン
- テナント解決
- WAF
- テナント別レート制限
アイデンティティ・SSO
- SAML・OIDC
- SCIMプロビジョニング
- ロールと権限
- MFA
コントロールプレーン
テナントを管理し、テナントのトラフィックは処理しない
- テナントライフサイクル
- プランとエンタイトルメント
- 課金とメータリング
- フィーチャーフラグ
アプリケーションプレーン
- ステートレスサービス
- バックグラウンドジョブ
- テナントコンテキスト
- Webhook
データ分離
分離モデルはプラン階層ごとに選択
- 行レベルセキュリティ
- テナント別スキーマ
- 専用データベース
- テナント別の鍵
テナント別オブザーバビリティ
- 利用状況メトリクス
- テナントタグ付きトレース
- ノイジーネイバーアラート
- 監査ログ
プロジェクトの成果物
- コストと分離性の分析を含むテナンシーモデルの決定記録
- テナントのプロビジョニングとオフボーディングを自動化したコントロールプレーン
- SSO、SCIM、MFA、ロールベースアクセス制御を網羅するID連携
- 利用量メータリングのパイプラインと課金プロバイダー連携
- エンタイトルメントサービスとフィーチャーフラグのフレームワーク
- ゼロダウンタイムのデプロイとスキーママイグレーションのパイプライン
- テナント単位のダッシュボード、クォータ、アラート
着手する前に
早い段階で決めておくべきこと
- プール、サイロ、ブリッジのいずれか
- テナントが多数で性質も似ている場合は、データベースで分離を強制するプールモデルを基本とします。運用コストが最も低く、リリースも最も単純です。顧客が専用インフラ、独自の暗号鍵、特定のリージョンを求める場合はサイロを選び、それに見合った価格を設定します。プールを基本としつつ、テナントを専用リソースに配置する選択肢を持つブリッジモデルは、小規模チームと大企業の両方に販売するプロダクトに適しています。
- IDと課金は自作か、購入か
- それ自体が自社のプロダクトでない限り、どちらも購入します。マネージドのIDプロバイダーや課金プラットフォームには、プロトコル、税務、決済失敗時の処理に関する長年のエッジケースが織り込まれています。自作するのは、自社固有の部分、すなわちテナントモデル、エンタイトルメントのロジック、そして課金にデータを渡すメータリングパイプラインです。
- モジュラーモノリスか、マイクロサービスか
- 初期段階のプラットフォームには、モジュール境界が明確でデプロイ単位が1つの、よく構造化されたモジュラーモノリスのほうが適していることがほとんどです。サービスとして切り出すのは、あるモジュールが異なるスケール特性、リリース頻度、担当チームを持つようになったときです。最初から多数のサービスで始めると、それを正当化するだけのトラフィックや人員が揃う前に、運用の作業量だけが何倍にも膨らみます。
- シングルテナント構成をいつ提供するか
- 顧客の要件が論理分離では満たせず、かつ契約金額が運用コストを賄える場合に提供します。その前に、専用スタックのプロビジョニングとアップグレードが完全に自動化されていることを確認してください。手作業で構築したシングルテナント環境は、SaaS企業がいつの間にかホスティング事業者になってしまう典型的な経路です。
FAQ
よくあるご質問
既存のシングルテナント製品をマルチテナント化できますか。
多くの場合は可能ですが、作業はテナント列を追加するよりも大がかりです。リクエスト経路全体へのテナントコンテキストの導入、データ層での分離の強制、既存顧客のデータ移行、バックグラウンドジョブ、キャッシュ、ファイルストレージの作り直しが必要になります。通常は段階的に進め、分離層とコントロールプレーンから着手し、その後テナントをグループ単位で移行します。
テナント分離が機能していることを、どのように証明しますか。
セキュリティ特性としてテストすることで証明します。自動テストがすべてのAPIを通じてテナントをまたぐ読み取りと書き込みを試み、デリバリーパイプラインの中で実行されます。データベースのポリシーはアプリケーションコードとは独立にレビューおよびテストし、分離はペネトレーションテストの対象範囲にも含めます。
ゼロダウンタイムリリースはデータベースの変更にも対応できますか。
規律を守れば可能です。変更は後方互換のステップに分割します。新しい構造を追加し、両方に書き込み、既存データをバックフィルし、読み取りを切り替え、その後のリリースで古い構造を削除します。大きなテーブルをロックするような操作は、オンラインマイグレーションツールを使うか、バッチに分けて実行します。
どのクラウド上に構築しますか。
設計は特定のプロバイダーに縛られません。私たちは主要なパブリッククラウドに対応しており、運用負荷を下げられる箇所ではマネージドサービスを選択します。どのクラウドにするかは一般に、既存の利用環境、データレジデンシーの要件、プラットフォームを運用するチームのスキルに応じて決まります。
