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

ApsaraDB RDS:水平分割 (PL/Proxy)

最終更新日:Mar 29, 2026

PL/Proxy は、プロキシノードからリモートデータベースへの SQL 呼び出しをルーティングする PostgreSQL 拡張機能です。ApsaraDB RDS for PostgreSQL では、クラスターモードで使用してシャード間で書き込みを分散したり、ノード間でデータをレプリケーションしたり、コネクトモードで使用して特定のデータベースにクエリをルーティングしたりできます。

前提条件

開始する前に、以下を確認してください:

仕組み

PL/Proxy は、専用のプロキシノードで実行されます。クライアントが PL/Proxy 関数を呼び出すと、PL/Proxy はその呼び出しをインターセプトし、関数本文に埋め込まれたルーティングルールに基づいて 1 つ以上のデータノードに転送します。

クラスターモードでは、SQL/MED の CREATE SERVER 文を使用して、データノードを名前付きクラスターにグループ化します。各プロキシ関数は、呼び出しのルーティング方法を制御する RUN ON 句を指定します:

ルーティング動作
RUN ON ANY呼び出しをランダムに選択されたデータノードに送信します
RUN ON ALL呼び出しをすべてのデータノードにブロードキャストします (SQL レプリケーションやクロスシャード読み取りに使用)

コネクトモードでは、クラスター設定をスキップします。各関数は接続文字列を直接埋め込み、クエリを固定のターゲットデータベースにルーティングします。

注意事項

  • 同じ Virtual Private Cloud (VPC) 内の RDS インスタンスは、互いに直接アクセスできます。

  • 異なる VPC にある RDS インスタンス間でクエリをルーティングするには、中間プロキシとして同じ VPC 内に Elastic Compute Service (ECS) インスタンスを配置します。

  • クラスター内のデータノードの数は、2 のべき乗 (2、4、8 など) である必要があります。

拡張機能のインストール

プロキシノードのデータベースに接続し、以下を実行します:

CREATE EXTENSION plproxy;

クラスターの設定 (クラスターモードのみ)

コネクトモードを使用している場合は、このセクションをスキップしてください。

クラスターは CREATE SERVER で定義されます。各データノードはオプション (p0p1 など) として登録されます。オプションの数は 2 のべき乗である必要があります。

  1. クラスターサーバーを作成し、データノードを登録します:

    CREATE SERVER cluster_srv1 FOREIGN DATA WRAPPER plproxy
    OPTIONS (
        connection_lifetime '1800',
        disable_binary '1',
        p0 'dbname=pl_db0 host=100.xxx.xxx.72 port=5678',
        p1 'dbname=pl_db1 host=11.xxx.xxx.9 port=5678'
    );
  2. クラスターへのアクセス権を付与します:

    GRANT USAGE ON FOREIGN SERVER cluster_srv1 TO postgres;
  3. PL/Proxy がデータノードに認証できるように、ユーザーマッピングを作成します:

    CREATE USER MAPPING FOR postgres SERVER cluster_srv1 OPTIONS (user 'postgres');

テスト設定

以下のセクションでは、3 つの RDS インスタンスを使用して両方のモードをデモンストレーションします。

IPロールデータベースユーザー名
100.xx.xx.136プロキシノードpostgrespostgres
100.xx.xx.72データノードpl_db0postgres
11.xx.xx.9データノードpl_db1postgres

各データノードに users テーブルを作成します:

CREATE TABLE users (userid int, name text);

クラスターモードのテスト

水平シャーディング

RUN ON ANY は、各 INSERT をデータノードの 1 つにランダムにルーティングし、クラスター全体に書き込みを分散させます。

  1. 各データノードinsert_user 関数を作成します:

    CREATE OR REPLACE FUNCTION insert_user(i_id int, i_name text)
    RETURNS integer AS $$
        INSERT INTO users (userid, name) VALUES ($1, $2);
        SELECT 1;
    $$ LANGUAGE SQL;
  2. プロキシノードにプロキシ関数を作成します。PL/Proxy は関数名で呼び出しを照合するため、プロキシ関数とデータノード関数は同じ名前を共有する必要があります。

    CREATE OR REPLACE FUNCTION insert_user(i_id int, i_name text)
    RETURNS integer AS $$
        CLUSTER 'cluster_srv1';
        RUN ON ANY;
    $$ LANGUAGE plproxy;
  3. プロキシノードに読み取り関数を作成します。RUN ON ALL はすべてのデータノードにクエリを実行し、結果をマージします。

    CREATE OR REPLACE FUNCTION get_user_name()
    RETURNS TABLE(userid int, name text) AS $$
        CLUSTER 'cluster_srv1';
        RUN ON ALL;
        SELECT userid, name FROM users;
    $$ LANGUAGE plproxy;
  4. プロキシノードから 10 件のレコードを挿入します:

    SELECT insert_user(1001, 'Sven');
    SELECT insert_user(1002, 'Marko');
    SELECT insert_user(1003, 'Steve');
    SELECT insert_user(1004, 'lottu');
    SELECT insert_user(1005, 'rax');
    SELECT insert_user(1006, 'ak');
    SELECT insert_user(1007, 'jack');
    SELECT insert_user(1008, 'molica');
    SELECT insert_user(1009, 'pg');
    SELECT insert_user(1010, 'oracle');
  5. 各データノードにクエリを実行して、データがどのように分散されたかを確認します:

    RUN ON ANY は書き込みをランダムにルーティングするため、分散は不均一になります。
    -- On pl_db0
    SELECT * FROM users;
     userid |  name
    --------+--------
       1001 | Sven
       1003 | Steve
       1004 | lottu
       1005 | rax
       1006 | ak
       1007 | jack
       1008 | molica
       1009 | pg
    (8 rows)
    
    -- On pl_db1
    SELECT * FROM users;
     userid |  name
    --------+--------
       1002 | Marko
       1010 | oracle
    (2 rows)
  6. プロキシノードを介してすべての行を読み取ります:

    SELECT userid, name FROM get_user_name();
     userid |  name
    --------+--------
       1001 | Sven
       1003 | Steve
       1004 | lottu
       1005 | rax
       1006 | ak
       1007 | jack
       1008 | molica
       1009 | pg
       1002 | Marko
       1010 | oracle
    (10 rows)

