PL/Proxy は、プロキシノードからリモートデータベースへの SQL 呼び出しをルーティングする PostgreSQL 拡張機能です。ApsaraDB RDS for PostgreSQL では、クラスターモードで使用してシャード間で書き込みを分散したり、ノード間でデータをレプリケーションしたり、コネクトモードで使用して特定のデータベースにクエリをルーティングしたりできます。
前提条件
開始する前に、以下を確認してください:
PL/Proxy をサポートするメジャーエンジンバージョン — 「ApsaraDB RDS for PostgreSQL でサポートされる拡張機能」をご参照ください
メジャーバージョンがサポートされているにもかかわらず PL/Proxy が利用できない場合は、最新のマイナーエンジンバージョン — 「マイナーエンジンバージョンの更新」をご参照ください
仕組み
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 で定義されます。各データノードはオプション (p0、p1 など) として登録されます。オプションの数は 2 のべき乗である必要があります。
クラスターサーバーを作成し、データノードを登録します:
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' );クラスターへのアクセス権を付与します:
GRANT USAGE ON FOREIGN SERVER cluster_srv1 TO postgres;PL/Proxy がデータノードに認証できるように、ユーザーマッピングを作成します:
CREATE USER MAPPING FOR postgres SERVER cluster_srv1 OPTIONS (user 'postgres');
テスト設定
以下のセクションでは、3 つの RDS インスタンスを使用して両方のモードをデモンストレーションします。
| IP | ロール | データベース | ユーザー名 |
|---|---|---|---|
| 100.xx.xx.136 | プロキシノード | postgres | postgres |
| 100.xx.xx.72 | データノード | pl_db0 | postgres |
| 11.xx.xx.9 | データノード | pl_db1 | postgres |
各データノードに users テーブルを作成します:
CREATE TABLE users (userid int, name text);クラスターモードのテスト
水平シャーディング
RUN ON ANY は、各 INSERT をデータノードの 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;プロキシノードにプロキシ関数を作成します。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;プロキシノードに読み取り関数を作成します。
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;プロキシノードから 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');各データノードにクエリを実行して、データがどのように分散されたかを確認します:
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)プロキシノードを介してすべての行を読み取ります:
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 は各書き込みをすべてのデータノードにブロードキャストし、すべてのノードを同期させます。
各データノードとプロキシノードに
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;すべてのノードでテーブルを切り詰めます:
SELECT trunc_user(); trunc_user ------------ 1 1 (2 rows)プロキシノードにレプリケーション用の挿入関数を作成します。
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 件のレコードを挿入します:
SELECT insert_user_2(1004, 'lottu'); SELECT insert_user_2(1005, 'rax'); SELECT insert_user_2(1006, 'ak'); SELECT insert_user_2(1007, 'jack');両方のデータノードに同一のデータが含まれていることを確認します:
-- 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)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 インスタンスに分散 | クロスインスタンスクエリまたはアドホックフェデレーション |
次のステップ
PL/Proxy の完全な言語リファレンスについては、「PL/Proxy チュートリアル」をご参照ください。
詳細については、「ApsaraDB RDS for PostgreSQL でサポートされる拡張」をご参照ください。