すべてのプロダクト
Search
ドキュメントセンター

PolarDB:テナント隔離

最終更新日:Mar 03, 2026

マルチテナントのビジネスシナリオでは、データ量またはアクセス頻度が極めて高い「ホットスポットテナント」が、所属ノードの計算リソースおよびストレージリソースを独占することがあります。これにより、同一ノード上で動作する他のテナントのクエリパフォーマンスに影響が及びます。PolarDB for PostgreSQL Distributed Edition は、テナント隔離機能を提供しています。この機能により、特定のテナントのデータを専用リソースを備えた独立したノードへオンラインで移行できます。これによってリソース競合を解消し、すべてのテナントに対して安定したパフォーマンスと可用性を確保します。

機能概要

標準的なマルチテナントアーキテクチャでは、リソース利用率を最大化するために、PolarDB for PostgreSQL Distributed Edition は、異なるテナントのデータをクラスター内のデータノード(DN)に均等に分散します。つまり、複数のテナントが同一ノードのストレージおよび計算リソースを共有することになります。

しかし、クラスター内に「ホットスポットテナント」が出現すると、この共有モードによって以下のような課題が生じます。ホットスポットテナントとは、データ量またはアクセスペイロードが他のテナントと比較して著しく大きいテナントです。

  • リソース競合:ホットスポットテナントからの頻繁なクエリ実行により、当該ノードの CPU、メモリ、I/O リソースが過剰に消費されます。その結果、同一ノード上の他のテナントのクエリパフォーマンスが大幅に低下します。

  • パフォーマンス変動:ホットスポットテナントから発生するバーストトラフィックにより、他のテナントのクエリ遅延が顕著に増加し、ユーザー体験に悪影響を及ぼします。

  • ストレージ不均衡:ホットスポットテナントの大量データにより、一部ノードのストレージ使用率が他のノードと比較して著しく高くなる場合があります。これにより、リソースの無駄や運用管理の複雑化が招かれます。

テナント隔離機能は、上記の課題を物理的なデータ移行によって効果的に解決します。ホットスポットテナントのデータ(シャードまたはスキーマ)を、十分なリソースを備えた独立ノードへ移行することで、リソースの完全な隔離を実現します。

主なメリット

  • 専用リソースの保証:ホットスポットテナントを専用ノードへ隔離することで、他のテナントとのリソース競合を防止します。これにより、コア業務のパフォーマンスと安定性を確保できます。

  • 全体パフォーマンスの向上:ノード間の負荷を均等化し、リソースボトルネックを解消します。これにより、クラスター全体のサービスパフォーマンスおよび安定性が向上します。

  • オンラインでのスムーズな移行:テナント隔離に伴うデータ移行はオンラインで実行されます。読み取りおよび書き込み操作(DML/DQL)をブロックせず、業務継続性に影響を与えません。

  • 柔軟な移行戦略:ホットスポットテナントを新規ノードへ移行するだけでなく、既存ノード上の他のテナントを順次移行して、当該ノードをホットスポットテナント専用に解放することも可能です。

注意事項

  • データ移行中は、ソースノードおよび宛先ノードのリソース負荷(CPU、I/O、ネットワークなど)が増加します。そのため、非ピーク時間帯に実施してください。

  • データ移行を実行する前に、宛先ノードに移行対象データを収容可能な十分なストレージ容量があることを確認してください。

水平分割(シャード単位)

テナント ID(tenant_id)で水平分割されたテーブルの場合、まずホットスポットテナント専用のシャードを作成し、その後そのシャードを宛先ノードへ移行します。

ステップ 1:テナント専用シャードの作成

isolate_tenant_to_new_shard 関数を実行することで、特定テナントのデータ向けに新しい独立シャードを作成できます。

構文

SELECT isolate_tenant_to_new_shard('<distributed_table_name>', '<tenant_ID>', 'CASCADE');

  1. データの準備:

    CREATE TABLE orders (
        order_id     BIGSERIAL,          -- 注文 ID(自動インクリメント)
        store_id     INT NOT NULL,       -- 店舗 ID(分散キーとして使用)
        product_name VARCHAR(255),       -- 商品名
        amount       DECIMAL(10, 2),     -- 注文金額
        order_time   TIMESTAMPTZ DEFAULT NOW(), -- 注文日時
        PRIMARY KEY (order_id, store_id) -- ※ 分散キーはプライマリキーに含める必要があります。
    );
    
    -- 'orders' テーブルを分散テーブルとして定義し、'store_id' 列で水平分割します。
    SELECT create_distributed_table('orders', 'store_id');
    
    -- 店舗 101 向けに 5 件の注文を挿入します。
    INSERT INTO orders (store_id, product_name, amount)
    SELECT 101, 'ノートパソコン - ' || i, 4999.00 + i FROM generate_series(1, 5) i;
    
    -- 店舗 102 向けに 5 件の注文を挿入します。
    INSERT INTO orders (store_id, product_name, amount)
    SELECT 102, 'メカニカルキーボード - ' || i, 899.00 + i FROM generate_series(1, 5) i;
  2. コマンドの実行:

    -- 例:分散テーブル 'orders' 内のテナント '102' 用に隔離シャードを作成します。
    SELECT isolate_tenant_to_new_shard('orders', '102', 'CASCADE');
  3. 実行結果の確認:
    関数は新規シャードの ID を返します。

     isolate_tenant_to_new_shard
    -----------------------------
                          102108

    この時点で、ID 102108 のシャードが作成されますが、まだ元のノード上に存在します。次のステップを実行して隔離を完了してください。

