TT Lab
はじめる
学ぶ 学習パス コース

PostgreSQLのレプリケーションと昇格

レプリケーションを立てて昇格させる

TT Labで続きを見る

目標

プライマリサーバーとスタンバイサーバーを1つのPodの中で自分で立ち上げ、レプリケーションを接続し、プロモートまで行います。最後にタイムラインが分岐するのを目で確認します。

なぜ重要なのか

「HAを構築した」という言葉は、たいてい一度もフェイルオーバーをしたことがないという意味です。設定は合っているのに、いざプロモートしてみるとスタンバイサーバーが追いついていなかったり、プロモートはできたのにアプリケーションが古いアドレスを見ていたり、古いプライマリサーバーを再接続しようとしてデータを壊したりします。

このラボは、その一巡を先に体験します。

環境

このPodはpostgresアカウントで動きます(ラボのPodにはcapabilityがないため、suでユーザーを切り替えられません)。そのためsuやsudoを使わず、そのまま入力すれば動きます。

psql                      주 서버(5432)에 바로 붙습니다
psql -h 127.0.0.1 -p 5433 대기 서버

スタンバイサーバーには必ず-h 127.0.0.1を付けてください。この環境ではUnixソケットのディレクトリをホームの下へ移してあります(コンテナランタイムが/runをtmpfsで上書きするため、デフォルトのパスが消えるからです)。

ステップ

  1. プライマリサーバーをレプリケーション可能にする
  2. レプリケーション用アカウントとスロット
  3. ベースバックアップ → /var/lib/postgresql/standby
  4. スタンバイサーバーを5433で起動
  5. レプリケーションの確認 → /root/db/05-repl.txt
  6. 読み取り専用の確認 → /root/db/06-readonly.txt
  7. プロモート
  8. タイムラインの比較 → /root/db/08-timeline.txt

参考

プライマリサーバーをレプリケーション可能にする

プライマリサーバーをレプリケーション可能にしてください。

wal_level、max_wal_senders、max_replication_slots、hot_standbyをalter system setで変更して再起動します。再起動はpg_ctl -D /var/lib/postgresql/data -w -t 40 restart -l /var/log/postgresql.logで行います。show wal_levelの結果がreplicaになっている必要があります。

レプリケーション用アカウントとスロット

レプリケーション用アカウントとスロットを作成してください。

create role rep with replication login password 'rep'でアカウントを作成し、select pg_create_physical_replication_slot('s1')でスロットを作成します。スロットがないと、スタンバイサーバーが少し切断されてから戻ってきたときに必要なWALがすでに消えていて、レプリケーションが壊れます。

ベースバックアップ

ベースバックアップ → /var/lib/postgresql/standby

PGPASSWORD=rep pg_basebackup -h 127.0.0.1 -U rep -D /var/lib/postgresql/standby -X stream -S s1 -Rを実行します。-Rがstandby.signalとprimary_conninfoを自動で作ってくれます。このファイル1つが「あなたはスタンバイサーバーです」という目印です。

スタンバイサーバーを5433で起動する

スタンバイサーバーを5433で起動してください。

echo "port=5433" >> /var/lib/postgresql/standby/postgresql.auto.confを実行したあとで、pg_ctl -D /var/lib/postgresql/standby -l /var/log/labhub/standby.log -w -t 40 startを実行します。確認は、psql -h 127.0.0.1 -p 5433 -tAc "select pg_is_in_recovery()"の結果がtである必要があります。\n\n必ず-h 127.0.0.1を付けてください。この環境はUnixソケットのディレクトリを移してあるため、ポートだけを変えるとソケットのパスが見つかりません。

本当にレプリケーションされているか確認する

レプリケーションの確認 → /root/db/05-repl.txt

プライマリサーバーでcreate table if not exists ha(id int)とinsert into ha values (42)を実行し、2秒後にスタンバイサーバーで同じ行が見えるか確認します。そしてselect state, replay_lag from pg_stat_replicationの結果を/root/db/05-repl.txtに保存してください。stateがstreamingである必要があります。

スタンバイサーバーがなぜ書き込みを拒否するのか確認する

読み取り専用の確認 → /root/db/06-readonly.txt

スタンバイサーバーでinsert into ha values (1)を実行し、エラーメッセージをそのまま/root/db/06-readonly.txtに保存してください。スタンバイサーバーは自分でWALを作れないため、書き込みを受け付けられません。設定ではなく構造の問題です。

プロモートする

プロモートしてください。

pg_ctl -D /var/lib/postgresql/standby promoteでプロモートします。pg_is_in_recovery()がfに変わり、書き込みが可能になります。プロモートしたあとで、insertを1回実行してみてください。

タイムラインが分岐するのを確認する

タイムラインの比較 → /root/db/08-timeline.txt

プロモートすると、新しいサーバーはタイムライン2に分岐します。2台のサーバーのWALファイル名を比べて、/root/db/08-timeline.txtに2行で書いてください:\npsql -h 127.0.0.1 -p 5432 -tAc "select pg_walfile_name(pg_current_wal_lsn())"と、5433のものです。ファイル名の先頭8桁がタイムラインです(00000001 / 00000002)。\n\nこれが、古いプライマリサーバーをそのまま再接続できない理由です。2台のサーバーが同じ地点から異なる履歴を書き始めたからです。再接続するには、pg_rewindで分岐した地点まで巻き戻す必要があります。