Performing cluster maintenance#

実稼働に移行する前にクラスター構成を確認し、継続的なメンテナンスを注意深く計画します。単一ロケーションのクラスターでの簡単な操作は、複数のロケーションがアクティブな場合、クロスロケーションフェールオーバーをトリガーし、レプリケーションラグを導入し、競合を発生させる可能性があります。

クラスター構成の検証#

セットアップが完了したら、運用に行く前に、サブグループ、ルーティング、およびコミットスコープが正しく構成されていることを確認します。

  • サブグループとそのルーティング設定を確認します。

SELECT node_group_name, node_group_enable_raft, node_group_enable_routing
FROM bdr.node_group;
  • 現在の書き込みリーダーを確認します。

SELECT node_group_name, write_lead
FROM bdr.node_group_routing_summary;
  • コミットスコープ構成を確認します。

SELECT commit_scope_name, commit_scope_origin_node_group, commit_scope_rule
FROM bdr.commit_scopes;

データベースの変更の管理#

地理分散クラスターでは、スキーマの変更と日常的なメンテナンスの動作が異なります。 DDLはクラスター全体のロックを取得しますが、 VACUUM やANALYZE のような操作は各ノードでローカルに実行されますが、レプリケーションスロットのラグの影響を受ける可能性があります。

DDLの実行#

DDL操作はクラスター全体のロックを取得しますが、ロックのタイプとタイミングは操作によって異なります。 ALTER TABLE やCREATE INDEX などのスキーマ変更は、すべてのノードでグローバルDDLロックを同時に取得し、ロック取得時間は最も遠いノードへの往復時間とほぼ等しくなります。 DROP TABLE などのオペレーションは、レプリケーションもフラッシュするグローバルDMLロックを取得し、完了時間はネットワーク遅延のみではなく現在のレプリケーションラグに依存します。

どちらの場合も、長時間実行DDLは、ロックが保持されている間レプリケーションをブロックし、失敗したDDLは場所間で一貫性のない状態を残す場合があります。

リスクを軽減するには、 DDLトランザクションを最小限に抑え、単一のトランザクションで複数のDDL変更を組み合わせないようにします。実際のクロスロケーションのレイテンシーをシミュレートするステージング環境でDDLタイミングをテストします。メンテナンス時間帯にDDLをスケジュールします。

VACUUMとANALYZEの実行#

VACUUM およびANALYZE は、各ノードでローカルに実行され、レプリケートされません。 Autovacuumは各ノードで独立して動作するため、場所を超えて特別な調整は必要ありません。

PGD固有の懸念事項は、レプリケーションスロットの遅延です。オフラインまたは遅延ノードのスロットはcatalog_xmin を抑制し、VACUUMがカタログテーブルをクリーニングできず、元のノードに肥大化が蓄積します。スロットラグを定期的にチェックして、これを早期にキャッチします。

SELECT target_name, state, replay_lag_bytes, replay_lag_size, xmin, catalog_xmin
FROM bdr.node_slots
ORDER BY replay_lag_bytes DESC;

書き込みリーダーシップの管理#

地理的分散クラスターでは、ノードの障害または計画的な操作が原因で、書き込みリーダーシップが場所間を移動する場合があります。レイテンシーに合わせてフェールオーバー検出を構成し、ノードをオフラインにする前にクォーラムを維持し、計画的なスイッチオーバーを使用して書き込みリーダーシップを安全に転送します。

フェイルオーバーの処理#

