EDB Postgres Distributed Support

LiveCompareは、 EDB Postgres Distributed(PGD、旧称BDR)ノード、および非PGDノードに対して使用できます。

logical_replication_mode = bdr を設定すると、ツールは、比較されるすべてのデータベースが同じPGDクラスターに属すると想定します。次に、ノード名を接続として指定し、レプリケーションセットを指定してテーブルをフィルタリングできます。

たとえば、PGDクラスター内の任意のノードに接続できるとします。これをInitial Connection としましょう。このノードに最初に接続することにより、LiveCompareはPGDメタデータを確認し、他のすべてのノードから接続情報を取得できます。

次に、3つのPGDノードを比較したいとします。 LiveCompareはInitial Connection から始まる任意のノードに接続できるため、 dsn またはデータ接続の接続情報を定義する必要はありません。 node_name を定義するだけです。 LiveCompareは、そのノードの接続情報に関するPGDメタデータを検索し、ノードに接続します。

LiveCompareがPGDメタデータを取得して他のすべてのノードに接続できるようにするには、LiveCompareがPGDビューbdr.node_summary 、フィールドinterface_connstr から同じDSNを使用してノードに接続できる必要があることに注意してください。この場合、Initial Connection と同じマシンでpostgres ユーザーとしてLiveCompareを実行することをお勧めします。それが不可能な場合は、すべてのデータ接続でdsn 属性を定義してください。

レプリケーションセットをテーブルフィルターとして指定することもできます。 LiveCompareはPGDメタデータを使用して、 replication_sets 設定で定義したレプリケーションセットに属するテーブルのみを考慮して、テーブルリストを作成します。

たとえば、 .ini ファイルを作成して3つのPGDノードを比較できます。

[General Settings]
logical_replication_mode = bdr
max_parallel_workers = 4

[Initial Connection]
dsn = port=5432 dbname=live user=postgres

[Node1 Connection]
node_name = node1

[Node2 Connection]
node_name = node2

[Node3 Connection]
node_name = node3

[Output Connection]
dsn = port=5432 dbname=liveoutput user=postgres

[Table Filter]
replication_sets = set_name = bdrgroup

PGDクラスター内のすべてのアクティブノードを比較するようにLiveCompareに指示することもできます。その目的のためには、次のことを実行してください。

  • General Settings で、all_bdr_nodes = on を有効にします。

  • Initial Connection を指定します。

  • 追加のデータ接続は必要ありません。

例:

[General Settings]
logical_replication_mode = bdr
max_parallel_workers = 4
all_bdr_nodes = on

[Initial Connection]
dsn = port=5432 dbname=live user=postgres

[Output Connection]
dsn = port=5432 dbname=liveoutput user=postgres

[Table Filter]
replication_sets = set_name = bdrgroup

all_bdr_nodes = on の場合、LiveCompareはInitial Connection を使用して、すべてのPGDノードのリストを取得します。追加のデータ接続は必要ありません。ただし、設定されている場合、データ接続のリストに追加されます。たとえば、移行プロジェクトで役立つ、PGDクラスター全体を単一のPostgres接続と比較できます。

[General Settings]
logical_replication_mode = bdr
max_parallel_workers = 4
all_bdr_nodes = on

[Initial Connection]
dsn = port=5432 dbname=live user=postgres

[Old Connection]
dsn = host=oldpg port=5432 dbname=live user=postgres

[Output Connection]
dsn = port=5432 dbname=liveoutput user=postgres

[Table Filter]
replication_sets = set_name = bdrgroup

設定node_name およびreplication_sets は、次のテクノロジでサポートされています。

  • PGD 1、2、3、4および5;

  • pglogical 2および3。

PGDの代わりにpglogicalメタデータフェッチを有効にするには、 logical_replication_mode = bdr の代わりにlogical_replication_mode = pglogical を設定するだけであることに注意してください。

PGD Witnessノード

PGDのレプリケーションセットを使用すると、特定のテーブルをPGDレプリケーションに含めるように構成し、テーブルが属するレプリケーションセットをサブスクライブするようにノードを構成することにより、そのようなテーブルからデータを受信するノードを指定できます。これにより、PGDシャーディングやPGD Witnessノードの使用など、さまざまなアーキテクチャが可能になります。

