geek.conf.2

あるエンジニアの備忘録

PostgreSQL 9.1 Streaming ReplicationとPgpool-II 3.1を用いた自動フェールオーバ ソリューション

こんばんわ。早く今年が終わることを祈る僕です。

今回はPostgreSQL 9.1 Streaming Replication(SR)を実装してかつPgpool-II 3.1にて障害時に自動で待機系へフェールオーバさせるソリューション構築を書きます。

OSはRHELをイメージしてもらえれば。

PostgreSQL 9.1 SRを構成するノードはデータベースを提供するノードとそのデータベースのレプリケーション先のノードに分別されます。前者をマスターノード、後者をスレーブノードと言います。

前提としてマスター/スレーブノードでPostgreSQL 9.1はインストール済み。
マスターノードでデータベースも構築済み。とします。

※ホスト名はMasNod:マスターノード、SlaNod:スレーブノードとします。
※POSTGRES_HOME=PostgreSQLインストールディレクトリ
※PG_DATA=PostgreSQLデータベースディレクトリ

1.ユーザ作成と接続設定
レプリケーション用ユーザreplを作成してREPLICATION権限を付与します。
データベースが構築されているマスターノードでやれ。
[postgres@MasNod ~]$ psql -p 5432 -d postgres

=# CREATE ROLE repl LOGIN REPLICATION PASSWORD 'xxxxxx';

次にレプリケーション用の仮想データベースreplicationに接続許可する設定を行います。
マスターノードやれ。
[postgres@MasNod ~]$ vi $PG_DATA/pg_hba.conf


# IPv4 local connections:
host replication repl 192.168.10.2/32 trust

※アドレスはスレーブノードのもの。認証方式はtrustでもmd5でもお好みで。

2.マスターノードのSR設定
WALアーカイブログモードを使用します。普通使用します。そのようにディスクも確保しましょう。
マスターノードで。
[postgres@MasNod ~]$ vi $PG_DATA/postgresql.conf


wal_level = hot_standby
max_wal_sender = 2
archive_mode = on
archive_command = 'cp "%p" $POSTGRES_HOME/archive/"%f"'
wal_keep_segments = 16
synchronous_standby_names = 'SlaNod'

max_wal_senderはスレーブノード数+1としておく。
synchronous_standby_namesはレプリケーションを同期モードとするときに指定すべし。
これ以外はStreaming Replication Parameters Settingを参照されたし。


3.ベースバックアップのオンライン取得を開始
マスターノードのデータベースのベースバックアップのオンライン取得を開始する。
スレーブノードで
[postgres@SlaNod ~]$ pg_basebackup -h MasNod -p 5432 -U repl -D $PG_DATA --xlog --checkpoint=fast --progress

これ一発でスレーブノードのPG_DATAにマスターノードのPG_DATAの中身がコピーされます。まぁ便利。
PostgreSQL 9.0時代ではマスターノードでSELECT pg_start_backup('GEEK_SR');→scpかなんかでスレーブノードにマスターノードのPG_DATAの中身をコピー→マスターノードでSELECT pg_stop_backup(GEEK_SR);とやっていたのよ若者よ。

4.スレーブノードのSR設定
スレーブノードで
[postgres@SlaNod ~]$ vi $PG_DATA/postgresql.conf


wal_level = hot_standby

[postgres@SlaNod ~]$ cp -p $POSTGRES_HOME/share/recovery.conf.sample $PG_DATA/recovery.conf
[postgres@SlaNod ~]$ vi $PG_DATA/recovery.conf


standby_mode 'on'
primary_conninfo 'host=MasNod port=5432 user=postgres application_name=SlaNod'
restore_command 'scp MasNod:$POSTGRES_HOME/archive/%f %p'
trigger_file '$PG_DATA/trigger'

primary_conninfo内のapplication_nameはマスターノードのpostgres.conf内のsynchronous_standby_namesで指定した値を書け。これらはレプリケーションを同期モードで動作させるときに必要。

