マルチテナントのビジネスシナリオでは、データ量またはアクセス頻度が極めて高い「ホットスポットテナント」が、所属ノードの計算リソースおよびストレージリソースを独占することがあります。これにより、同一ノード上で動作する他のテナントのクエリパフォーマンスに影響が及びます。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');例
データの準備:
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;コマンドの実行:
-- 例:分散テーブル 'orders' 内のテナント '102' 用に隔離シャードを作成します。 SELECT isolate_tenant_to_new_shard('orders', '102', 'CASCADE');実行結果の確認:
関数は新規シャードの 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>
);移行戦略
ホットスポットテナントのシャードを移行
最も直接的な方法です。ホットスポットテナントの専用シャードを現在のノードから宛先ノードへ移行します。
ホットスポットシャードの現在位置を確認します:
-- 前ステップで取得したシャード ID(例:102108)に置き換えてください。 SELECT nodename, nodeport FROM pg_dist_shard_placement WHERE shardid = 102108;実行結果:
nodename | nodeport ----------+---------- 10.0.0.1 | 5432移行コマンドの実行:
-- 例:シャード 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);
非ホットスポットテナントのシャードを移行
ホットスポットテナント専用に現在のノードを完全に解放したい場合は、当該ノード上の他のすべての非ホットスポットシャードを順次移行できます。
ホットスポットノード上の非ホットスポットシャードを一覧表示します:
-- シャード 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非ホットスポットシャードを個別に移行します:
上記クエリ結果に基づき、これらのシャードを宛先ノードへ移行します。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>
);例
データの準備:
-- 新規スキーマ company1 を作成 CREATE SCHEMA company1; -- 分散スキーマとして定義 SELECT polar_cluster_schema_distribute('company1'); -- テストテーブルを作成 CREATE TABLE company1.users (id SERIAL, name TEXT);以下の
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)polar_cluster_schema_move関数を実行して移行を実施します。-- 例:'company1' スキーマをノード 10.0.0.2:5432 へ移行します。 SELECT polar_cluster_schema_move('company1', '10.0.0.2', 5432);