1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SaaSの3つのパーティショニングモデルを理解する

Posted at

これは何?

SaaSアーキテクチャにおけるマルチテナンシーのデータ分離戦略です。
各テナント(顧客企業)のデータをどう管理するかを決めるモデルです。

3つのモデル

サイロモデル(Silo Model)

各テナントごとに完全に独立したインフラを用意します。

  • データベース、サーバー、場合によってはAWSアカウントまで分離
  • メリット: 最高レベルのセキュリティと分離、テナントごとのカスタマイズが容易
  • デメリット: コスト高、運用管理が複雑

利用ケース:

  • 規制業界(金融、医療)で物理的分離が必須
  • 超大型エンタープライズ顧客(例: トヨタ、政府機関)
  • 「専用環境」として販売する高額プラン

ブリッジモデル(Bridge Model)

インフラは共有するが、データベースレベルで分離する中間的なアプローチです。

パターン1: スキーマ分離

CREATE SCHEMA tenant_a;
CREATE TABLE tenant_a.users (...);

CREATE SCHEMA tenant_b;
CREATE TABLE tenant_b.users (...);

パターン2: テーブル分離

CREATE TABLE users_tenant_a (...);
CREATE TABLE users_tenant_b (...);
  • メリット: サイロより安価、プールよりセキュア
  • デメリット: スケーラビリティに限界がある

利用ケース:

  • レガシーシステムからの移行過渡期
  • 中途半端な分離要件(正直、あまり使われない)
  • 技術的負債になりやすい

プールモデル(Pool Model)

すべてのテナントが同じテーブルを共有します。

-- テーブルは1つだけ
CREATE TABLE users (
  id INT PRIMARY KEY,
  tenant_id INT,  -- これでテナントを識別
  name VARCHAR(255),
  email VARCHAR(255)
);

-- テナントAのデータ
INSERT INTO users VALUES (1, 100, 'Taku', 'taku@company-a.com');

-- テナントBのデータ
INSERT INTO users VALUES (2, 200, 'Hanako', 'hanako@company-b.com');

アプリケーション側で常にフィルタリング:

// テナントAのユーザーを取得
db.Where("tenant_id = ?", currentTenantID).Find(&users)
  • メリット: 最もコスト効率が良い、スケールしやすい
  • デメリット: アプリケーションレベルでの厳密なテナント分離が必須

重要: WHERE句でtenant_idを付け忘れると、全テナントのデータが見えてしまいます。
SaaSでよくある「他社のデータが見えちゃった事故」は、このモデルでの実装ミスが多いです。

staging/productionとの違い

staging/productionは環境の分離、マルチテナンシーは顧客の分離で、別の概念です。

production環境
├── tenant_a (A社のデータ) ← マルチテナンシーで分離
├── tenant_b (B社のデータ)
└── tenant_c (C社のデータ)

staging環境
├── tenant_a (A社のテストデータ)
└── tenant_b (B社のテストデータ)

どれを選ぶべきか

プールモデルが最も広く使われているアプローチです。

AWS、Microsoft、Googleのマルチテナンシードキュメントでも、プールモデルを基本的なアプローチとして紹介しています。

  • Slack、Notion、GitHubなどの大規模SaaSがプールモデルを採用
  • スタートアップは初期コストの観点からプールモデルで開始するケースが多い
  • コスト効率とスケーラビリティに優れている
  • 何千・何万テナント追加してもDB構造は変わらない

実際のハイブリッド戦略

多くのSaaSでは、以下のような使い分けをしています:

- 大多数の顧客: プールモデル
- 少数の大口顧客: サイロモデル

推奨アプローチ

まずはプールモデルで設計して、大口顧客が来たらサイロを検討するのが王道です。

プールモデルのセキュリティ対策

// ミドルウェアで強制的にテナントスコープを適用
func TenantScopeMiddleware(tenantID string) func(*gorm.DB) *gorm.DB {
    return func(db *gorm.DB) *gorm.DB {
        return db.Where("tenant_id = ?", tenantID)
    }
}

// 使用例
db.Scopes(TenantScopeMiddleware(currentTenantID)).Find(&users)

このように、アプリケーション層でテナント分離を確実に実装することが重要です。

まとめ

  • プールモデルが最も広く使われている
  • サイロ・ブリッジは特殊ケース向け
  • まずはプールモデルで設計することを推奨
  • プールモデルではセキュリティ実装が最重要課題
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?