BDR Support

LiveCompareは、 BDRBDRに対しても使用できます。

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

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

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

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

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

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

[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

BDRクラスター内のすべてのアクティブノードを比較するように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 を使用してすべてのBDRノードのリストを取得します。追加のデータ接続は必要ありません。設定されている場合、データ接続のリストに追加されます。たとえば、移行プロジェクトで役立つ、 BDRクラスター全体を単一の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 は、次のテクノロジでサポートされています。

  • BDR 1、2、3および4;

  • pglogical 2および3。

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

BDR Witnessノード

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

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

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

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

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

Table public.tbl does not exist on connection node1

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

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

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

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

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

Table public.tbl is not subscribed on connection node1

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

BDRクラスターの違い

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

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

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

LiveCompareは、次のことを考慮して適用スクリプトを生成します。

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

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

LiveCompare修正スクリプトをBDRノードに適用した後、次のクエリを使用して、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によって修正されたすべての行をリストする上記のクエリは使用できません。

BDR 3.6.18とBDR 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 が必要です。 BDR 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;

BDRの競合

LiveCompareにはconflicts という実行モードがあります。この実行モードは、 BDRクラスターに固有です。 BDR 3.6、 BDR 3.7、またはBDR 4クラスターでのみ機能します。

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

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

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

一般的なユースケースでは、自動競合解決によってクラスターの一貫性が保証されますが、自動競合解決によりノード間でタプルが分散することが知られているケースがいくつかあります。したがって、 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)

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

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

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

そこで、 check.ini ファイルを作成してall_bdr_nodes = on を設定します、つまり、クラスター内のすべてのノードを比較するように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;

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

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

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

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

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

BDR 3.7のbdr.conflict_history またはBDR 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および/またはBDR対応データベースである必要があります。

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

例:

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

  • BDR 4ノードとバニラのPostgresインスタンス;

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