PostgreSQL 論理レプリケーション (パブリケーション / サブスクリプション)
PostgreSQLレベル: 上級所要時間: 45〜90 分 (+ 初期コピーの時間)2 つの PostgreSQL クラスタ間のテーブル単位の論理レプリケーションです: wal_level=logical、レプリカアイデンティティの確認、パブリケーションとサブスクリプション、初期同期、監視、コンフリクトの対処、シーケンスの手動同期。バージョン間の移行 (メジャーアップグレード、サーバー移設) のために、ダウンタイムを数秒に抑える最終切り替え (cutover) の手順も含みます。
論理レプリケーションは HA やバックアップの手段ではありません。クラスタ全体の完全なコピーと failover には ストリーミングレプリケーション または Patroni、バックアップには pgBackRest を使用します。同じサーバー上でのインプレースのメジャーバージョンアップグレード (pg_upgrade) は pg-major-upgrade で扱います。
構成: 2 台のサーバー: パブリッシャー (publisher) + サブスクライバー (subscriber)。パブリッシャーは単一サーバー、ストリーミングレプリケーション、Patroni クラスタのいずれでもよい
シナリオ
- 継続的なレプリケーション (レポート、連携、部分コピー) — 選択したテーブルを継続的に別のクラスタへ流します (レポート用サーバー、データウェアハウスへの供給、サービス間連携)。サブスクライバーは書き込み可能なままです。
- 移行: 新サーバー / 新メジャーバージョン + 最終切り替え (cutover) — 数秒のダウンタイムで新サーバーまたは新メジャーバージョンへ移行します: 初期コピーと継続的な同期の後、短時間書き込みを止めて最終切り替え (cutover) を行います。
開始前の確認
- パブリッシャーで PostgreSQL … が稼働しており、… データベースがあります。
- Patroni クラスタ … が正常で、… が現在 Leader です。replica では hot_standby_feedback = on です (pg-patroni のデフォルト)。
- Standby … が physical レプリケーションスロットで primary に接続しています (primary_slot_name = …、pg-streaming のスロットオプション)。このスロットがないとスロット同期は動作しません。
- サブスクライバーに PostgreSQL … が pg-install でインストールされて稼働しており、パブリッシャーにある拡張機能 (PostGIS など) の … 版がインストールされています。
- サブスクライバーからパブリッシャーの …HAProxy/VIP アドレス (…:…)…… ポート…に到達できます (ファイアウォール / セキュリティグループ)。
- パブリッシャーの wal_level は現在どの値ですか。logical でない場合、変更には再起動が必要です。メンテナンスウィンドウを計画してください。
- 公開するテーブルに primary key または適切な unique index があります。ない場合、パブリッシャーで UPDATE/DELETE がエラーになります。一覧に出たテーブルに PK を追加するか、レプリカアイデンティティを定義してください (後述のステップ)。
- 論理レプリケーションは DDL を転送しません (CREATE/ALTER TABLE)。シーケンスの値やラージオブジェクトも転送しません。レプリケーション期間中のスキーマ変更は、まずサブスクライバー、次にパブリッシャーへ手動で適用することをチームに周知済みです。
- パブリッシャーに WAL 用のディスク余裕があります。サブスクライバーが停止するとスロットが WAL を溜め込みます (上限: … GB)。
ガイドのフェーズ
- パブリッシャーの準備 — パブリッシャーが …Leader…primary… であることを確認する · 論理レプリケーションの設定を書き込む · 論理レプリケーションの設定を Patroni に書き込む · パブリッシャーを再起動する · Patroni メンバーを再起動する · レプリケーションユーザーを作成する …
- レプリカアイデンティティ — PK のないテーブルを一覧表示する · PK のないテーブルにレプリカアイデンティティを定義する
- パブリケーション — パブリケーションを作成する
- サブスクライバーの準備 — サブスクライバーの worker 設定を書き込む · サブスクライバーを再起動する · パブリッシャーのパスワードを .pgpass に書き込む · データベースとスキーマを作成する · ロールと権限を移す
- サブスクリプションと初期同期 — サブスクリプションを作成する · 初期同期の完了を待つ · データ件数を比較する · ライブ変更テスト
- failover 時のスロットの保持 — スロットを Patroni で永続 (permanent) として定義する · スロットが replica に表示されることを確認する · Primary: 同期対象の standby スロットを定義する · Standby: スロット同期を有効にする · failover 後にサブスクリプションを新しい primary に向ける · failover 後にサブスクリプションを再作成する
- 監視 — サブスクリプションの状態 (サブスクライバー) · スロットの遅延 (パブリッシャー)
- コンフリクト (conflict) の対処 — エラーを特定する · サブスクライバーでコンフリクトした行を修正する · コンフリクトしたトランザクションをスキップする
- シーケンスの同期 — シーケンスの値をパブリッシャーからサブスクライバーに移す
- 最終切り替え (cutover) — パブリッシャーへの書き込みを停止する · 最後の変更が転送されたことを確認する · シーケンスを最後にもう一度同期する · サブスクリプションを削除する · 統計情報を収集する · アプリケーションをサブスクライバーに向ける …
- 保守作業 — 新しいテーブルの追加 · スキーマ変更 (ALTER TABLE) · サブスクリプションの削除 (パブリッシャーに到達できない場合)