同期レプリケーションへの変更
まずは、前回までの非同期レプリケーションの処理の流れの概要を見てみます。

|
図2:非同期での処理の流れ |
実行の順序を見ていただくと分かる通り、プライマリがローカルのディスクへ WAL を書き出し終えたところで、クライアントへはコミットの成功を返し、その後で、クライアントの操作とは全く非同期に、スタンバイ側への WAL レコードの転送とディスクへの書き出しを行います。
それに対して、同期レプリケーションの処理は以下のようになります。

|
図3:同期での処理の流れ |
プライマリのディスクに WAL を書き出したことを確認した後で、スタンバイへ WAL ログを送信します。そしてスタンバイも WAL をディスクへ書き出したことを確認できたら、ようやくクライアントへコミットの成功を返します。パフォーマンスと引き換えに、データの保護を優先した構成と言うことができます。
それでは、前回の非同期レプリケーションの構成を、そのまま同期に変更して行きましょう。~postgres/pgdata-prim/postgresql.conf を下記のように修正し、同期スタンバイになるノードの application_name を指定します。
1 | synchronous_standby_names = '' |
5 | synchronous_standby_names = 'stby' |
修正し終えたら、プライマリ、スタンバイ共に再起動します。
01 | -bash-4.1$ pg_ctl -D ~/pgdata-prim restart |
02 | サーバ停止処理の完了を待っています....完了 |
05 | -bash-4.1$ pg_ctl -D ~/pgdata-stby/ restart |
06 | サーバ停止処理の完了を待っています....完了 |
09 | -bash-4.1$ psql -x -p 5432 -c "SELECT * FROM pg_stat_replication" |
10 | -[ RECORD 1 ]----+------------------------------ |
14 | application_name | stby |
15 | client_addr | 127.0.0.1 |
18 | backend_start | 2011-XX-XX 16:58:58.420314+09 |
20 | sent_location | 0/3037000 |
21 | write_location | 0/3037000 |
22 | flush_location | 0/3037000 |
23 | replay_location | 0/3036FA8 |
sync_priority が "0" から "1" へ、sync_state が "async" から "sync" へと、同期でのレプリケーションを表す値に変わったのが分かるかと思います。試しに、同期スタンバイを停止させてからプライマリに書き込みを行うとどうなるかを見てみましょう。
1 | -bash-4.1$ pg_ctl -D ~/pgdata-stby/ stop |
4 | -bash-4.1$ psql -p 5432 -c "INSERT INTO members VALUES(128, 'Hoge')" # 戻らない… |
このように、スタンバイ側への書き込みが確認されるまで、プライマリへの変更は確定しません。別のコンソールからスタンバイ側のノードをスタートさせれば、上記のクエリは成功します。
メンテナンスなどのためにプライマリを単体で起動させたい場合には、一時的に synchronous_commit パラメータを "local" にすることで、スタンバイへの同期レプリケーションができなくても処理が返るようになります。
01 | -bash-4.1$ pg_ctl -D ~/pgdata-stby/ stop # スタンバイの停止 |
02 | サーバ停止処理の完了を待っています....完了 |
04 | -bash-4.1$ pg_ctl -D ~/pgdata-prim/ -o "-c synchronous_commit=local" restart |
05 | サーバ停止処理の完了を待っています....完了 |
08 | -bash-4.1$ psql -p 5432 -c "INSERT INTO members VALUES(256, 'Fuga')" # 戻る |
10 | -bash-4.1$ pg_ctl -D ~/pgdata-prim/ -o "-c synchronous_commit=on" restart |
11 | サーバ停止処理の完了を待っています....完了 |
14 | -bash-4.1$ psql -p 5432 -c "INSERT INTO members VALUES(512, 'Hare')" # 戻らない… |
最後に、プライマリノードを終了手続きを経ずに異常終了させ、それまでのスタンバイを新プライマリに昇格させてみます。その後で、旧プライマリを新スタンバイとして、pg_basebackup コマンドによる再構築なしに、recovery_target_timeline='latest' の設定を用いることで、新プライマリに再度接続させてみます。この際、~/pgdata-stby/pg_log/ ディレクトリに出力されているテキストログを見ながら作業をすると、昇格の流れが分かりやすいかと思います。
1 | -bash-4.1$ pg_ctl -D ~/pgdata-prim/ -m immediate stop |
4 | -bash-4.1$ pg_ctl -D ~/pgdata-stby/ promote |
旧プライマリを新スタンバイにするために、~postgres/pgdata-prim/recovery.conf を準備します。
2 | primary_conninfo = 'host=localhost port=5433 user=reprole password=reppass application_name=prim' |
3 | recovery_target_timeline = 'latest' |
4 | restore_command = 'cp /var/lib/pgsql/pgdata-stby/pg_xlog/%f "%p" 2> /dev/null' |
新スタンバイのサービスを起動します。
1 | -bash-4.1$ pg_ctl -D ~/pgdata-prim/ start |
レプリケーションが行われていることを確認します。
01 | -bash-4.1$ psql -p 5433 -c "INSERT INTO members VALUES(777, 'Foo')" |
03 | -bash-4.1$ psql -p 5433 -c "SELECT * FROM members WHERE id = 777" # 新プライマリ |
09 | -bash-4.1$ psql -p 5432 -c "SELECT * FROM members WHERE id = 777" # 新スタンバイ |
次回は、Keepalived の VRRP サービスを利用して、非同期(2 台構成)と同期(3 台構成)のそれぞれによる簡単な HA (High-Availability: 高可用性) システムの構成を行う予定です。
【関連リンク】
<サイト最終アクセス:2010.10>