レプリケーションを立てて昇格させる
目標
プライマリサーバーとスタンバイサーバーを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で上書きするため、デフォルトのパスが消えるからです)。
ステップ
- プライマリサーバーをレプリケーション可能にする
- レプリケーション用アカウントとスロット
- ベースバックアップ →
/var/lib/postgresql/standby - スタンバイサーバーを5433で起動
- レプリケーションの確認 →
/root/db/05-repl.txt - 読み取り専用の確認 →
/root/db/06-readonly.txt - プロモート
- タイムラインの比較 →
/root/db/08-timeline.txt
参考
- エラーが出たら、
/var/log/postgresql.log(プライマリ)と/var/log/labhub/standby.log(スタンバイ)を見ます。 pg_stat_replicationはプライマリサーバーでのみ表示されます。スタンバイサーバーで見て空なのは正常です。
プライマリサーバーをレプリケーション可能にする
プライマリサーバーをレプリケーション可能にしてください。
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で分岐した地点まで巻き戻す必要があります。