書き込みリーダーの障害が発生すると、PGDはTCPキープアライブと接続タイムアウトを介してそれを検出し、Raftコンセンサスを介して新しい書き込みリーダーを選択します。クロスロケーションのレイテンシーと許容可能なフェイルオーバー時間と一致するように次のパラメーターを調整します。

  • bdr.global_keepalives_idle 、bdr.global_keepalives_interval 、およびbdr.global_keepalives_count は、障害が発生した接続が検出される速さを制御します。

  • bdr.global_connection_timeout は、接続を確立するときに待機する最大時間を設定します。高遅延の展開では、この値を小さくして、完全なTCPタイムアウトを待たずに障害をより迅速に検出します。

  • bdr.raft_global_election_timeout は、新しい書き込みリーダーがトップレベルグループで選択されるまでの時間を制御します。 bdr.raft_group_election_timeout は、ロケーションごとのサブグループ選択に適用されます。予想されるクロスロケーション遅延がネットワークジッターからの誤選択を引き起こしている場合、これらの値を増やします。

クォーラムの維持#

ノードをオフラインにする前に、クラスターがクォーラム投票ノードのマジョリティを維持していることを確認します。クォーラムがないと、新しい書き込みリーダーは選択されず、クラスターは読み取り専用状態になり、手動介入が必要です。続行する前に、現在の投票ノードの数を確認してください。

SELECT nvoting_nodes, is_voting FROM bdr.stat_raft_state;

残りの投票ノードの数がマジョリティを下回る場合、ノードをフェンスまたは停止しないでください。 2つの場所の展開では、3番目の場所の監視ノードは、1つの場所に障害が発生した場合にクォーラムを維持するために必要な追加の投票を提供します。詳細は、 ノード分散の計画 を参照してください。

計画的なスイッチオーバーの実行#

計画的なスイッチオーバーの前に、ターゲットノードが正常であり、追い付いていることを確認します。現在のリーダーでアクティブな長時間実行トランザクションがないことを確認し、可能な場合はトラフィックの少ない時間帯にスイッチオーバーを実行します。

  1. ターゲットノードのレプリケーションスロットがアクティブでストリーミングで、遅延がほぼゼロであることを確認します。

SELECT target_name, active, state, replay_lag_bytes, replay_lag_size
FROM bdr.node_slots
WHERE target_name = <target_node_name>;

スロットには、ゼロに近いactive = true 、state = 'streaming' 、およびreplay_lag_bytes が表示されるはずです。状態がcatchup またはdisconnected である場合、または遅延が高い場合、続行する前に待機します。

  1. スイッチオーバーを開始します。

SELECT bdr.routing_leadership_transfer(
    node_group_name := <group_name>,
    leader_name := <target_node_name>
);
  1. クラスターが正常な状態であることを確認します。

  2. 新しい書き込みリーダーが選択されたことを確認します。

SELECT node_group_name, write_lead
FROM bdr.node_group_routing_summary;
  1. プロキシルーティングが新しいリーダーに更新されたことを確認します。

SELECT node_group_name, write_lead_name, previous_write_lead_name
FROM bdr.stat_routing_state;
  1. 新しいリーダーから他のノードへのレプリケーションが低い遅延でストリーミングされていることを確認します。

SELECT target_name, active, state, replay_lag_bytes, replay_lag_size
FROM bdr.node_slots
WHERE origin_name = <new_leader_node_name>;

すべてのスロットで、ゼロに近いstate = 'streaming' およびreplay_lag_bytes が表示されるはずです。

ノードのメンテナンスの実行#

ローリング操作の場所を認識した順序に従い、ノードをオフラインにする前にフェンスします。

ロケーションをまたいだローリングオペレーション#

複数のノードに影響を与えるアップグレードまたはメンテナンスを実行する場合、次の順序に従って、クロスロケーションフェイルオーバーを最小限に抑え、できるだけ長く書き込みをローカルに保ちます。この順序は、各場所に独自の書き込みリーダーがあるローカルルーティングを想定しています。グローバルルーティングでは、クラスター全体に単一の書き込みリーダーがあるため、手順2をスキップして、最後にグローバル書き込みリーダーを処理します。

  1. セカンダリロケーションの非リーダーノードから開始します。

  2. セカンダリの場所の書き込みリーダーに移動しますこれにより、そのロケーション内でローカルフェイルオーバーが発生します。グローバルルーティングを使用する場合、手順2をスキップします。

  3. プライマリロケーションの非リーダーノードに進みます。

  4. プライマリ書き込みリーダーを最後に処理します。プライマリ書き込みリーダーのダウンは、クロスロケーションフェイルオーバーを発生させる可能性が最も高い操作です。

