Cluster topology
================

クラスタートポロジは、PostgreSQLレプリケーションクラスターを視覚的に表現します。ストリーミングレプリケーションを介して接続されているデータベースサーバーを自動的に検出し、以下を示す対話型図に表示します。

- プライマリサーバー — レプリケーションのソース。

- レプリカサーバー — レプリケートされたデータを受信するサーバー。

- レプリケーション関係 — どのサーバーがどのサーバーから複製するか。

- 同期状態 — レプリケーションが同期か非同期か。

- カスケードレプリケーション — 他のレプリカから複製するレプリカ。

- PGD / BDRクラスター —
  すべてのノードが他のすべてのノードにレプリケートするメッシュレプリケーション。

- Witnessノード —
  高可用性HAセットアップでコンセンサスに使用される非データノード。

トポロジ検出の仕組み
--------------------

PEMは、PostgreSQLサーバーからデータを収集する専用プローブを使用して、レプリケーショントポロジを検出します。プローブは、生のレプリケーションデータを収集し、相関機能によって処理されて、クラスタートポロジを構築します。

..  Note::
   **Refresh**をクリックすると、トポロジビューが更新されます。これにより、相関ファンクションがトリガーされ、最新のプローブデータを処理し、クラスター情報を更新します。

必須プローブ
^^^^^^^^^^^^

トポロジ機能が正常に動作するには、監視対象サーバーで次のプローブを有効にします。

.. csv-table::
  :header: Probe name,Required for,Description
  :widths: 12,15,25
  :align: left
  :class: longtable

  Streaming Replication,All cluster types,`pg_stat_replication`プライマリ上および`pg_stat_wal_receiver`スタンバイ上からレプリケーションデータを収集します。すべてのトポロジ検出に必要です。
  PGD Group Summary (`bdr_group_summary`),PGD clusters,PGDグループレベルの情報を収集します。
  PGD Node Summary (`bdr_node_summary`),PGD clusters,ノード名、サブグループ、書き込みリーダーステータスを含むPGDノード情報を収集します。
  EFM Cluster Node Status,EFM clusters,`efm_cluster_node_status`プローブを介してEFMノードデータを収集します。

これらのプローブは、新しいサーバー登録でデフォルトで有効になっています。トポロジデータが表示されない場合は、これらのプローブが
**Management > Probe Configuration**
で有効になっていることを確認します。

クラスタータイプの検出
^^^^^^^^^^^^^^^^^^^^^^

PEMは、サーバー構成に基づいてクラスタータイプを自動的に検出します。

.. csv-table::
  :header: Cluster type,How it's detected
  :widths: 10,30
  :align: left
  :class: longtable

  Physical Streaming Replication (PSR),Default for servers with streaming replication and no HA manager configured.
  PGD,Servers with the BDR extension installed (detected via PGD probes).
  Patroni,Servers with  **Patroni Cluster Name**  configured in server properties.
  EDB Failover Manager (EFM),Servers with  **EFM Cluster Name**  configured in server properties.

PatroniまたはEFMクラスター検出を有効にするには、PEMでサーバーを登録または編集するときにサーバーのプロパティで各クラスター名を構成します。

トポロジービューへのアクセス
----------------------------

2つの方法でクラスタートポロジビューを開くことができます。

- パネルヘッダーの右上隅にある **3つの点⋯** をクリックし、 **Open >
  Cluster Topology** を選択します。

- オブジェクトツリーでサーバーを右クリックし、 **Show Cluster Topology**
  を選択します。

必要な権限
^^^^^^^^^^

クラスタートポロジを表示するには、ユーザーに\ ``pem_topology_view``
ロールが必要です。 PEM管理者に連絡して、この権限を付与してください。

トポロジ表示を理解する
----------------------

クラスターリスト左側のサイドバー
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

サイドバーには、検出されたすべてのレプリケーションクラスターが表示されます。

.. csv-table::
  :header: Element,Description
  :widths: 10,30
  :align: left
  :class: longtable

  Cluster name,自動生成またはプライマリサーバーの説明。
  Type badge,PSR、パトローニ、EFM、またはPGD。
  Member count,クラスター内のサーバーの数。