trigger_fileはスレーブノードの指定した場所にtriggerというファイル名のファイルがあればスレーブノードはレプリケーションを止めてデータベース更新可能となる。
または
[postgres@SlaNod ~]$ pg_ctl promote -D $PG_DATA
でスレーブノードを昇格させても同様にデータベース更新可能と出来る。
restore_commandはお好みで。

5.スレーブノードのPostgreSQL起動

6.レプリケーション確認
PostgreSQLのログからレプリケーションが出来ているか確認します。
マスター/スレーブノードで以下のメッセージが出ていればレプリケーション出来てます。
マスターノードで
LOG: replication connection authorized: user=postgres host=SlaNod port=5432
スレーブノードで
LOG: streaming replication successfully connected to primary

またはクエリで確認も出来ます。
マスターノードで
[postgres@MasNod ~]$ psql -p 5432 -d postgres
=# SELECT * FROM pg_stat_replication;
state列の値は以下のよう変化します。
startup:接続の確立中
backup:pg_basebackup中
catchup:過去のデータを更新中
streaming:リアルタイムデータを更新中

スレーブノードで
[postgres@SlaNod ~]$ psql -p 5432 -d postgres
=# SELECT pg_last_xact_replay_timestamp();
最後にデータがレプリケーションによって更新された時刻が表示されます。

ちなみにスレーブノードのデータベースを更新しようとすると以下のエラーが出て更新できない。
ERROR: cannot execute INSERT in a read-only transaction

7.自動フェールオーバソリューションの構築
ここまででPostgreSQL SRは構築できた。次にマスターノードの障害時にPostgreSQLデータベース利用者に意識させずにスレーブノードへ自動でフェールオーバさせるソリューションを構築する。
方法はslony-Iでフェールオーバ・・・からのぉぉ・・フェールバックしよっかで紹介したのと同様、Pgpool-IIのfailover_commandを使用します。
まぁPostgreSQLデータベースへの接続にはプロキシであるPgpool-II経由であることが前提ですが。

まずはPgpool-IIをPostgreSQL SR仕様にいたします。
※PGPOOL2_HOME=Pgpool-IIインストールディレクトリ
[postgres@AppNod ~]$ vi $PGPOOL2_HOME/etc/pgpool.conf


replication_mode false
master_slave_mode true
master_slave_sub_mode 'stream'
failover_command '$PGPOOL2_HOME/bin/failover.sh %d %H $PG_DATA/trigger'

以下に$PGPOOL2_HOME/bin/failover.shの中身をさらします。

------------------------------failover.sh--------------------------------------
#! /bin/bash
# Failover command for streming replication.
# This script assumes that DB node 0 is primary, and 1 is standby.
#
# If standby goes down, does nothing(do pgsql9 stop only). If primary goes down, create a
# trigger file so that standby take over primary node.
#
# Arguments: $1: failed node id. $2: new master hostname. $3: path to
# trigger file.

failed_node=$1
new_master=$2
trigger_file=$3

# Do nothing if standby goes down.
if [ $failed_node = 1 ]; then
slogin -i ~/.ssh/nopass-dsa SlaNod pg_ctl -D $PG_DATA -m immediate stop
exit 0;
fi

# Create trigger file.
slogin -i ~/.ssh/nopass-dsa MasNod pg_ctl -D /usr/local/pgsql/data -m immediate stop
slogin -i ~/.ssh/nopass-dsa $new_master /bin/touch $trigger_file

exit 0;
------------------------------------------------------------------------------
環境変数宣言はお任せします。
このシェルはPgpool-IIがインストールされたホストで実行されますが、そのPgpool-IIホストからPostgreSQLホスト(=マスター/スレーブノード)へはパスワードなしでログインできるよう設定しておくことが、使用の前提条件です。
今回はtrrigerファイルを利用していますが、pg_ctl promoteのほうが直接データベースプロセスに働きかけるためフェールオーバも早いようです。
フェールオーバするとスレーブノード内のrecovery.confはrecovery.doneになります。
フェールバックは手動となりますが、フェールバックの時のためにマスター/スレーブノードの両ノードのpostgres.confとpg_hba.confとrecovery.confは$PG_DATA外にバックアップを取っておくことをお勧めします。

じゃこのへんで。