PGD Witnessは、他のノードからDMLを複製しない通常のPGDノードです。 Witnessの目的は、Raftコンセンサス投票でクォーラムを提供することです(PGD Witnessノードの詳細については、PGDドキュメントを確認してください)。レプリケーションセットの構成に応じて、 WitnessはDDLをレプリケートする場合とレプリケートしない場合があります。つまり、PGD Witnessesには2種類あります。

  • データもテーブルもない完全に空のノード。または

  • 他のノードからDDLをレプリケートするため、空のテーブルを持つノード。

最初のケースでは、PGD Witnessが比較に含まれていても([Connections] で手動で、またはall_bdr_nodes = on を使用して)、Witnessにはテーブルがないため、次のメッセージがログに記録されます。

Table public.tbl does not exist on connection node1

一方、2番目のケースでは、テーブルはPGD Witnessに存在します。ただし、Witnessで欠落しているデータを相違として報告するのは正しくありません。そのため、各テーブルについて、 LiveCompareは比較に含まれる各ノードに関する次の情報をチェックします。

  • ノードがサブスクライブするレプリケーションセット。

  • テーブルが関連付けられているレプリケーションセット。

  • レプリケーションは、Table Filter の下のフィルターreplication_sets で定義されたユーザーを設定します。

PGD Witnessの場合、レプリケーションセットの3つすべてのリストの共通部分が空の場合、 LiveCompareはこれをログに記録します。

Table public.tbl is not subscribed on connection node1

どちらの場合も、その特定のテーブルの比較はテーブルが存在するノードで続行され、テーブルはレプリケーションセット構成に従って複製されます。

PGDクラスターの違い

LiveCompareはローカルノードのみに変更を加えます。修正変更が他のノードにレプリケートされないことが重要です。

logical_replication_mode = bdr の場合、LiveCompareは最初にbdr_local_only_origin という複製起点が既に存在するかどうかを確認します(複製起点の名前は、設定difference_fix_replication_origin を調整することで構成できます)。 bdr_local_only_origin というレプリケーションオリジンがまだ存在しない場合、 LiveCompareはすべてのPGD接続でそれを作成します。

重要 :PGD 3.6.18では、ローカルのみのトランザクションを適用するために使用される、事前に作成された新しいbdr_local_only_origin レプリケーションオリジンが導入されたことに注意してください。したがって、LiveCompareがPGD 3.6.18に接続されている場合、このレプリケーションオリジンは作成されません。

LiveCompareは、以下を考慮して適用スクリプトを生成します。

  • レプリケーションオリジンbdr_local_only_origin を使用するように現在のトランザクションを設定します。したがって、実行されるDMLにはxmin がbdr_local_only_origin に関連付けられます。

  • 現在のトランザクションの日時をはるかに過去に設定します。そのため、データベースで実行されている実際のDMLとPGD競合がある場合、 LiveCompare DMLは常に競合を失います。

LiveCompare修正スクリプトをPGDノードに適用した後、次のクエリを使用して、LiveCompareによって挿入または更新された行を正確に取得できます( mytable をテーブルの名前に置き換えます)。

with lc_origin as (
    select roident
    from pg_replication_origin
    where roname = bdr_local_only_origin
)
select t.*
from mytable t
inner join lc_origin r
on r.roident = bdr.pg_xact_origin(t.xmin);

(削除された行はもう表示されないことに注意してください。)

LiveCompareでメタデータを適切にフェッチするには、少なくともbdr_superuser 権限を持つPostgreSQLユーザーが必要であることに注意してください。

PostgreSQLユーザーがbdr_superuser またはPostgreSQLスーパーユーザー特権を持っている場合、レプリケーション起点を含む上記のすべての手順は出力スクリプトにのみ適用されます。それ以外の場合、LiveCompareはレプリケーションオリジンを関連付けずに修正を生成します(トランザクションレプリケーションはSET LOCAL bdr.xact_replication = off を使用してまだ無効になっています)。ただし、DMLスクリプトを適用するときはレプリケーションオリジンを使用することをお勧めします。そうしないと、LiveCompareは競合解決に関して通常のユーザーアプリケーションと同じ優先順位を持つためです。また、修正に関連付けられた複製起点がないため、LiveCompareによって修正されたすべての行をリストする上記のクエリは使用できません。