フェンシングノード#

フェンシングは、クラスターから削除せずにノードを書き込みリーダー資格から削除します。ノードの再起動が必要なメンテナンスの前、アップグレードの前、およびノードの状態に疑問がある場合に、フェンシングを使用します。

ノードをフェンスするには

SELECT bdr.alter_node_option(
    node_name := <node_name>,
    config_key := route_fence,
    config_value := true
);

フェンスされたノードはクォーラムに参加し、レプリケーションの受信を継続するため、クラスターのコンセンサスを維持する能力に影響はありません。ただし、複数のノードを同時にフェンシングすると、可用性が低下する可能性があります。メンテナンス完了後は常にアンフェンス。

フェンスを解除するには

SELECT bdr.alter_node_option(
    node_name := <node_name>,
    config_key := route_fence,
    config_value := false
);

クラスターの監視とインシデントへの対応#

操作の一部として、レプリケーションスロットの状態と競合率を定期的に確認します。以下のビューを使用して、インシデントが発生した場合の影響を評価し、復旧を確認します。

ネットワークパーティションの処理#

場所がパーティション化されると、クォーラムを保持する側が動作を継続します。クォーラムのない側は読み取り専用になります。分離された側のレプリケーションスロットは一時停止し、パーティションの期間中に遅延が増加します。

パーティションが修復したら、操作を再開する前に復旧を確認します。

  1. bdr.node_slots のラグメトリックを使用してキャッチアップの進行状況を監視し、すべてのスロットがstreaming に戻るまで待機します。

  2. パーティションウィンドウの競合率を確認します。 競合のモニタリング を参照してください。

競合のモニタリング#

ジオレプリケーションでは、同じ行が異なる場所で同時に更新される可能性があるため、競合の可能性が増加します。デフォルトでは、 PGDはlast-update-winsを使用して競合を解決します。タイムスタンプベースのリゾルバーは、ノード間のクロック同期に依存しています。すべてのノードでNTPまたはchronydを実行することにより、クロックスキューを最小限に抑えます。

bdr.conflict_history_summary を定期的にチェックして、競合率の高いテーブルがないかどうかを確認します。

SELECT nspname, relname, conflict_type, count(*)
FROM bdr.conflict_history_summary
GROUP BY nspname, relname, conflict_type
ORDER BY count(*) DESC;

特定のテーブルでの高い競合率が持続する場合は、アプリケーションチームと再検討する価値があるアクセスパターンを示しています。永続的な競合は通常、デザインの問題です。ロケーションベースのデータの分割、追加専用パターン、またはCRDTデータ型への切り替えは、競合解決を調整するよりも長期的に効果的です。

競合リゾルバーの構成#

アクセスパターンの変更が現実的でなく、last-update-winsが特定のテーブルに対して誤った結果を生成する場合、 bdr.alter_node_set_conflict_resolver() を使用してカスタムリゾルバーを構成します。使用可能なストラテジーはupdate_if_newer デフォルト、skip 、およびerror です。ファンクション呼び出しはレプリケートされないため、クラスター内の各ノードで実行します。最初にSELECT node_name FROM bdr.node_summary を使用してノード名を確認します。

SELECT bdr.alter_node_set_conflict_resolver(
    node_name         => node1,
    conflict_type     => update_update,
    conflict_resolver => error
);

すべての競合タイプにわたって現在のリゾルバー構成を確認するには

SELECT * FROM bdr.node_conflict_resolvers;

競合タイプとリゾルバーの完全なリストについては、 欠落列の競合の解決 を参照してください。