ステップ 2:シャードの宛先ノードへの移行

polar_cluster_move_shard_placement 関数を実行することで、前ステップで作成した専用シャードを、十分なリソースを備えた宛先ノードへ移行できます。ご要件に応じて、以下のいずれかの戦略を選択してください。

構文

SELECT polar_cluster_move_shard_placement(
    <shard_ID>,
    '<source_node_IP>',
    <source_node_port>,
    '<destination_node_IP>',
    <destination_node_port>
 );

移行戦略

ホットスポットテナントのシャードを移行

最も直接的な方法です。ホットスポットテナントの専用シャードを現在のノードから宛先ノードへ移行します。

  1. ホットスポットシャードの現在位置を確認します:

    -- 前ステップで取得したシャード ID(例:102108)に置き換えてください。
    SELECT nodename, nodeport FROM pg_dist_shard_placement WHERE shardid = 102108;

    実行結果:

    nodename  | nodeport
    ----------+----------
    10.0.0.1  |     5432
  2. 移行コマンドの実行:

    -- 例:シャード 102108 を 10.0.0.1:5432 から 10.0.0.2:5432 へ移行します。
    SELECT polar_cluster_move_shard_placement(102108, '10.0.0.1', 5432, '10.0.0.2', 5432);

非ホットスポットテナントのシャードを移行

ホットスポットテナント専用に現在のノードを完全に解放したい場合は、当該ノード上の他のすべての非ホットスポットシャードを順次移行できます。

  1. ホットスポットノード上の非ホットスポットシャードを一覧表示します:

    -- シャード ID(例:102108)、およびホットスポットノード情報(例:'10.0.0.1' と 5432)に置き換えてください。
    SELECT shardid, shard_size
     FROM polar_cluster_shards
     WHERE table_name::text = 't' AND
           shardid <> 102108 AND
           nodename = '10.0.0.1' AND nodeport = 5432
     ORDER BY shard_size ASC, shardid ASC;

    実行結果:

     shardid | shard_size
    ---------+------------
      102104 |       8192
      102105 |      16384
      102106 |   83820544
      102107 |  256344064
  2. 非ホットスポットシャードを個別に移行します:
    上記クエリ結果に基づき、これらのシャードを宛先ノードへ移行します。

    SELECT polar_cluster_move_shard_placement(102104, '10.0.0.1', 5432, '10.0.0.2', 5432);
    SELECT polar_cluster_move_shard_placement(102105, '10.0.0.1', 5432, '10.0.0.2', 5432);
    ...

垂直分割(スキーマ単位)

独立スキーマによる垂直分割のシナリオでは、隔離処理がよりシンプルです。ホットスポットテナントの全スキーマを宛先ノードへ移行できます。

構文

SELECT polar_cluster_schema_move(
    '<schema_name>',
    '<destination_node_IP>',
    <destination_node_port>
);

  1. データの準備:

    -- 新規スキーマ company1 を作成
    CREATE SCHEMA company1;
    
    -- 分散スキーマとして定義
    SELECT polar_cluster_schema_distribute('company1');
    
    -- テストテーブルを作成
    CREATE TABLE company1.users (id SERIAL, name TEXT);
  2. 以下の SELECT 文の実行計画を確認すると、特定テナントに対するクエリは 1 つのみのノードにアクセスしていることがわかります。計画には、アクセス対象となる唯一の DN が 10.0.0.1:5432 であると示されています。

    EXPLAIN SELECT * FROM company1.users WHERE id = 1;
                                       QUERY PLAN
    --------------------------------------------------------------------------------
     Custom Scan (PolarCluster Adaptive)  (cost=0.00..0.00 rows=0 width=0)
       Task Count: 1
       Tasks Shown: All
       ->  Task
             Node: host=10.0.0.1 port=5432 dbname=postgres
             ->  Seq Scan on users_102010 users  (cost=0.00..25.88 rows=6 width=36)
                   Filter: (id = 1)
  3. polar_cluster_schema_move 関数を実行して移行を実施します。

    -- 例:'company1' スキーマをノード 10.0.0.2:5432 へ移行します。
    SELECT polar_cluster_schema_move('company1', '10.0.0.2', 5432);