CDC Failover support
====================

背景
----

PGDの以前のバージョンでは、データベース内のデータに発生した論理変更のフィードを提供できるノードに論理レプリケーションスロットを作成できました。これらの論理レプリケーションスロットはノードに対してローカルであり、レプリケートされていません。特定のノードで変更をレプリケートするだけでなく、この動作は、クラスター内のノードフェールオーバーが発生した場合に課題を提示しました。そのシナリオでは、障害が発生したノードの論理レプリケーションのコンシューマには、別のノードに消費を継続するスロットのレプリカがありません。

この問題へのソリューションは、サブスクライバ専用ノードを中間として使用して設計できますが、論理レプリケーションのコストが大幅に増加します。

CDCフェイルオーバーのサポート
-----------------------------

このニーズに対応するために、PGDはCDCフェールオーバーサポートを導入しました。これは、クラスター全体で自動論理スロットレプリケーションをアクティブにするオプションで有効な機能です。これにより、論理スロットのレプリケーションのコンシューマは、障害が発生したときに任意のノードから変更データを受信できます。

CDCフェールオーバーの仕組み
^^^^^^^^^^^^^^^^^^^^^^^^^^^

CDCフェールオーバーサポートが有効になっているノードで論理スロットが作成されると、スロットはクラスター全体でレプリケートされます。これは、クラスター内の任意のノードでスロットを使用できることを意味します。ノードに障害が発生すると、クラスター内の別のノードからスロットが消費される可能性があります。これにより、論理レプリケーションストリームを中断せずに継続できます。

ただし、スロットのコンシューマがクラスター内の別のノードに接続する場合、コンシューマが以前に持っていた接続はPGDによって閉じられます。この動作は、スロットがマルチプルのノードから同時に消費されないようにするためです。バックグラウンドで、PGDはRaftコンセンサスプロトコルを使用して、スロットが一度に1つのノードのみから消費されるようにします。これは、一度に1つのスロットのみが消費されるという保証が、スプリットブレインシナリオでは成立しないことを意味します。

現在、CDCフェールオーバーのサポートは、トップグループオプションによって制御されるグローバルオプションです。
``failover_slot_scope``
トップグループオプションは現在、論理スロットのレプリケーションを無効にする\ ``local``
または\ ``global`` に設定できます。デフォルト。 ``global`` 設定は、
PGDデータベースで作成されたすべての非一時論理スロットのレプリケーションを有効にします。

一時論理スロットは、有効期間がそれらを作成したセッションにスコープされ、そのセッションが終了すると消失するため、レプリケートされません。

少なくとも1回の配信保証
^^^^^^^^^^^^^^^^^^^^^^^

CDCフェールオーバーサポートは、コンシューマーがすべての変更を少なくとも1回受信できるようにするための手順を実行します。これは、配信が確認されるまでスロットを抑制することにより行われ、その時点でスロットは非同期方法ですべてのノードで進められます。スロットが消費されていたノードに障害が発生した場合、スロットは、コンシューマがクラスター内のノードに接続するまで保持されます。これにより、スロットが進行できます。

..  Important  ::
   使用するアプリケーションが切断され、再接続しない場合、スロットはクラスター内のすべてのノードで保留されたままになります。これはディスクとメモリを消費するため、この状況を回避することが重要です。スロットを消費するアプリケーションは、できるだけ早く消費に戻る必要があります。

1回限りの配信
^^^^^^^^^^^^^

現在、正確に1回だけの配信を保証する方法はなく、使用するアプリケーションが、以前に完了したトランザクションの破棄を管理することを期待しています。

CDCフェールオーバーサポートの有効化
-----------------------------------

CDCフェールオーバーのサポートを有効にするには、
SQLコマンドを実行し、次のパラメーターを使用して `bdr.alter_node_group_option <https://www.enterprisedb.com/docs/pgd/latest/reference/tables-views-functions/nodes-management-interfaces#bdralter_node_group_option>`_ ファンクションを呼び出します。

.. code:: sql

   select bdr.alter_node_group_option(<top-level group name>,
        failover_slot_scope,
        global);

``<top-level group name>``
は、クラスターのトップレベルグループの名前に置き換えます。名前がわからない場合は、
`bdr.node_group <https://www.enterprisedb.com/docs/pgd/latest/reference/tables-views-functions/catalogs-visible#bdrnode_group>`_ のnode_group_parent_idが0に等しいグループです。

