Replication sets#
レプリケーションセットは、PGDノードがサブスクライブできるテーブルのグループです。レプリケーションセットを使用して、各ノードが他のノードの正確なコピーである通常の対称マルチマスタートポロジよりも複雑なレプリケーショントポロジを作成できます。
すべてのPGDグループは、グループと同じ名前のレプリケーションセットを作成します。このレプリケーションセットは、すべてのユーザーテーブルとDDLレプリケーションに使用されるデフォルトのレプリケーションセットです。すべてのノードがそれにサブスクライブされます。つまり、デフォルトでは、すべてのユーザーテーブルがすべてのノード間でレプリケートされます。
レプリケーションセットを使用する#
bdr.create_replication_set を使用して、挿入、更新、削除、または切り捨てアクションを含めるかどうかを指定して、レプリケーションセットを作成できます。 1つのオプションでは既存のテーブルをセットに追加でき、2番目のオプションでは作成時にテーブルを追加するかどうかを定義します。
テーブルを手動で定義して、レプリケーションセットに追加または削除することもできます。
レプリケーションセットに含まれるテーブルは、ノードがクラスターに参加したときおよびその後に維持されます。
ノードが参加したら、レプリケーションセットからテーブルを削除できますが、再同期操作を使用して新しいテーブルを追加する必要があります。
デフォルトでは、新しく定義されたレプリケーションセットはDDLまたはPGD管理ファンクション呼び出しをレプリケートしません。 bdr.replication_set_add_ddl_filter を使用する
複製するコマンドを定義します。
PGDは、すべてのノードでレプリケーションセット定義を作成します。次に、 bdr.alter_node_replication_sets を使用して各レプリケーションセットをパブリッシュまたはサブスクライブするように各ノードを定義できます。
ファンクションを使用して、これらの定義を後で変更したり、レプリケーションセットを削除したりできます。
注釈
選択的レプリケーションにデフォルトのレプリケーションセットを使用しないでください。クラスター内のPGDノードにあるデフォルトのレプリケーションセットは、 DDLレプリケーションおよび管理ファンクション呼び出しにもデフォルトで使用されるため、ドロップまたは変更しないでください。
パーティション分割テーブルの動作#
PGDは、パーティション化テーブルを透過的にサポートします。つまり、パーティション化されたテーブルをレプリケーションセットに追加できます。
パーティションに関係する変更は、ダウンストリームにレプリケートされます。
注釈
パーティションがパーティションテーブルを介してレプリケートされる場合、パーティションで直接実行されるステートメントは、親テーブルで実行されたときと同じようにレプリケートされます。例外は`TRUNCATE` コマンドであり、これは常に影響を受けるテーブルまたはパーティションのリストを使用して複製します。
個々のパーティションをレプリケーションセットに追加できます。この場合、それらは通常のテーブルと同様に、つまり、ダウンストリームのパーティションと同じ名前のテーブルにレプリケートされます。パーティショニング定義がプロバイダーとサブスクライバーの両方で同じである場合、パーティショニングロジックを実行する必要がないため、この動作にはいくつかのパフォーマンスの利点があります。
注釈
ルートパーティションテーブルがレプリケーションセットの一部である場合、個々のパーティションのメンバーシップは無視されます。そのルートテーブルのメンバーシップのみが考慮されます。
外部キーを使用した動作#
外部キー制約は、参照テーブルの各行が参照先テーブルの行と一致することを保証します。したがって、参照テーブルがレプリケーションセットのメンバーである場合、参照されるテーブルも同じレプリケーションセットのメンバーである必要があります。
PGDの現在のバージョンは、この条件をチェックまたは適用しません。レプリケーションセットにテーブルを追加するとき、データベース管理者は、外部キーによって参照されるすべてのテーブルも追加されていることを確認する必要があります。
次のクエリを使用して、この要件を満たさないすべての外部キーとレプリケーションセットをリストできます。参照テーブルはレプリケーションセットのメンバーですが、参照されるテーブルはレプリケーションセットのメンバーではありません。
SELECT t1.relname,
t1.nspname,
fk.conname,
t1.set_name
FROM bdr.tables AS t1
JOIN pg_catalog.pg_constraint AS fk
ON fk.conrelid = t1.relid
AND fk.contype = f
WHERE NOT EXISTS (
SELECT *
FROM bdr.tables AS t2
WHERE t2.relid = fk.confrelid
AND t2.set_name = t1.set_name
);
このクエリの出力は次のようになります。
relname | nspname | conname | set_name
- --------+---------+-----------+----------
t2 | public | t2_x_fkey | s2
(1 row)
この出力は、テーブルt2 がレプリケーションセットs2
のメンバーであるが、外部キーt2_x_fkey
によって参照されるテーブルがそうでないことを意味します。
TRUNCATE CASCADE
コマンドは、コマンドをレプリケートする前にレプリケーションセットのメンバーシップを考慮します。例
TRUNCATE table1 CASCADE;
これは、レプリケーションセットのみの一部であるすべてのテーブルでカスケードなしのTRUNCATE
になります。
TRUNCATE table1, referencing_table1, referencing_table2 ...
レプリケーションセットのメンバーシップ#
1つ以上のレプリケーションセットにテーブルを追加または削除できます。そうすると、これらのテーブルの変更DMLのレプリケーションにのみ影響します。スキーマ変更DDLは、 DDLレプリケーションセットフィルターによって処理されます DDLレプリケーションフィルタリング を参照してください。
レプリケーションは、ノードレプリケーションセット構成を使用してレプリケーションセットのテーブルメンバーシップを使用して、レプリケートするアクションとそれらのレプリケート先のノードを決定します。決定は、すべてのメンバーシップとレプリケーションセットオプションの和集合を使用して行われます。テーブルが、 INSERTアクションのみをレプリケートするレプリケーションセットAと、 UPDATEアクションのみをレプリケートするレプリケーションセットBのメンバーであるとします。ターゲットノードがレプリケーションセットAおよびBの両方にサブスクライブされている場合、 INSERTおよびUPDATEアクションは両方ともレプリケートされます。
bdr.replication_set_add_table および bdr.replication_set_remove_table を使用してメンバーシップを制御できます。
レプリケーションセットのリスト#
次のクエリーを使用して、既存のレプリケーションセットをリストできます。
SELECT set_name
FROM bdr.replication_sets;
このクエリを使用して、特定のレプリケーションセット内のすべてのテーブルをリストできます。
SELECT nspname, relname
FROM bdr.tables
WHERE set_name = myrepset;
外部キーを使用した動作 は、参照されるテーブルが参照テーブルと同じレプリケーションセットに含まれていないすべての外部キーをリストするクエリーを示しています。
次のSQLを使用して、現在のノードが発行およびサブスクライブするレプリケーションセットを表示します。
SELECT node_id,
node_name,
pub_repsets,
sub_repsets
FROM bdr.local_node_summary;
このコードは、次のような出力を生成します。
node_id | node_name | pub_repsets | sub_repsets
- -----------+-----------+----------------------------------------
1834550102 | s01db01 | {bdrglobal,bdrs01} | {bdrglobal,bdrs01}
(1 row)
クラスター内のすべてのノードに対して同じクエリーを実行するには、次のクエリーを使用できます。このアプローチでは、すべてのノードに関連付けられたレプリケーションセットを同時に取得します。
WITH node_repsets AS (
SELECT jsonb_array_elements(
bdr.run_on_all_nodes($$
SELECT
node_id,
node_name,
pub_repsets,
sub_repsets
FROM bdr.local_node_summary;
$$)::jsonb
) AS j
)
SELECT j->response->command_tuples->0->>node_id AS node_id,
j->response->command_tuples->0->>node_name AS node_name,
j->response->command_tuples->0->>pub_repsets AS pub_repsets,
j->response->command_tuples->0->>sub_repsets AS sub_repsets
FROM node_repsets;
これは、例を示します。
node_id | node_name | pub_repsets | sub_repsets
- -----------+-----------+----------------------------------------
933864801 | s02db01 | {bdrglobal,bdrs02} | {bdrglobal,bdrs02}
1834550102 | s01db01 | {bdrglobal,bdrs01} | {bdrglobal,bdrs01}
3898940082 | s01db02 | {bdrglobal,bdrs01} | {bdrglobal,bdrs01}
1102086297 | s02db02 | {bdrglobal,bdrs02} | {bdrglobal,bdrs02}
(4 rows)
DDLレプリケーションフィルタリング#
デフォルトでは、サポートされているすべてのDDLのレプリケーションは、デフォルトのPGDグループレプリケーションセットを介して発生します。このレプリケーションは、PGDグループと同じ名前のDDLフィルターを使用して実現されます。このフィルタは、 PGDグループの作成時に、デフォルトのPGDグループレプリケーションセットに追加されます。
既存のすべてのレプリケーションセットのDDLレプリケーションフィルターを変更することにより、この動作を調整できます。これらのフィルターは、レプリケーションセットのテーブルメンバーシップとは独立しています。データ変更と同様に、各DDLステートメントは、複数のレプリケーションセットの複数のフィルターと一致する場合でも、1回だけレプリケートされます。
次のクエリーを使用して既存のDDLフィルターをリストできます。これは、フィルターごとに、コマンドタグとロール名に適用された正規表現を示します。
SELECT * FROM bdr.ddl_replication;
bdr.replication_set_add_ddl_filter および bdr.replication_set_remove_ddl_filter を使用して、
DDLフィルターを操作できます。これらはDDL であると考えられるため、
DDLレプリケーションとグローバルロックの対象になります。
選択的レプリケーションの例#
この例では、テーブルを特定のノードのグループに選択的にレプリケートするようにEDB Postgres分散を構成します。
クラスター構成#
この例では、6つのデータノード、data-a1 〜data-a3
およびdata-b1 〜data-b3
のクラスターが2つの場所にあることを前提としています。これらがメンバーである2つのロケーションは、region_a
およびregion_b グループとして表されます。
また、お勧めのように、この例では記載されていませんが、 region-c
にwitness
という名前の監視ノードがあります。クラスターの名前はsere です。
応募要項#
この例は、音楽作品の公演に出席した人々の意見を記録するアプリケーションで動作します。出席者用のテーブル、作品用のテーブル、そしてオピニオンテーブルがあります。オピニオンテーブルには、各出席者が見た各作品、どこで、いつ見たか、および作品をどのように採点したかが記録されます。データ規制のため、この例では、意見データは、意見が記録されたリージョンにのみ存在する必要があることを前提としています。
テーブルの作成#
最初のステップは、適切なテーブルを作成することです。
CREATE TABLE attendee (
id bigserial PRIMARY KEY,
email text NOT NULL
);
CREATE TABLE work (
id int PRIMARY KEY,
title text NOT NULL,
author text NOT NULL
);
CREATE TABLE opinion (
id bigserial PRIMARY KEY,
work_id int NOT NULL REFERENCES work(id),
attendee_id bigint NOT NULL REFERENCES attendee(id),
country text NOT NULL,
day date NOT NULL,
score int NOT NULL
);
グループとレプリケーションセットの表示#
デフォルトでは、 EDB Postgres分散は、各テーブル全体を各すべてのノードにレプリケートするように構成されます。これは、レプリケーションセットを介して管理されます。
初期構成のデフォルトレプリケーションセットを表示するには、次のコマンドを実行します。
SELECT node_group_name, default_repset, parent_group_name
FROM bdr.node_group_summary;
node_group_name | default_repset | parent_group_name
- ----------------+----------------+-------------------
sere | sere |
region_a | region_a | sere
region_b | region_b | sere
region_c | region_c | sere
出力には、トップレベルのグループsere があり、 sere
という名前のデフォルトのレプリケーションセットがあることがわかります。
3つのサブグループには、それぞれ、サブグループと同じ名前のレプリケーションセットがあります。
region_a グループには、region_a
デフォルトレプリケーションセットがあります。
デフォルトでは、既存のすべてのテーブルと新しいテーブルは、トップレベルグループのレプリケーションセットのメンバーになります。
レプリケーションセットへのテーブルの追加#
次の手順は、リージョンを表すグループに属するレプリケーションセットにテーブルを追加することです。前述のように、新しいテーブルはすべてsere
レプリケーションセットに自動的に追加されます。次を実行して、それを確認できます。
SELECT relname, set_name FROM bdr.tables ORDER BY relname, set_name;
relname | set_name
- ---------+----------
attendee | sere
opinion | sere
work | sere
(3 rows)
opinion テーブルは、region_a でのみ、別にregion_b
でのみレプリケートする必要があります。これを行うには、各リージョンのレプリカセットにテーブルを追加します。
SELECT bdr.replication_set_add_table(opinion, region_a);
SELECT bdr.replication_set_add_table(opinion, region_b);
しかし、opinion はまだsere
レプリケーションセットのメンバーであるため、これで完了ではありません。テーブルが複数のレプリケーションセットのメンバーである場合、各テーブルでレプリケートされます。ただし、各行は各ターゲットノードで1回のみレプリケートされるため、これはパフォーマンスに影響しません。
opinion
をすべてのノードでレプリケートしたくないため、トップレベルグループのレプリケーションセットから削除する必要があります。
SELECT bdr.replication_set_remove_table(opinion, sere);
これらの変更を確認できるようになりました。
SELECT relname, set_name FROM bdr.tables ORDER BY relname, set_name;
relname | set_name
- ---------+-------------------
attendee | sere
opinion | region_a
opinion | region_b
work | sere
(4 rows)
このプロセスにより、目的の選択的レプリケーションが提供されます。行われたかどうかを確認するには、次の手順を使用してテストします。
選択的レプリケーションのテスト#
最初にいくつかのテストデータ2つの作品と出席者を作成します。 data-a1
に直接接続して、次のコードを実行します。
INSERT INTO work VALUES (1, Aida, Verdi);
INSERT INTO work VALUES (2, Lohengrin, Wagner);
INSERT INTO attendee (email) VALUES (gv@example.com);
これらのテーブルにデータが追加されたため、外部キー制約に違反せずにopinion
テーブルに挿入できます。
INSERT INTO opinion (work_id, attendee_id, country, day, score)
SELECT work.id, attendee.id, Italy, 1871-11-19, 3
FROM work, attendee
WHERE work.title = Lohengrin
AND attendee.email = gv@example.com;
挿入が完了したら、同じノードでデータベースの内容を検証できます。
SELECT a.email
, o.country
, o.day
, w.title
, w.author
, o.score
FROM opinion o
JOIN work w ON w.id = o.work_id
JOIN attendee a ON a.id = o.attendee_id;
email | country | day | title | author | score
- ---------------+---------+------------+-----------+--------+-------
gv@example.com | Italy | 1871-11-19 | Lohengrin | Wagner | 3
(1 row)
ここで、ノードdata-a2 およびdata-a3
に接続し、同じクエリーを実行すると、同じ結果が得られます。データはregion_a
で複製されています。 data-b1 、data-b2 、またはdata-b3
に接続する場合、クエリーは行を返しません。これは、 attendee
およびwork
テーブルにデータが入力されていますが、選択するopinion
行がないためです。これは、 region_a でのopinion
のレプリケーションがそのリージョンでのみ発生するためです。
次に、 data-b1 に接続し、そこに意見を挿入します。
INSERT INTO attendee (email) VALUES (fb@example.com);
INSERT INTO opinion (work_id, attendee_id, country, day, score)
SELECT work.id, attendee.id, Germany, 1850-08-27, 9
FROM work, attendee
WHERE work.title = Lohengrin
AND attendee.email = fb@example.com;
この意見はregion_b でのみ複製されます。 data-b1
、data-b2 、およびdata-b3 では、次を実行できます。
SELECT a.email
, o.country
, o.day
, w.title
, w.author
, o.score
FROM opinion o
JOIN work w ON w.id = o.work_id
JOIN attendee a ON a.id = o.attendee_id;
email | country | day | title | author | score
- ---------------+---------+------------+-----------+--------+-------
fb@example.com | Germany | 1850-08-27 | Lohengrin | Wagner | 9
(1 row)
各region_b データノードで同じ結果が表示されます。 region_a
ノードでクエリーを実行すると、この特定のエントリが表示されません。
最後に、 attendee
テーブルがすべてのノードで同様に共有されていることに注意してください。任意のノードで、クエリを実行します。
SELECT * FROM attendee;
id | email
- -------------------+----------------
904252679641903104 | gv@example.com
904261037006536704 | fb@example.com
(2 rows)