次の方法で共有


Azure Cosmos DB for PostgreSQL でのマルチテナント SaaS アプリのモデル化

適用対象: Azure Cosmos DB for PostgreSQL (PostgreSQL の Citus データベース拡張機能を利用)

シャード キーとしてのテナント ID

テナント ID は、ワークロードのルート、またはデータ モデルの階層の最上位にある列です。 たとえば、この SaaS e コマース スキーマでは、ストア ID になります。

store_id 列が強調表示されているテーブルの図。

このデータ モデルは、Shopify などのビジネスでは一般的です。 複数のオンライン ストアのサイトをホストし、各ストアが独自のデータを操作します。

  • このデータ モデルには、Stores、products、orders、line_items、Countries など、多数のテーブルがあります。
  • Stores テーブルは階層の最上位にあります。 products、orders、line_items はすべて Stores に関連付けられているため、階層内で下位になります。
  • Countries テーブルは個々のストアに関連せず、複数のストアに共通です。

この例では、階層の最上位にある store_id がテナントの識別子です。 これが適切なシャード キーです。 store_id をシャード キーとして選択すると、1 つのストアのすべてのテーブルにまたがるデータを 1 つのワーカーで収集できます。

ストア別にテーブルを併置することには、次のような利点があります。

  • 外部キー、JOIN などの SQL カバレッジを提供します。 1 つのテナントのトランザクションは、各テナントが存在する 1 つのワーカー ノードに局所化されます。
  • 1 桁ミリ秒のパフォーマンスを実現します。 1 つのテナントに対するクエリは、並列化されず 1 つのノードにルーティングされるため、ネットワーク ホップを最適化しつつ、コンピューティングやメモリをスケーリングできます。
  • スケーリングします。 テナント数が増加したら、ノードを追加したり、新しいノードにテナントをリバランスしたり、大規模テナントを独自のノードに分離したりできます。 テナントの分離により、専用リソースを提供できます。

同じノードに併置されたテーブルの図。

マルチテナント アプリに最適なデータ モデル

この例では、ストア固有のテーブルをストア ID によって分散し、countries を参照テーブルにする必要があります。

store_idがさらにあらゆる場所で強調表示されたテーブルの図。

テナント固有のテーブルにはテナント ID があり、分散されていることに注意してください。 この例では、Stores、products、line_items が分散されます。 残りのテーブルは参照テーブルです。 この例では、Countries テーブルは参照テーブルです。

-- Distribute large tables by the tenant ID

SELECT create_distributed_table('stores', 'store_id');
SELECT create_distributed_table('products', 'store_id', colocate_with => 'stores');
-- etc for the rest of the tenant tables...

-- Then, make "countries" a reference table, with a synchronized copy of the
-- table maintained on every worker node

SELECT create_reference_table('countries');

すべての大きなテーブルにはテナント ID が必要です。

  • 既存のマルチテナント アプリを Azure Cosmos DB for PostgreSQL に移行する場合は、少し非正規化し、大きなテーブルにテナント ID 列がない場合は追加し、列の欠損値をバックフィルする必要があります。
  • Azure Cosmos DB for PostgreSQL 上の新しいアプリの場合は、すべてのテナント固有テーブルにテナント ID が存在することを確認します。

分散テーブルに対する主キー、一意キー、外部キーの各制約に、複合キーの形式でテナント ID を必ず含めてください。 たとえば、テーブルに id の主キーがある場合は、それを複合キー (tenant_id,id) に変えます。 参照テーブルのキーを変更する必要はありません。

パフォーマンス最適化のためのクエリの考慮事項

テナント ID でフィルター処理する分散クエリは、マルチテナント アプリで最も効率的に実行されます。 クエリのスコープが常に 1 つのテナントであることを確認します。

SELECT *
  FROM orders
 WHERE order_id = 123
   AND store_id = 42;  -- ← tenant ID filter

元のフィルター条件で目的の行が明確に識別されている場合でも、テナント ID フィルターを追加する必要があります。 テナント ID フィルターは、一見冗長ですが、クエリを 1 つのワーカー ノードにルーティングする方法を Azure Cosmos DB for PostgreSQL に指示します。

同様に、2 つの分散テーブルを結合するときは、両方のテーブルのスコープが 1 つのテナントであることを確認します。 スコープ設定を行うには、結合条件にテナント ID が含まれることを確認します。

SELECT sum(l.quantity)
  FROM line_items l
 INNER JOIN products p
    ON l.product_id = p.product_id
   AND l.store_id = p.store_id   -- ← tenant ID in join
 WHERE p.name='Awesome Wool Pants'
   AND l.store_id='8c69aa0d-3f13-4440-86ca-443566c1fc75';
       -- ↑ tenant ID filter

いくつかの一般的なアプリケーション フレームワーク用のヘルパー ライブラリがあり、これらを利用すると、クエリにテナント ID を簡単に含めることができます。 手順は以下のとおりです。

次のステップ

これで、スケーラブルなアプリのデータ モデリングの調査が完了しました。 次の手順では、選択したプログラミング言語を使用してデータベースに接続してクエリを実行します。