PostgreSQL-9.2のレプリケーション構成における可用性の確認

■基本構成とシナリオ


master -----> slave1
| sync
|
+--------> slave2
potencial

slave1がダウンするとslave2は自動的に同期モードになるように設定。
以前の記事ではレプリケーションの設定でslave2を非同期(async)に設定しました。slave2をpotencialにするにはマスタのpostgresql.confのsynchronous_standby_namesにslave2を追加。


synchronous_standby_names='slave1,slave2'


select application_name, state, sync_state from pg_stat_replication;
application_name | state | sync_state
------------------+-----------+------------
slave1 | streaming | sync
slave2 | streaming | potencial

システム構成が上記構成であることを前提に、今回は以下3つの障害シナリオに沿って、PostgreSQL9.2のレプリケーション構成時の可用性の確認とその運用についてみていきます。

1.slave1のノードダウン時はslave2が自動的に同期モードによる接続となること。
2.masterノードダウン後にslave1をマスタに昇格させ、新マスタslave1を停止させることなくslave2と接続可能であること。
3.障害から復旧した旧マスタが新マスタslave1に(slave1を停止させることなく)接続可能であること。

■テスト用のテーブルを準備
各ステップの途中に適当にデータを投入しリカバリの状態を確認するために適当なテーブルを準備

【例】


CREATE TABLE TEST_TBL (ID INTEGER PRIMARY KEY, COL1 VARCHAR(16));

■slave1をダウンさせてslave2が同期モードに昇格することを確認
(1)slave1のサーバでimmediateモードで疑似的にクラッシュした状態で停止させる。


pg_ctl stop -m immediate -D /var/lib/pgsql/9.2/data

(2)masterでレプリケーションの状態を確認


select application_name, state, sync_state from pg_stat_replication;
application_name | state | sync_state
------------------+-----------+------------
slave2 | streaming | sync

(3)masterサーバで事前に準備しておいたテーブルに適当なデータを投入しmasterとslave2に反映されることを確認

(4)slave1を起動しmasterでレプリケーションの状態を確認


select application_name, state, sync_state from pg_stat_replication;
application_name | state | sync_state
------------------+-----------+------------
slave1 | streaming | sync
slave2 | streaming | potencial

(5)slave1で停止中に追加されたデータが反映されていることを確認

■masterをダウンさせslave1をマスタサーバへ昇格させる
これ以降の作業を行う前に念のため全ノードのデータベースを停止し、/var/lib/pgsql/9.2/dataディレクトリのバックアップを取得することをお勧めします。
なお、今回はpg_basebackupを利用した方法でリカバリを行います。

(1)masterでレプリケーションの状態を確認


select application_name, state, sync_state from pg_stat_replication;
application_name | state | sync_state
------------------+-----------+------------
slave1 | streaming | sync
slave2 | streaming | potential

(2)masterノードを停止し、slave1をマスタに昇格
masterサーバで下記コマンドにより擬似的にクラッシュさせる


pg_ctl stop -m immediate -D /var/lib/pgsql/9.2/data

(3)slave1のサーバをマスタに昇格(slave1のサーバで実施)


pg_ctl -D /var/lib/pgsql/9.2/data promote

■pg_basebackupによりslave2のリカバリを行い新マスタslave1に同期モードで接続する
事前にpostgresql.conf、pg_hba.conf、recovery.confは退避させておく。

(1)slave2のデータベースを停止

(2)slave2の/var/lib/pgsql/9.2/dataディレクトリの削除

(3)pg_basebackupよりslave1(新マスタ)のベースバックアップを取得し/var/lib/pgsql/9.2/dataに展開


pg_basebackup -h [slave1サーバ] -p [ポート] -U [レプリケーションユーザ] -D /var/lib/pgsql/9.2/data --xlog --progress --verbose

(4)退避させておいたpostgresql.conf、pg_hba.conf、recovery.confをdataディレクトリに戻し、recovery.confのprimary_conninfoのhostをslave1に変更後slave2のデータベースを再起動

(5)slave1でレプリケーションの状態を確認する


select application_name, state, sync_state from pg_stat_replication;
application_name | state | sync_state
------------------+-----------+------------
slave2 | streaming | async

(6)slave1のpostgresql.confのsynchronous_standby_namesにslave2を追加し設定の再読み込みを行う


pg_ctl -D /var/lib/pgsql/9.2/data reload

(7)slave1とslave2が同期モードでレプリケーションされていることを確認


select application_name, state, sync_state from pg_stat_replication;
application_name | state | sync_state
------------------+-----------+------------
slave2 | streaming | sync

(8)slave1のテーブルに適当なデータを投入してslave2に反映されることを確認

■ダウンした元マスタを復旧させ新マスタslave1に接続する
旧マスタのpostgresql.conf、pg_hba.confは事前に退避させておく。recovery.confはダウンするまではマスタであったため存在しない。

(1)masterの/var/lib/pgsql/9.2/dataディレクトリの削除

(2)pg_basebackupよりslave1(新マスタ)のベースバックアップを取得し/var/lib/pgsql/9.2/dataに展開


pg_basebackup -h [slave1サーバ] -p [ポート] -U [レプリケーションユーザ] -D /var/lib/pgsql/9.2/data --xlog --progress --verbose

(3)退避させたpostgresql.confとpg_hba.confを/var/lib/pgsql/9.2/data配下に戻す

(4)postgresql.confのsynchronous_standby_namesをコメントアウト、hot_standby = onとなっていない場合は合わせて設定を行う

(5)recovery.doneファイルをrecovery.confにリネームし、primary_conninfoのhostをslave1に、application_nameをmasterに設定した後、masterを再起動

(6)新マスタslave1でレプリケーションの状態を確認する


select application_name, state, sync_state from pg_stat_replication;
application_name | state | sync_state
------------------+-----------+------------
slave2 | streaming | sync
master | streaming | async

(7)slave1のpostgresql.confのsynchronous_standby_namesを以下のように設定し、再読み込みを行う。


synchronous_standby_names = 'master,slave2'


pg_ctl -D /var/lib/pgsql/9.2/data reload

(8)新マスタslave1で再度レプリケーションの状態を確認


select application_name, state, sync_priority, sync_state from pg_stat_replication;
application_name | state | sync_priority | sync_state
------------------+-----------+---------------+------------
slave2 | streaming | 2 | potential
master | streaming | 1 | sync

後から復旧してきた旧マスタが優先順位が上がり同期モードになり、slave2はpotencialに優先度が下がっています。

これは、synchronous_standby_namesに定義した順番が関係しています。

もし、synchronous_standby_names = 'slave2,master'と定義するとレプリケーションの状態は次のようになります。


select application_name, state, sync_priority, sync_state from pg_stat_replication;
application_name | state | sync_priority | sync_state
------------------+-----------+---------------+------------
slave2 | streaming | 1 | sync
master | streaming | 2 | potential

(9)新マスタslave1で適当なデータを投入するとレプリケーションをしている全ノードにデータが反映されることを確認

■まとめ
3台構成でレプリケーションをさせた状態で、各シナリオを検証しました。当たり前ですが全ノードがダウンしない限り最低1台で運転が可能です。
実運用ではPacemaker+Heartbeat(or Corosync)+pgpool-IIあたりを利用した運用が一般的かと思いますが、今回は動作確認が主なのでそういったソフトウェアは利用していません。