名前がわからない場合は、
`bdr.node_group <https://www.enterprisedb.com/docs/pgd/latest/reference/tables-views-functions/catalogs-visible#bdrnode_group>`_ で0に等しいnode_group_parent_idを持つグループです。次のものも使用できます。

.. code:: sql

   SELECT bdr.alter_node_group_option(
        node_group_name,
        failover_slot_scope,
        global)
       from bdr.node_group 
       where node_group_parent_id=0;

このコマンドにより、正しいトップレベルグループのオプションを設定できます。

CDCフェールオーバーが有効になったら、新しいグローバルにレプリケートされたスロットを作成するには、以下を使用できます。

.. code:: sql

   SELECT pg_create_logical_replication_slot(myslot,
                                             test_decoding);

オプションが\ ``global``
に設定される前に作成された論理レプリケーションスロットはレプリケートされません。新しいスロットのみが複製されます。

フェールオーバースロットは、レプリケーション接続で\ ``CREATE_REPLICATION_SLOT``
コマンドを使用して作成することもできます。

フェイルオーバースロットのステータスは、 `bdr.failover_replication_slots <https://www.enterprisedb.com/docs/pgd/latest/reference/tables-views-functions/catalogs-visible#bdrfailover_replication_slots>`_ テーブルで追跡されます。

Postgres 17+でのCDCフェールオーバーのサポート
---------------------------------------------

Postgres
17以降では、フェールオーバーのサポートが追加され、スタンバイを再開できるようになりました。このためには、
``failover`` という名前の\ ``pg_create_logical_replication_slot``
のオプションを使用します。この新しい設定では、 ``failover_slot_scope``
の設定に関係なく、 ``failover`` を\ ``true`` に設定する必要があります。

.. code:: sql

   SELECT pg_create_logical_replication_slot(myslot,
                                             test_decoding,
                                             failover=>true);

一貫した初期スナップショットの取得
----------------------------------

論理レプリケーションスロットが作成されると、一貫したスナップショットがPostgresによってエクスポートされます。このスナップショットを使用して、データの一貫した初期コピーを取得できます。
PGDのフェイルオーバースロットメカニズムも同じ手順に従います。ただし、コンシューマは、スロットが最初に作成されたノードと同じノードからスナップショットを取得する必要があります。さらに、同じノードから初期レプリケーションを開始する必要があります。コンシューマがレプリケーションストリームを介して十分な変更を受信すると、フェールオーバースロットは\ ``failover_safe``
としてマークされます。スロットが\ ``failover_safe``
としてマークされると、コンシューマはPGDクラスター内の他のノードに安全にフェイルオーバーできます。ただし、他の考慮事項が適用されます。以下を参照してください。

スロットが\ ``failover_safe``
かどうかを確認するには、\ ``bdr.failover_replication_slots``
カタログを照会し、指定されたスロットの\ ``failover_safe``
列の値を確認できます。

スロットが\ ``failover_safe``
とマークされる前に、コンシューマが他のPGDノードに接続し、レプリケーションを開始しようとすると、PGDによって適切なエラーが発生します。

新しく参加したノードへのフェイルオーバー
----------------------------------------

新しいノードがPGDクラスターに参加すると、CDCフェールオーバースロットのデコードターゲットとして機能する準備がすぐに整わない場合があります。新しく参加したノードには、コンシューマがまだ使用していない変更をデコードするためのすべてのWALファイルがない場合があります。このようなノードから消費すると、データの損失が発生する可能性があります。
PGDは、レプリケーションの進行状況を内部で追跡し、安全なまで新しいノードがフェールオーバーターゲットになるのを防ぐことにより、このような状況を検出して防止します。コンシューマが、デコードターゲットとして機能する準備がまだ整っていないノードに接続しようとすると、適切なエラーが発生します。

オリジンごとの進行状況の追跡
----------------------------

トランザクションは、PGDクラスター内の任意のノードから発生できます。コンシューマがPGDノードに接続し、トランザクションのデコードを開始すると、そのノードで発生したトランザクションと、クラスター内の他のノードからレプリケートされたトランザクションの変更を受信する場合があります。コンシューマは、このようなすべてのPGDノードまたはオリジンにわたってレプリケーションの進行状況を追跡し、重複したトランザクションが正しく処理されることを確認することが求められます。これを促進するために、Postgres-ExtendedおよびEnterpriseDB
Advance Serverの\ ``test_decoding``
プラグインが機能強化され、トランザクションの起点情報が含まれるようになりました。コンシューマは、論理レプリケーションの開始時に\ ``include-origin``
オプションを\ ``on``
に設定することにより、オリジン情報を受信することを選択できます。

