EDB Postgres Distributed Proxy overview
=======================================

特に非同期レプリケーションでは、競合を回避し、アプリケーションの可用性を保証するために、一貫した書き込みリーダーノードを持つことが重要です。

EDB Postgres Distributedのプロキシレイヤーの2つの部分は次のとおりです。

-  プロキシ構成とルーティング情報。
   PGDコンセンサスメカニズムによって維持されます。

-  ホストにインストールされるPGDプロキシサービス。
   PGDクラスターに接続し、構成を読み取り、ルーティング情報の変更をリッスンします。

このレイヤーは、通常、高可用性構成PGDグループごとにプロキシサービスの少なくとも2つのインスタンスでインストールされます。

構成が完了すると、 PGDプロキシサービスは、 EDB
Postgres Distributedクラスターによって決定されたとおりにルーティングの変更を監視します。これらの変更に基づいて動作して、接続が一貫して正しいノードにルーティングされるようにします。

PGDプロキシサービスの構成変更は、 PGDクラスターを介して行われます。
PGDプロキシサービスは、PGDクラスターから構成を読み取りますが、プロキシサービスを再起動してこれらの変更を適用する必要があります。

現在選択されている書き込みノードおよび読み取りノードに関する情報は、\ ``bdr.node_group_routing_summary``
に表示されます。これはノードローカルビューです。プロキシは常にRaftリーダーから読み取り、最新の一貫したビューを取得します。

リーダーの選択
--------------

書き込みリーダーは、プロキシが属しているグループの現在のRaftリーダーによって選択されます。
これは、サブグループのRaftリーダーまたはクラスター全体のリーダーである可能性があります。リーダーは、
:ref:`PGDプロキシクラスター構成 <PGDプロキシクラスター構成>` で説明している構成に基づいて、到達可能で基準を満たす候補ノードから選択されます。実行可能な候補になるには、ノードで\ ``route_writes``
が有効になり\ ``route_fence``
が無効で、以前のリーダーから\ ``route_writer_max_lag``
有効な場合内にある必要があります。候補者は\ ``route_priority``
で降順に、以前のリーダーからの遅延で昇順に並べられます。

新しいリーダー選択プロセスは、現在既存のリーダーが存在しない場合、または既存のリーダーへの接続が失われた場合に開始されます。既存の書き込みリーダーがない場合、有効な候補が存在しないか、Raftがダウンしていることが考えられます。

ノードは、リーダーから受け取った最後のRaftプロトコルメッセージがRaft選挙タイムアウトより古くない場合、接続されているとみなされます
:ref:`内部設定 - Raftタイムアウト <内部設定 - Raftタイムアウト>` を参照してください。

Raftリーダーは選択タイムアウト制限ごとに3回ハートビートを送信しているため、リーダーノードは、切断されたと考えられる前に3つのハートビートへの応答を逃す必要があります。

PGDプロキシクラスター構成
-------------------------

PGDクラスターには、常に少なくとも1つのトップレベルグループと1つのデータグループがあります。
PGDは、 ``enable_proxy_routing`` および\ ``enable_raft``
オプションがtrueに設定されている各データグループの書き込みリーダーを選択します。

クラスターは、各グループのプロキシ構成も維持します。各構成には名前があり、グループに関連付けられています。プロキシをトップレベルグループまたはデータグループに接続できます。各グループに複数のプロキシをアタッチできます。
PGDプロキシサービスがホストで実行を開始すると、ローカル構成ファイルに名前があり、グループ内のノードに接続します。そこから、名前を使用して、グループに保存されている完全な構成を検索します。

PGDプロキシサービス
-------------------

EDB
Postgres DistributedプロキシPGDプロキシサービスは、クライアントアプリケーションとPostgres間の抽象化レイヤーとして機能するプロセスです。
PGDコンセンサスメカニズムとインターフェイスして、現在の書き込みリーダーノードのIDを取得し、トラフィックをそのノードにリダイレクトします。また、オプションで読み取り専用モードをサポートし、書き込みリーダーではないノードに読み取り専用クエリをルーティングできるため、クラスターの全体的なパフォーマンスを向上させます。

PGDプロキシは、TCPレイヤー4プロキシです。

連携する方法
------------

PGDプロキシは、起動時に、ローカル構成ファイルで指定されたエンドポイントのいずれかに接続します。それは取得します

-  すべてのノードのDB接続情報。

-  リッスンアドレス、リッスンポートなどのプロキシオプション。

-  デフォルトモードの現在の書き込みリーダー、読み取り専用モードの読み取りノード、または任意のモードの両方を含むルーティングの詳細。

構成ファイルで指定されたエンドポイントは、起動時にのみ使用されます。その後、実際のエンドポイントは、
PGDカタログの `bdr.node_routing_config_summary <https://www.enterprisedb.com/docs/pgd/latest/reference/catalogs-internal#bdrnode_routing_config_summary>`_ の\ ``route_dsn``
フィールドから取得されます。

PGDは、書き込みリーダー選択を管理します。
PGDプロキシはPGDと対話して、Postgres通知/リッスンチャネルで書き込みリーダー変更イベント通知を取得し、クライアントトラフィックを現在の書き込みリーダーにルーティングします。
PGDプロキシは、書き込みリーダーの変更または書き込みリーダーが使用できないときに、既存のすべてのクライアント接続を切断します。書き込みリーダー選挙はRaftによってサポートされるアクティビティであり、Raftリーダーの可用性の対象となります。書き込みリーダーが使用できない場合、
PGDプロキシは新しいクライアント接続を閉じます。

PGDプロキシは、 *フェールオーバー* と *スイッチオーバー*
の2つの操作モードに分類できる書き込みリーダー変更イベントに応答します。

