2 台で非同期 HA を構築
まず最初に、2 台のホストを設定し、非同期レプリケーションを用いた構成をしてみましょう。

|
図2:非同期 2 台の構成例(クリックで拡大) |
構成は上記のようになります。今回は説明を分かりやすくするためにホスト名で記述していますが、実環境では、DNS が不調になることも考えられますので、IP アドレスで指定した方が良いでしょう。
まずは動作するところまで一気に構築をしてから、個々の設定については後で説明して行こうと思います。最初に、各ホストで共通の設定を行います。
/etc/keepalived/keepalived.conf を以下のように設定します。
14 | 192.168.12.23/24 dev eth0 |
16 | notify "/var/lib/pgsql/pgdata/notify" |
前回までの環境を流用するならば、使用するポートがかぶってしまうので、前回動かしていたインスタンスを止めておきます。
1 | [root@node1 ~]# su - postgres |
2 | -bash-4.1$ export PATH=/usr/pgsql-9.1/bin/:$PATH |
3 | -bash-4.1$ pg_ctl -D ~/pgdata-prim/ status && pg_ctl -D ~/pgdata-prim/ stop -m fast |
5 | -bash-4.1$ pg_ctl -D ~/pgdata-stby/ status && pg_ctl -D ~/pgdata-stby/ stop -m fast |
他ホストから RSH でログインするための ~/.rhost と、psql クライアントで VIP に対してデータベース接続をするための ~/.pgpass を設定します。
1 | -bash-4.1$ echo node1 postgres > ~/.rhosts |
2 | -bash-4.1$ echo node2 postgres >> ~/.rhosts |
3 | -bash-4.1$ echo spare postgres >> ~/.rhosts |
4 | -bash-4.1$ chmod 0600 ~/.rhosts |
5 | -bash-4.1$ echo vip:5432:*:reprole:reppass > ~/.pgpass |
6 | -bash-4.1$ echo vip:5432:postgres:postgres:postgres >> ~/.pgpass |
7 | -bash-4.1$ chmod 0600 ~/.pgpass |
以上が各ホストに共通の設定となり、ここから先がプライマリの設定となります。データディレクトリ下のファイルは pg_basebackup でレプリケーション・ベースをコピーする際に同時にコピーされますので、可能な限りプライマリ上で前もって設定をし、後でそれらをスタンバイ側へコピーするようにします。
プライマリ上にデータ領域を作成して仮起動し、レプリケーション用のユーザを作成します。
01 | -bash-4.1$ initdb -D ~/pgdata/ --encoding=UTF-8 --no-locale --pwprompt --auth=md5 |
03 | 新しいスーパーユーザのパスワードを入力してください: postgres |
06 | 成功しました。以下を使用してデータベースサーバを起動することができます。 |
08 | postmaster -D /var/lib/pgsql/pgdata |
10 | pg_ctl -D /var/lib/pgsql/pgdata -l logfile start |
11 | -bash-4.1$ pg_ctl -D ~/pgdata/ start |
13 | -bash-4.1$ psql -c "CREATE ROLE reprole REPLICATION LOGIN PASSWORD 'reppass'" |
~postgres/pgdata/postgresql.conf を設定します。内容は前回と同じですので、変更箇所のみ記載します。
01 | ## '*' を指定することで PostgreSQL はアドレス 0.0.0.0 に対して listen を |
02 | ## します。すると、後で付与された VIP 上でも listen することができます。 |
06 | wal_level = hot_standby |
08 | wal_keep_segments = 1000 |
09 | synchronous_standby_names = '' |
~postgres/pgdata/pg_hba.conf に以下を追加します。今回はネットワークごしでのアクセスが必要ですので、ネットワークアドレス (ここでは 192.168.0.0/16) を指定します。
1 | host replication reprole 192.168.0.0/16 md5 |
2 | host postgres reprole 192.168.0.0/16 md5 |
3 | host postgres postgres 192.168.0.0/16 md5 |
スタンバイに降格した際に用いる recovery.conf のひな形として、~postgres/pgdata/recovery.conf.in を作成しておきます。実際には、"application_name" の値をホスト名 ("node1" や "node2" といった名前) に置換して使用されます。
2 | primary_conninfo = 'host=vip user=reprole password=reppass application_name=@hostname@' |
3 | recovery_target_timeline = 'latest' |
4 | restore_command = 'rcp vip:/var/lib/pgsql/pgdata/pg_xlog/%f "%p" 2> /dev/null' |
次に、Keepalived がマスターやバックアップに遷移する際に呼ばれるスクリプトファイルである ~postgres/pgdata/notify を設置します。
04 | pgdata=/var/lib/pgsql/pgdata/ |
07 | export PATH=$PATH:/usr/pgsql-9.1/bin/ |
08 | # -------------------------------------------------------------------- |
09 | # root で実行されていたら、DB ユーザに切り替えて再実行します |
12 | abspath=$(cd $(dirname $0); pwd)/$(basename $0) |
13 | exec su - $dbuser $abspath "$@" |
22 | # PostgreSQL が起動していなければ起動します |
23 | pg_ctl -D $pgdata status || pg_ctl -D $pgdata start |
24 | # スタンバイであれば、プライマリに昇格させます |
25 | if test -e $pgdata/recovery.conf |
27 | pg_ctl -D $pgdata promote |
28 | while ! psql -h $vhost -U $reprole $repdb -c "SELECT pg_switch_xlog()" |
32 | psql -h $vhost -U $reprole $repdb -c "CHECKPOINT" |
36 | # PostgreSQL を停止し、プライマリであればスタンバイに降格させます |
37 | if ! test -e $pgdata/recovery.conf && \ |
38 | psql -h $vhost -U $reprole $repdb -l |
40 | pg_ctl -D $pgdata status && pg_ctl -D $pgdata -m immediate stop |
41 | sed -e "s/@hostname@/$(hostname)/" < $pgdata/recovery.conf.in \ |
42 | > $pgdata/recovery.conf |
45 | pg_ctl -D $pgdata status || pg_ctl -D $pgdata start |
以上で設定は終わりですので、仮稼働させていた PostgreSQL を停止させます。
1 | -bash-4.1$ chmod 755 ~/pgdata/notify |
2 | -bash-4.1$ pg_ctl -D ~/pgdata/ stop -m fast |
root ユーザへ戻り、Keepalived を起動させます。Keepalived はまずバックアップで起動しますが、まだネットワーク上に自分自身しか Keepalived ホストが存在しないので、すぐにマスターに遷移します。そして上記の "notify" のスクリプトを経由して、PostgreSQL のインスタンスをプライマリとして起動させます。
2 | [root@node1 ~]# service keepalived start |
4 | [root@node1 ~]# chkconfig keepalived on |
以上が、プライマリの構築手順でした。次に、スタンバイの設定を行います。必要なファイル群はベースのコピーとしてプライマリから取得できるので、こちらの手順は簡単です。なお、フェイルオーバーの際に WAL の取りこぼしが発生して旧プライマリではレプリケーションが継続できなくなった場合には、スタンバイの再構築が必要です。これは、その際の手順でもあります。
1 | [root@node2 ~]# su - postgres |
2 | -bash-4.1$ export PATH=/usr/pgsql-9.1/bin/:$PATH |
3 | -bash-4.1$ rm -fr ~/pgdata/ |
4 | -bash-4.1$ pg_basebackup -x -h vip -U reprole -D ~/pgdata/ |
root ユーザへ戻り、keepalived を起動させます。設定が正しくなされていれば、"notify" のスクリプトを経由して、PostgreSQL のインスタンスが、こちらはスタンバイとして起動されるはずです。
2 | [root@node2 ~]# service keepalived start |
4 | [root@node2 ~]# chkconfig keepalived on |
以上です。下記のように、プライマリ上でレプリケーションの状態を確認し、プライマリの現在の WAL 位置とスタンバイの flush_location の位置が一致しているようであれば、試しにプライマリのホストの電源を、終了処理を経ずに落としてみましょう。
01 | -bash-4.1$ psql -h vip -x -c "SELECT * FROM pg_current_xlog_location()" |
02 | -[ RECORD 1 ]------------+---------- |
03 | pg_current_xlog_location | 0/40000B0 ← これと |
05 | -bash-4.1$ psql -h vip -x -c "SELECT * FROM pg_stat_replication" |
06 | -[ RECORD 1 ]----+------------------------------ |
10 | application_name | node2 |
11 | client_addr | 192.168.12.25 |
14 | backend_start | 2011-XX-XX 18:29:08.142613+09 |
16 | sent_location | 0/40000B0 |
17 | write_location | 0/40000B0 |
18 | flush_location | 0/40000B0 ← これが一致 |
19 | replay_location | 0/40000B0 |
その結果、Keepalived によって node2 がマスター (プライマリ) に昇格し、引き続き "vip" に対してデータベースへのアクセスができるはずです。その後 node1 を起動すれば、今度は node1 がバックアップ (スタンバイ) としてレプリケーションを受けることになります。
なお、HA クラスタ全体を停止させる際には、スタンバイ→プライマリの順に停止してください。