EDB Postgres Distributed support
================================

LiveCompareは、 EDB Postgres
DistributedPGD、以前はBDRノードと同様に非PGDノードに対して使用できます。

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

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

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

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

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

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

.. code:: ini

   [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に指示することもできます。そのためには

1. ``General Settings`` の下で、\ ``all_bdr_nodes = on``
   を有効にします。

2. ``Initial Connection`` の下で、初期接続を指定します。

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

例

.. code:: ini

   [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接続と比較できます。これは、移行プロジェクトに役立ちます。

.. code:: ini

   [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

- pglogical 2および3

PGDの代わりにpgロジカルメタデータの取得を有効にするには、
``logical_replication_mode = bdr``
の代わりに\ ``logical_replication_mode = pglogical`` を設定します。

PGD監視ノード
-------------

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

PGD監視は、他のノードからDMLをレプリケートしない通常のPGDノードです。
Witnessの目的は、Raftコンセンサス投票でクォーラムを提供することです。レプリケーションセットの構成は、監視がDDLをレプリケートするかどうかを決定します。これは、2種類のPGD証人が存在することを意味します。

- データもテーブルも含まない完全に空のノード

- 他のノードからDDLを複製するノードのため、空のテーブルがあります

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

::

   Table public.tbl does not exist on connection node1

2番目のケースでは、テーブルはPGD監視に存在します。ただし、証人で不足しているデータを発散として報告するのは正しくありません。したがって、LiveCompareは、テーブルごとに、比較に含まれる各ノードに関する次の情報をチェックします。

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

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

- ``Table Filter`` の下のフィルタ\ ``replication_sets``
  で定義したレプリケーションセットがある場合

レプリケーションセットの3つのリストすべての交差が空の場合、PGD監視の場合、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``
設定を調整することにより、レプリケーションオリジンの名前を構成できます。

..  Important::
   PGD 3.6.18では、ローカル専用トランザクションを適用するために使用する新しい既存の`bdr_local_only_origin` レプリケーションオリジンを導入しました。 LiveCompareがPGD 3.6.18に接続されている場合、このレプリケーションオリジンは作成されません。

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

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

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

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

.. code:: postgresql

   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はレプリケーションオリジンを関連付けずに修正を生成します。ただし、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以降、これらの機能は非推奨です。その場合、PostgreSQLスーパーユーザーとして実行している場合、LiveCompareは次の機能を使用して同じアクションを実行します。

- ``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、PGD 3.7、PGD 4、およびPGD 5クラスターでのみ動作します。

``compare``
モードは、テーブルのすべてのコンテンツを全体的に比較するために使用されますが、
``conflicts`` モードは、PGD 3.6の場合は\ ``bdr.apply_log`` 、またはPGD
3.7の場合は\ ``bdr.conflict_history``
に登録されている既存の競合に関連するタプル/テーブルにのみ焦点を当てます。
、PGD 4、およびPGD 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クラスターは発散しています。

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

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

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

::

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

   [Initial Connection]
   dsn = dbname=bdrdb

   [Output Connection]
   dsn = dbname=liveoutput

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

::

   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を提案します。

``node3``
に対してこのDMLスクリプトを実行すると、PGDクラスターの一貫性が再び高まります。

::

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

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

..  Note::
   PGD 3.7の`bdr.conflict_history` またはPGD 3.6の`bdr.apply_log` のデータを表示するには、 bdr_superuserまたはPostgreSQLスーパーユーザーであるユーザーでLiveCompareを実行します。

PGD 3.7+の\ ``bdr.conflict_history`` またはPGD 3.6の\ ``bdr.apply_log``
のデータを表示できるようにするには、
bdr_superuserまたはPostgreSQLスーパーユーザーであるユーザーでLiveCompareを実行します。

競合フィルター
^^^^^^^^^^^^^^

``bdr.conflicts_history`` または\ ``bdr.apply_log``
の列で競合をフィルターするようにLiveCompareに指示することもできます。例

.. code:: ini

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

ミキシングテクノロジー
----------------------

``node_name`` および\ ``replication_sets``
のメタデータは、初期接続で取得されます。したがって、pglogicalおよび/またはPGD対応データベースである必要があります。

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

混合テクノロジーの比較を実行できます。例

- PGD 1ノードとPGD 3ノード

- PGD 4ノードとバニラのPostgresインスタンス

- Vanilla Postgresインスタンスとpg論理ノード