Postgresまたはオペレーティングシステムがクラッシュした場合に、現在の書き込みリーダーノードから新しいノードへの書き込みリーダーシップの自動転送は、
*フェールオーバー* と呼ばれます。
PGDは、現在の書き込みリーダーがダウンするか、応答しなくなると、新しい書き込みリーダーを選択します。新しい書き込みリーダーがPGDによって選択されると、
PGDプロキシは古い書き込みリーダーへの既存のクライアント接続を閉じ、新しいクライアント接続を新しく選択された書き込みリーダーにリダイレクトします。

現在の書き込みリーダーから新しいターゲットリーダーへのユーザー制御の手動転送は、
*スイッチオーバー* と呼ばれます。スイッチオーバーは、
:ref:`計画的なスイッチオーバーを実行する <計画的なスイッチオーバーを実行する>` コマンドを介してトリガーされます。コマンドはPGDに送信され、指定されたターゲットノードを新しい書き込みリーダーとして選択しようとします。フェールオーバーと同様に、
PGDプロキシは既存のクライアント接続を閉じ、新しいクライアント接続を新しく選択された書き込みリーダーにリダイレクトします。これは、サーバーのメンテナンス中に、たとえば、サーバーの更新やOSパッチの更新などのメンテナンスのために現在の書き込みリーダーノードを停止する必要がある場合に役立ちます。

プロキシが読み取り専用ルーティングをサポートするように構成されている場合、読み取り専用クエリを書き込みリーダーではないノードのプールにルーティングできます。ノードのプールはPGDクラスターによって維持され、プロキシはプールへの変更をリッスンします。プールが変更されると、プロキシはルーティング構成を更新し、ノードの新しいプールへの読み取り専用クエリのルーティングを開始し、プールを離れたノードへの既存のクライアント接続の切断を開始します。

コンセンサス猶予期間
^^^^^^^^^^^^^^^^^^^^

PGDプロキシは、Raftリーダーの損失時にルーティング動作を構成するために使用できる\ ``consensus_grace_period``
プロキシオプションを提供します。
PGDプロキシは、この期間にわたって現在の書き込みリーダー利用可能な場合にルーティングし続けます。この期間中に新しいRaftリーダーが選出されない場合、プロキシはルーティングを停止します。
``0s``
に設定されている場合、PGDプロキシはルーティングをすぐに停止します。

このオプションの主な目的は、Raftリーダーが失われたときにユーザーが書き込み動作を構成できるようにすることです。
Raftリーダーがクラスターに存在しない場合、プロキシから見られる現在の書き込みリーダーが正しいものであるとは、必ずしも保証されません。場合によっては、次の例のネットワークパーティションのように、2つの書き込みリーダーが、同じグループに接続された2つの異なるプロキシによって認識され、書き込み競合の可能性が増加する可能性があります。これが目的の動作でない場合は、前述の\ ``consensus_grace_period``
を0sに設定できます。この設定は、Raftリーダーが失われたことを検出すると、ルーティングを停止し、既存のオープン接続をすぐに閉じるようにプロキシを構成します。

ネットワークパーティションの例
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

各データノードにプロキシがある3つのデータノードグループを検討します。この場合、現在の書き込みリーダーがネットワーク分割または分離されると、マジョリティパーティションに存在するデータノードが新しい書き込みリーダーを選択します。
``consensus_grace_period`` がゼロ以外の値たとえば\ ``10s``
に設定されている場合、以前の書き込みリーダーに存在するプロキシは、この期間書き込みをルーティングし続けます。

この場合、猶予期間が長すぎると、2つの書き込みリーダーで書き込みが発生し続けます。この条件により、書き込み競合が発生する可能性が増加します。

そうは言っても、ほとんどの場合、現在のRaftリーダーを失うと、ノードクォーラムの半分以上がまだ残っている場合、新しいRaftリーダーは数秒以内にBDRによって選択されます。したがって、Raftリーダーがダウンしているが、書き込みリーダーがまだアップしている場合、\ ``consensus_grace_period``
をゼロ以外の正の値に保つことにより、ルーティングを許可するようにプロキシを構成できます。プロキシは、ルーティングを停止する前に、この期間にRaftリーダーが選出されるのを待ちます。これは、可用性がより重要な場合に役立つ場合があります。

コンセンサス読み取り猶予期間
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

``consensus_grace_period`` と同様に、 ``read_consensus_grace_period``
オプションは読み取り専用ルーティングで使用できます。このオプションは、読み取り専用クエリのRaftリーダーが損失した際のルーティング動作を構成するために使用できます。
PGDプロキシは、この期間中、現在の読み取りノードへのルーティングを継続します。この期間中に新しいRaftリーダーが選出されない場合、プロキシは読み取り専用クエリのルーティングを停止します。
``0s``
に設定されている場合、PGDプロキシは読み取り専用クエリのルーティングをすぐに停止します。

マルチホスト接続文字列
^^^^^^^^^^^^^^^^^^^^^^

PostgreSQL
Cクライアントライブラリlibpqを使用すると、単純なフェイルオーバーのために単一の接続文字列で複数のホスト名を指定できます。この機能は、他の一部のプログラミング言語のクライアントライブラリドライバーでもサポートされています。ダウンまたはアクセス不能なPGDプロキシインスタンス全体のフェイルオーバーに適しています。

アプリケーションが書き込みリーダーへのアクセスを持たないプロキシインスタンスに接続する場合、接続は単に失敗します。マルチホスト接続文字列内の他のホストは試行されません。この動作は、
HAProxyやpgbouncerなどの他のプロキシを使用したPostgreSQLクライアントライブラリの動作と一貫しています。書き込みリーダーにアクセスするには、インスタンスが一部であるグループがグループの書き込みリーダーを選択できる必要があります。