サポートされているクラスタータイプ
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. csv-table::
  :header: Type,Description
  :widths: 10,30
  :align: left
  :class: longtable

  PSR,物理的ストリーミングレプリケーション標準のPostgreSQL。
  Patroni,Patroni管理対象HAクラスター。
  EFM,EDBフェールオーバーマネージャークラスター。
  PGD,メッシュレプリケーションを使用したPostgres DistributedBDR。

トポロジグラフメインパネル
^^^^^^^^^^^^^^^^^^^^^^^^^^

インタラクティブ図には、ノードとそれらの間の接続が表示されます。

**ノードタイプ**

.. csv-table::
  :header: Node color,Description
  :widths: 10,30
  :align: left
  :class: longtable

  Green border,プライマリ — レプリケーションを提供するソースサーバー。
  Blue border,レプリカ — レプリケートされたデータを受信するサーバー。
  Purple border,データノード — 読み取りおよび書き込みを受け入れるPGDデータノード。
  Orange border,Witness — HAコンセンサス用の非データノード。
  Gray border,Unknown — 未登録のレプリカIPアドレスを表示します。

各ノードには、サーバーの名前または説明、ホスト名とポート、ロールバッジプライマリ/レプリカ、およびレプリカの同期状態バッジが表示されます。

図の右上隅の凡例は、色分けを説明しています。

インタラクティブSVGビュー
-------------------------

トポロジの視覚化では、次の機能を備えたインタラクティブなスケーラブルベクターグラフィックSVGビューを使用します。

パンとズーム
^^^^^^^^^^^^

- **ズームイン/アウト** — マウススクロールホイールを使用します。

- **パン** — キャンバス上の任意の場所をクリックしてドラッグします。

- **ズームコントロール** — 右下隅にある **+** および **−**
  ボタンを使用します。 **Fit to screen**
  ボタンは、ビューをリセットして、ビューポート内のすべてのノードに収まるようにします。

フルスクリーンモード
^^^^^^^^^^^^^^^^^^^^

ヘッダーの **フルスクリーン**
ボタンをクリックして、ビューを展開します。これは、チームメンバーにトポロジを提示したり、大規模なクラスターを表示したり、ドキュメントのスクリーンショットを撮ったりする場合に役立ちます。
**Escape** を押すか、ボタンを再度クリックして終了します。

SVGエクスポート
^^^^^^^^^^^^^^^

ヘッダーの **Download**
ボタンをクリックして、現在のトポロジビューをSVGファイルとしてエクスポートします。

ノードカードの詳細
^^^^^^^^^^^^^^^^^^

各サーバーは、次の情報を含むカードとして表示されます。

- **アイコン** —
  登録済みサーバーのストレージアイコン、未登録サーバーのヘルプアイコン。

- **サーバー名** — サーバーの説明またはホスト名。

- **ロールバッジ** ``P`` プライマリ、\ ``R`` レプリカ、\ ``D``
  PGDのデータノード、\ ``W`` 書き込みリーダーまたはWitness、\ ``?``
  不明。

- **Hostname:Port** — サーバーの接続情報。

- **タグ** — 「Write
  Leader」や「Raft_Leader」などのサーバータグは、丸薬型のバッジとして表示されます。

- **ステータス** — PEMに登録されていないサーバーの「Not
  Registered」インジケーター。

レンダラー設定
^^^^^^^^^^^^^^

PEMは2つのレンダリングモードを提供します。 **Preferences > Cluster
Topology > Renderer** でそれらを切り替えます。

.. csv-table::
  :header: Renderer,Description
  :widths: 10,30
  :align: left
  :class: longtable

  SVG (default),パン/ズームおよびスムーズなツールチップを備えたインタラクティブSVGビュー。
  HTML,パン/ズームを使用しないクラシックなHTML/CSSレンダリング。

PGD/ BDRクラスター
------------------