以下は、起点情報を含む\ ``test_decoding`` プラグインのサンプル出力です。

.. code:: text

   BEGIN 1723654 (origin 2) (origin_name bdr_bdrdemo_bdrgroup_node2) (origin_lsn 0/1D948910)
   table public.pgbench_accounts: UPDATE: old-key: aid[integer]:39958 bid[integer]:1 abalance[integer]:0 filler[character]:                                                                                     new-tuple: aid[integer]:39958 bid[integer]:1 abalance[integer]:-1783 filler[character]:                                                                                    
   table public.pgbench_tellers: UPDATE: old-key: tid[integer]:6 bid[integer]:1 tbalance[integer]:0 new-tuple: tid[integer]:6 bid[integer]:1 tbalance[integer]:-1783 filler[character]:null
   table public.pgbench_branches: UPDATE: old-key: bid[integer]:1 bbalance[integer]:0 new-tuple: bid[integer]:1 bbalance[integer]:-1783 filler[character]:null
   table public.pgbench_history: INSERT: tid[integer]:6 bid[integer]:1 aid[integer]:39958 delta[integer]:-1783 mtime[timestamp without time zone]:2025-01-31 16:51:21.511571 filler[character]:null
   COMMIT 1723654 (origin 2) (origin_name bdr_bdrdemo_bdrgroup_node2) (origin_lsn 0/1D948910)

コンシューマはこの情報を利用して、オリジンごとの進行状況を追跡できます。

PGDは、\ ``bdr.logical_checkpoints``
カタログ内のすべてのノードにわたるレプリケーションの進行状況も記録し、コンシューマはカタログのデコードされた変更を受信し、その情報を使用してレプリケーションの進行状況を知ることができます。

.. code:: text

   ​​BEGIN 65720
   id[name]:370098259-0-6056978 origin_node[oid]:370098259 origin_lsn[pg_lsn]:0/6056978 local_node[oid]:370098259 local_lsn[pg_lsn]:0/6056978 peer_count[integer]:2 peer_nodes[oid[]]:{2228531844,4052927809} peer_lsns[pg_lsn[]]:{0/4836758,0/67F0AF8}
   COMMIT 65720

この例では、ノード370098259がレプリケーションの進行状況を報告しています。コンシューマがこの変更レコードを受信すると、ノード2228531844および4052927809からそれぞれ0/4836758および0/67F0AF8までのすべてを受信したことを確認できます。

..  Important  ::
   現在、PGDは、`bdr.node` カタログに保存されているOIDとしてノード情報を報告します。しかし、これは近い将来に変わり、情報はUUIDに置き換えられます。

制限事項
--------

CDCフェールオーバースロットのサポートには、特定の制限があります。

- CDCフェールオーバースロットのサポートには、 EDB Postgres
  DistributedPGD 5.7+の最新バージョンとPostgres ExtendedまたはEDB
  Postgres Advanced
  Serverの最新のマイナーリリース2025年2月利用可能が必要です。

- CDCフェールオーバーのサポートはグローバルオプションであり、スロットごとに設定はできません。
  CDCフェールオーバーの有効なステータスの変更は、以前にプロビジョニングされたスロットに影響を与えないため、これを有効にして\ ``global``
  に設定し、レプリケートスロットを作成してから無効にして\ ``local``
  に設定して、単一のレプリケートスロットを作成することが可能です。

- CDCフェールオーバーのサポートは、一時的なスロットではサポートされていません。

- CDCフェールオーバーのサポートは、 ``failover`` オプションを\ ``false``
  に設定して作成されたスロットではサポートされていません。

- CDCフェールオーバーのサポートは、EDB Postgres Advanced ServerおよびEDB
  Postgres Extended
  Serverでのみ動作します。コミュニティPostgresインストールではサポートされていません。

- オプションが有効になっている場合、既存のスロットはフェールオーバースロットに変換されません。

- ``pg_logical_slot_get_changes()``
  などのPostgresのビルトイン機能は使用できますが、スロットが他の場所でデコードされていないことは保証されず、クラスター全体のレプリケーションの進行状況を正確に更新できません。したがって、デコードされた変更を受信するファンクションに依存しないことをお勧めします。
