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