BDR双方向レプリケーションとしても知られるPostgres
DistributedPGDは、すべてのノードが書き込みを受け入れることができるマルチマスターレプリケーションソリューションです。従来のプライマリレプリカ設定とは異なり、
PGDは、すべてのノードが他のすべてのノードにレプリケートするメッシュレプリケーションを使用します。

ポリゴンとフォースグラフのレイアウト
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**ポリゴンレイアウト1〜8ノード**

1〜8のデータノードを含むPGDクラスターの場合、PEMはポリゴンメッシュレイアウトを使用します。1つのノードには単一の中央カード、2には水平ペア、3〜8ノードにはポリゴン構成三角形、正方形、五角形など。破線はすべてのノードを接続して、メッシュレプリケーショントポロジを視覚化します。

**Forceグラフレイアウト9+ノード**

9つ以上のデータノードを持つ大規模なPGDクラスターの場合、PEMは強制グラフレイアウトに切り替えます。ノードは、番号付きのラベルの付いた色付きの円として表示されます。ノードにカーソルを合わせると、ツールチップで完全な詳細が表示されます。書き込みリーダーは外側のリングで強調表示され、まばらなメッシュ線は、視覚的に混乱することなく接続を示します。

サブグループ
^^^^^^^^^^^^

PGDクラスターは、ノードをサブグループロケーションとも呼ばれ、通常は地理的なデータセンターまたはアベイラビリティーゾーンを表すサブグループに編成できます。
PGDクラスターに複数のサブグループがある場合、PEMはそれらを、サブグループの中心を接続するサブグループ間破線で個別の境界線付きカードとして表示します。
3つ以上のサブグループの場合、カードは円形に配置されます。

すべてのノードが同じサブグループに属しているか、サブグループが定義されていない場合、PEMは標準のポリゴンまたはフォースグラフレイアウトを使用してノードを直接表示します。

未登録のレプリカでの作業
------------------------

PEMがPEM監視対象サーバーとして登録されていないレプリカを検出すると、カード内のIPアドレスと「Not
Registered」ラベルを示す「不明な」ノードとして表示されます。

これを解決するには、PEMにレプリカサーバーを登録します。

トポロジデータの更新
--------------------

Streaming
Replicationプローブは、デフォルトで5分ごとに実行され、サーバーから最新のレプリケーションデータを収集します。この生データは、相関機能で処理して、トポロジビューを更新する必要があります。

トポロジビューヘッダーの **Refresh**
をクリックして相関機能をトリガーし、新しいまたは変更されたクラスターでクラスターリストを更新し、現在のトポロジグラフを更新します。レプリケーション設定に変更を加えた後-レプリカの追加やフェールオーバーの実行後、常に[
**Refresh** ]をクリックして、更新されたトポロジを表示します。

障害対応
--------

**クラスターは表示されません**

考えられる原因

- Streaming Replicationプローブはまだ実行されていません -
  5分間待機するか、手動更新をトリガーします。

- 監視対象サーバーではストリーミングレプリケーションが構成されていません。

- ``streaming_replication`` プローブは無効になっています。

プローブが **プローブ構成**
で有効になっていることを確認し、\ ``pg_stat_replication``
がプライマリサーバー上のデータを返すことを確認して、更新を手動でトリガーします。

**サーバーは「Unknown」と表示されます**

レプリカのIPアドレスは、登録されたサーバーと一致しません。
PEMにサーバーを登録するか、サーバーの\ ``server`` または\ ``hostaddr``
フィールドがレプリケーションで表示されるIPと一致することを確認します。

**トポロジグラフは空です**

考えられる原因

- 選択したクラスターには、アクティブなメンバーがありません。

- すべてのメンバーが非アクティブになりました。

サーバーが実行され、エージェントが接続されていることを確認し、プローブがデータを収集していることを確認します。

.. code:: sql

   SELECT * FROM pemdata.streaming_replication;

**PGDクラスターが検出されませんでした**

PGD Node Summary ``bdr_node_summary``
プローブはデータを収集していません。
PGDサーバーでプローブが有効になっていることを確認し、サーバーにBDRがインストールおよび構成されていることを確認し、プローブデータを照会します。