PGD 3.6.18とPGD 3.7.0の間、次の機能が使用されます。

  • bdr.difference_fix_origin_create() :LiveCompareによって実行され、この複製起点が存在しない場合、difference_fix_replication_origin で指定された複製起点を作成します(デフォルトではbdr_local_only_origin に設定されます)。

  • bdr.difference_fix_session_setup() :生成されたDMLスクリプトに含まれるため、トランザクションはdifference_fix_replication_origin で指定された複製起点に関連付けられます。

  • bdr.difference_fix_xact_set_avoid_conflict() :生成されたDMLスクリプトに含まれ、トランザクションがはるかに過去に設定される(2010-01-01 )ため、 LiveCompareによって適用される修正トランザクションは、競合があれば常に失います。

上記の機能には、PostgreSQLスーパーユーザーではなくbdr_superuser が必要です。 PGD 3.7.0以降、これらの関数は非推奨です。 LiveCompareは、PostgreSQLスーパーユーザーとして実行している場合、代わりに次の関数を使用して、上記と同じアクションを実行します。

  • pg_replication_origin_create(origin_name) ;

  • pg_replication_origin_session_setup() ;

  • pg_replication_origin_xact_setup() 。

PostgreSQLスーパーユーザーが使用されていない場合、 LiveCompareは生成されたDMLトランザクションに次のみを含めます。

SET LOCAL bdr.xact_replication = off;

PGDの競合

LiveCompareにはconflicts という実行モードがあります。この実行モードは、PGDクラスターに固有です。 PGD 3.6、3.7、4、および5クラスターでのみ動作します。

compare モードはテーブル全体のすべての内容を比較するために使用されますが、 conflicts モードは、PGD 3.6の場合はbdr.apply_log 、PGDの場合はbdr.conflict_history に登録されている既存の競合に関連するタプル/テーブルにのみ焦点を合わせます3.7、4および5。

とはいえ、 conflicts 実行モードは、特定のテーブルの特定のタプルを検査するだけなので、 compare モードよりもはるかに高速に実行されることが期待されます。同時に、同じ理由により、 compare モードほど完全ではありません。

この実行モードの主な目的は、PGDによって行われている自動競合解決がノード間で一貫していることを確認することです。 つまり、PGDが競合を解決した後、クラスターは一貫した状態にあります。

一般的なユースケースでは、自動競合解決によりクラスターの一貫性が保証されますが、自動競合解決によりノード間でタプルが分岐することが知られているケースがいくつかあります。したがって、 LiveCompareのconflicts 実行モードは、時間と結果のバランスをとりながら、一貫性のチェックと保証に役立ちます。

競合の例

node3 で次のクエリを実行すると想像してみてください。

SELECT c.reloid::regclass,
       s.origin_name,
       c.local_time,
       c.key_tuple,
       c.local_tuple,
       c.remote_tuple,
       c.apply_tuple,
       c.conflict_type,
       c.conflict_resolution
FROM bdr.conflict_history c
INNER JOIN bdr.subscription_summary s
ON s.sub_id = c.sub_id;

bdr.conflict_history には、次の競合が見られます。

reloid              | tbl
origin_name         | node2
local_time          | 2021-05-13 19:17:43.239744+00
key_tuple           | {"a":null,"b":3,"c":null}
local_tuple         |
remote_tuple        |
apply_tuple         |
conflict_type       | delete_missing
conflict_resolution | skip

つまり、 DELETE がnode2 からnode3 に到着したとき、テーブルtbl にb = 3 の行はありませんでした。ただし、 INSERT はnode1 からnode3 に後で到着した可能性があり、次にb = 3 を含む行をnode3 に追加しました。だからこれはnode3 の現在の状況です:

bdrdb=# SELECT * FROM tbl WHERE b = 3;
 a | b |  c
- --+---+-----
 x | 3 | foo
(1 row)

ノードnode1 およびnode2 で、これが私たちが見るものです:

bdrdb=# SELECT * FROM tbl WHERE b = 3;
 a | b | c
- --+---+---
(0 rows)

PGDクラスターは発散しています。

このような相違を検出して修正するために、 LiveCompareをcompare モードで実行できますが、比較セットのサイズによっては(テーブルtbl が非常に大きいと想像してください)、長い時間、場合によっては数時間かかる場合があります。

これは、まさに conflicts モードが役立つ状況です。この場合、delete_missing の競合はnode3 からのみ可視ですが、LiveCompareは競合がログに記録された行(key_tuple 、local_tuple 、remote_tuple およびapply_tuple )からPK値を抽出し、影響を受けたテーブルでのみクラスター全体の自動比較を実行できます。すでにPK値でフィルタリングしています。次に、比較により、クラスター内のすべてのノードの現在の行バージョンがチェックされます。