SQL レプリケーション

RUN ON ALL は各書き込みをすべてのデータノードにブロードキャストし、すべてのノードを同期させます。

  1. 各データノードとプロキシノードに trunc_user 関数を作成します:

    -- On pl_db0 and pl_db1
    CREATE OR REPLACE FUNCTION trunc_user()
    RETURNS integer AS $$
        TRUNCATE TABLE users;
        SELECT 1;
    $$ LANGUAGE SQL;
    
    -- On the proxy node
    CREATE OR REPLACE FUNCTION trunc_user()
    RETURNS SETOF integer AS $$
        CLUSTER 'cluster_srv1';
        RUN ON ALL;
    $$ LANGUAGE plproxy;
  2. すべてのノードでテーブルを切り詰めます:

    SELECT trunc_user();
     trunc_user
    ------------
              1
              1
    (2 rows)
  3. プロキシノードにレプリケーション用の挿入関数を作成します。TARGET insert_user は、PL/Proxy に、すべてのノードで (データノードにすでに定義されている) insert_user 関数を呼び出すように指示します:

    CREATE OR REPLACE FUNCTION insert_user_2(i_id int, i_name text)
    RETURNS SETOF integer AS $$
        CLUSTER 'cluster_srv1';
        RUN ON ALL;
        TARGET insert_user;
    $$ LANGUAGE plproxy;
  4. 4 件のレコードを挿入します:

    SELECT insert_user_2(1004, 'lottu');
    SELECT insert_user_2(1005, 'rax');
    SELECT insert_user_2(1006, 'ak');
    SELECT insert_user_2(1007, 'jack');
  5. 両方のデータノードに同一のデータが含まれていることを確認します:

    -- On pl_db0
    SELECT * FROM users;
     userid | name
    --------+-------
       1004 | lottu
       1005 | rax
       1006 | ak
       1007 | jack
    (4 rows)
    
    -- On pl_db1
    SELECT * FROM users;
     userid | name
    --------+-------
       1004 | lottu
       1005 | rax
       1006 | ak
       1007 | jack
    (4 rows)
  6. RUN ON ANY を使用してプロキシノード経由で読み取ります。すべてのノードが同一のデータを保持しているため、どのノードも完全な結果を返します:

    CREATE OR REPLACE FUNCTION get_user_name_2()
    RETURNS TABLE(userid int, name text) AS $$
        CLUSTER 'cluster_srv1';
        RUN ON ANY;
        SELECT userid, name FROM users;
    $$ LANGUAGE plproxy;
    
    SELECT userid, name FROM get_user_name_2();
     userid | name
    --------+-------
       1004 | lottu
       1005 | rax
       1006 | ak
       1007 | jack
    (4 rows)

コネクトモードのテスト

コネクトモードは、クラスター設定を必要とせずに、クエリを単一の指定されたデータベースにルーティングします。関数に接続文字列を直接埋め込みます。

CREATE OR REPLACE FUNCTION get_user_name_3()
RETURNS TABLE(userid int, name text) AS $$
    CONNECT 'dbname=pl_db0 host=100.81.137.72 port=56789';
    SELECT userid, name FROM users;
$$ LANGUAGE plproxy;

SELECT userid, name FROM get_user_name_3();
 userid | name
--------+-------
   1004 | lottu
   1005 | rax
   1006 | ak
   1007 | jack
(4 rows)

モードの選択

クラスターモードコネクトモード
使用する状況水平シャーディングが必要な場合、またはノード間で書き込みをレプリケーションしたい場合接続文字列で特定のリモートデータベースにクエリを実行する必要がある場合
クラスターのセットアップが必要はい (CREATE SERVER、ユーザーマッピング)いいえ
データノード数の制約2 のべき乗である必要がありますなし
ルーティングRUN ON ANY (ランダム) または RUN ON ALL (ブロードキャスト)関数ごとに固定の接続文字列
一般的なユースケース大規模なデータセットを複数の RDS インスタンスに分散クロスインスタンスクエリまたはアドホックフェデレーション

次のステップ