.. code:: sql

   SELECT * FROM pemdata.bdr_node_summary WHERE server_id = <id>;

**PGDノードが「Unregistered」と表示される**

BDRノード名は、登録されたサーバーの説明またはホスト名と一致しません。
PGD Node Summary ``bdr_node_summary`` プローブでノード名を確認します。

.. code:: sql

   SELECT node_name FROM pemdata.bdr_node_summary;

次に、ノード名と正確に一致するようにサーバーの説明を更新するか、正しいノード名を説明として新しいサーバーを登録します。

ベストプラクティス
------------------

- **すべてのサーバーを登録する**
  最も正確なトポロジビューを得るには、レプリカを含むすべてのサーバーを登録します。未登録のノードには、ヘルプアイコンと「未登録」ステータスが表示されます。

- **一貫した名前付けを使用します** -
  サーバーに意味のある説明を提供して、トポロジ図を理解しやすいようにします。

- **PGDクラスターの場合** — 適切なノード照合のために、
  BDRノード名と正確に一致するようにサーバーの説明を設定します。

- **プローブのステータスをモニタする** — ``streaming_replication``
  プローブが有効になっていて実行されていることを確認します。

- **フェールオーバー後のチェック** —
  計画的または計画外のフェールオーバーの後、トポロジを更新して新しい構成を確認します。

- **ドキュメントにはSVGエクスポートを使用します** —
  アーキテクチャドキュメントまたはプレゼンテーションに含めるために、トポロジをSVGとしてエクスポートします。

- **大規模なクラスターにはフルスクリーンを使用します** —
  多くのノードを持つクラスターの場合、フルスクリーンモードはより適切な概要を提供します。

- **詳細をズーム** —
  ズームコントロールを使用して、個々のノードの詳細を確認するか、クラスター全体の鳥瞰図を取得します。

- **ノードツールチップの確認**
  強制グラフレイアウトでは、ノードにカーソルを合わせると、ホスト名、ポート、ロール、タグを含む詳細情報を表示します。

トポロジデータのSQLクエリー
---------------------------

スクリプト、レポート、または他のツールとの統合のために、
SQLを介してトポロジデータを直接照会する場合は、PEMデータベースに対して次のクエリを実行します。

検出されたすべてのクラスターをリストする
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: sql

   SELECT
       c.id AS cluster_id,
       c.name AS cluster_name,
       c.cluster_type,
       ps.description AS primary_server,
       ps.server AS primary_host,
       (SELECT COUNT(*) FROM pem.replication_cluster_member m
        WHERE m.cluster_id = c.id AND m.is_active = true) AS active_members,
       c.updated_at AS last_updated
   FROM pem.replication_cluster c
   LEFT JOIN pem.server ps ON ps.id = c.primary_server_id
   ORDER BY c.name;

ロールを持つクラスターメンバーを表示する
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: sql

   SELECT
       c.name AS cluster_name,
       c.cluster_type,
       m.role,
       COALESCE(s.description, m.client_hostname, host(m.client_addr)::text) AS node_name,
       s.server AS hostname,
       s.port,
       m.sync_state,
       m.cascade_level,
       m.subgroup_name,
       CASE WHEN m.server_id IS NOT NULL THEN Yes ELSE No END AS registered_in_pem,
       m.updated_at
   FROM pem.replication_cluster_member m
   JOIN pem.replication_cluster c ON c.id = m.cluster_id
   LEFT JOIN pem.server s ON s.id = m.server_id
   WHERE m.is_active = true
   ORDER BY c.name, m.cascade_level, m.role DESC;