したがって、 all_bdr_nodes = on を設定するcheck.ini ファイルを作成します、つまり、クラスター内のすべてのノードを比較するようにLiveCompareに指示します。

[General Settings]
logical_replication_mode = bdr
max_parallel_workers = 2
all_bdr_nodes = on

[Initial Connection]
dsn = dbname=bdrdb

[Output Connection]
dsn = dbname=liveoutput

LiveCompareをconflicts モードで実行するには:

livecompare check.ini --conflicts

実行後、コンソール出力に次のように表示されます。

Elapsed time: 0:00:02.443557
Processed 1 conflicts about 1 tables from 3 connections using 2 workers.
Found 1 divergent conflicts in 1 tables.
Processed 1 rows in 1 tables from 3 connections using 2 workers.
Found 1 inconsistent rows in 1 tables.

フォルダー./lc_session_X/ (X は現在の比較セッションの番号です)内に、LiveCompareはファイルconflicts_DAY.out (ファイル名のDAY を現在の日に置き換えます)を書き込み、すべての発散する競合に関する主な情報を表示します。

データベースliveoutput に接続すると、たとえば次のクエリを使用して、競合に関する詳細を表示できます。

SELECT *
FROM livecompare.vw_conflicts
WHERE session_id = 1
  AND conflict_id = 1
ORDER BY table_name,
         local_time,
         target_node;

次のようなものが表示されます。

session_id             | 1
table_name             | public.tbl
conflict_id            | 1
connection_id          | node3
origin_node            | node2
target_node            | node3
local_time             | 2021-05-13 19:17:43.239744+00
key_tuple              | {"a": null, "b": 3, "c": null}
local_tuple            |
remote_tuple           |
apply_tuple            |
conflict_type          | delete_missing
conflict_resolution    | skip
conflict_pk_value_list | {(3)}
difference_log_id_list | {1}
is_conflict_divergent  | t

is_conflict_divergent = true は、 LiveCompareが競合を比較し、競合によって報告されたテーブルと行でノードが現在発散していることがわかったことを意味します。ビュー livecompare.vw_conflicts は、非発散のものを含むすべての競合に関する情報を表示します。

LiveCompareは、DMLスクリプト./lc_session_X/apply_on_the_node3_DAY.sql も自動的に生成します(ファイル名のDAY を現在の日に置き換えます)。

BEGIN;

SET LOCAL bdr.xact_replication = off;
SELECT pg_replication_origin_session_setup(bdr_local_only_origin);
SELECT pg_replication_origin_xact_setup(0/0, 2010-01-01::timestamptz);;

SET LOCAL ROLE postgres;
DELETE FROM public.tbl WHERE (b) = (3);

COMMIT;

LiveCompareは、他の2つのノードに行が存在しないため、node3 からb = 3 がいる行をDELETE に提案しています。デフォルトでは、 LiveCompareは、ノードの大部分に基づいて修正するDMLを提案します。

このDMLスクリプトをnode3 に対して実行する場合:

psql -h node3 -f ./lc_session_X/apply_on_the_node3_DAY.sql

PGDクラスターの一貫性が再び得られます。

--conflicts モードの比較は完全な--compare よりもはるかに高速であるため、 --conflicts 比較セッションをより頻繁にスケジュールして、競合解決によってクラスター全体の一貫性が提供されるようにすることを強くお勧めします。

PGD 3.7+のbdr.conflict_history またはPGD 3.6のbdr.apply_log のデータを表示できるようにするには、 bdr_superuser またはPostgreSQLスーパーユーザーであるユーザーでLiveCompareを実行する必要があることに注意してください。

競合フィルター

bdr.conflicts_history またはbdr.apply_log のいずれかの列で競合をフィルタリングするようにLiveCompareに指示することもできます。例:

[Conflicts Filter]
conflicts = table_name = public.tbl and conflict_type = delete_missing

混合技術

node_name およびreplication_sets のメタデータはInitial Connection でフェッチされることに注意してください。したがって、それはpglogicalおよび/またはPGD対応データベースである必要があります。

テーブルのリストは、最初のデータ接続で構築されます。したがって、 replication_sets 条件は最初の接続で有効である必要があります。

たとえば、次のような混合テクノロジの比較を実行できます。

  • PGD 1ノード対PGD 3ノード。

  • PGD 4ノードとバニラPostgresインスタンス。

  • Vanilla Postgresインスタンスとpglogicalノード。