レプリケーションラグの表示PSR、EFM、およびPatroniクラスター
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: sql

   SELECT
       c.name AS cluster_name,
       ps.description AS primary_server,
       sr.client_addr AS replica_address,
       COALESCE(rs.description, sr.client_addr) AS replica_name,
       m2.sync_state,
       sr.lag_mb,
       sr.recorded_time AS last_collected
   FROM pemdata.streaming_replication sr
   JOIN pem.replication_cluster_member m
       ON m.server_id = sr.server_id AND m.role = primary AND m.is_active = true
   JOIN pem.replication_cluster c ON c.id = m.cluster_id
   JOIN pem.server ps ON ps.id = sr.server_id
   LEFT JOIN pem.server rs ON host(rs.server::inet) = host(sr.client_addr::inet)
   LEFT JOIN pem.replication_cluster_member m2
       ON m2.cluster_id = c.id AND host(m2.client_addr) = host(sr.client_addr::inet)
       AND m2.is_active = true
   WHERE c.cluster_type IN (psr, efm, patroni)
     AND sr.client_addr IS NOT NULL
   ORDER BY c.name, sr.lag_mb DESC;

レプリケーションラグPGDクラスターの表示
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: sql

   SELECT
       c.name AS cluster_name,
       ps.description AS write_leader,
       bns.target_name AS peer_node,
       bns.client_addr AS peer_address,
       bns.active_pid AS slot_pid,
       bns.replay_lag_bytes,
       ROUND(bns.replay_lag_bytes / (1024.0 * 1024), 2) AS lag_mb,
       bns.replay_lag_size AS lag_pretty,
       bns.recorded_time AS last_collected
   FROM pemdata.bdr_node_slots bns
   JOIN pem.replication_cluster_member m
       ON m.server_id = bns.server_id AND m.role = primary AND m.is_active = true
   JOIN pem.replication_cluster c ON c.id = m.cluster_id
   JOIN pem.server ps ON ps.id = bns.server_id
   WHERE c.cluster_type = pgd
     AND bns.target_name IS NOT NULL
   ORDER BY c.name, lag_mb DESC;

完全なトポロジの概要すべてのクラスタータイプ
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

このクエリは、すべてのクラスター、メンバー、およびレプリケーションラグの統合ビューを提供します。

.. code:: sql

   WITH cluster_lag AS (
       -- PSR/EFM/Patroni lag from streaming_replication
       SELECT
           m.cluster_id,
           host(sr.client_addr::inet) AS replica_addr,
           sr.lag_mb
       FROM pemdata.streaming_replication sr
       JOIN pem.replication_cluster_member m
           ON m.server_id = sr.server_id AND m.role = primary AND m.is_active = true
       JOIN pem.replication_cluster c ON c.id = m.cluster_id
       WHERE c.cluster_type IN (psr, efm, patroni)
         AND sr.client_addr IS NOT NULL

       UNION ALL

       -- PGD lag from bdr_node_slots
       SELECT
           m.cluster_id,
           host(bns.client_addr::inet) AS replica_addr,
           ROUND(bns.replay_lag_bytes / (1024.0 * 1024), 2) AS lag_mb
       FROM pemdata.bdr_node_slots bns
       JOIN pem.replication_cluster_member m
           ON m.server_id = bns.server_id AND m.role = primary AND m.is_active = true
       JOIN pem.replication_cluster c ON c.id = m.cluster_id
       WHERE c.cluster_type = pgd
         AND bns.target_name IS NOT NULL
   )
   SELECT
       c.name AS cluster_name,
       c.cluster_type,
       m.role,
       COALESCE(s.description, m.client_hostname, host(m.client_addr)::text) AS node_name,
       s.server AS hostname,
       s.port,
       m.sync_state,
       m.subgroup_name,
       COALESCE(cl.lag_mb, 0) AS lag_mb,
       CASE WHEN m.server_id IS NOT NULL THEN Yes ELSE No END AS registered
   FROM pem.replication_cluster_member m
   JOIN pem.replication_cluster c ON c.id = m.cluster_id
   LEFT JOIN pem.server s ON s.id = m.server_id
   LEFT JOIN cluster_lag cl
       ON cl.cluster_id = m.cluster_id
       AND cl.replica_addr = COALESCE(host(m.client_addr), s.server)
   WHERE m.is_active = true
   ORDER BY c.name, m.cascade_level, m.role DESC;
