2017年2月8日水曜日

pgpool-2のオンラインリカバリを試す

どうも、俺です。

pgpool-2でオンラインリカバリを試したのでその方法をメモ。
若干ややこしかった...。

【環境】
・postgresql v9.5.3
・pgpool-2 v3.5.4
・ノード1のあるサーバー 192.168.0.1
・ノード2のあるサーバー 192.168.0.2
・pgpool-2のあるサーバー 192.168.0.1
※PostgreSQLとpgpool-2はすでに稼働中とします。
※pgpool-2の公式HP参照


手順1) C言語関数インストール

各ノードのPostgreSQLデータベースに関数をインストールします。
すべてのノードのあるサーバーで以下を行います。

# su - postgres
% cd /path/to/pgpool-II-3.5.4/src/sql/pgpool-recovery
% make install
% psql -p ポート番号 -f pgpool-recovery.sql template1 


手順2) pgpool.confの設定

オンラインリカバリを行うための設定を追加します。

# vim /path/to/pgpool/etc/pgpool.conf

--- 以下pgpool.conf内容 ---

# PCPの設定
pcp_listen_addresses = '*'
pcp_port = 9898
pcp_socket_dir = '/tmp'

# リカバリを行うPostgreSQLのユーザとパスワード。
recovery_user = 'postgres'
recovery_password = 'postgres'
# オンラインリカバリを実行するスクリプト名。
recovery_1st_stage_command = 'recovery_1st_stage.sh'
recovery_2nd_stage_command = 'recovery_2nd_stage.sh'
# オンラインリカバリのタイムアウト秒数。
recovery_timeout = 120 
# リカバリ中にアイドル状態のクライアントを何秒で切断するか。0は無効。-1は即時切断。
client_idle_limit_in_recovery = 1 


手順3) postgresql.confの設定

archive_logを取るように設定します。
既に設定済みであれば不要です。

# vim /path/to/pgsql/data/postgresql.conf

--- 以下postgresql.confの内容 ---

archive_mode = on

# /usr/local/pgsql/data/archive というディレクトリ以下にarchive_logがコピーされる
archive_command = 'cp %p /usr/local/pgsql/data/archive/%f'


手順4) リカバリスクリプトの作成

・recovery_1st_stage.sh
・recovery_2st_stage.sh
・pgpool_remove_start
の3ファイルを作成します。

pgpoolレプリケーションモード | PostgreSQL関連情報のスクリプトを使わせて頂きました。ありがとうございます。

recovery_1st_stage.sh

#!/bin/sh

PSQL="/usr/local/pgsql/bin/psql"
PORT=5432
MASTER_BASEDIR=$1
RECOVERY_HOST=$2
RECOVERY_BASEDIR=$3

$PSQL -p $PORT -c "SELECT pg_start_backup('pgpool-recovery')" postgres

echo "restore_command = 'cp /usr/local/pgsql/data/archive/%f %p'" > $MASTER_BASEDIR/recovery.conf

ssh -l postgres -T $RECOVERY_HOST rm -rf $RECOVERY_BASEDIR.bk
ssh -l postgres -T $RECOVERY_HOST mv -f $RECOVERY_BASEDIR{,.bk}

rsync -az -e ssh -l postgres $MASTER_BASEDIR/ $RECOVERY_HOST:$RECOVERY_BASEDIR/

ssh -l postgres  -T $RECOVERY_HOST cp -f $RECOVERY_BASEDIR.bk/postgresql.conf $RECOVERY_BASEDIR
ssh -l postgres  -T $RECOVERY_HOST rm -f $RECOVERY_BASEDIR/postmaster.pid

rm -f $MASTER_BASEDIR/recovery.conf

$PSQL -p $PORT -c "SELECT pg_stop_backup()" postgres

recovery_2nd_stage.sh

#!/bin/sh

PSQL="/usr/local/pgsql/bin/psql"
PORT=5432
ARCHIVEDIR=/usr/local/pgsql/data/archive/
MASTER_BASEDIR=$1
RECOVERY_HOST=$2
RECOVERY_BASEDIR=$3

$PSQL -p $PORT -c 'SELECT pg_switch_xlog()' postgres

rsync -az -e ssh  -l postgres $ARCHIVEDIR $RECOVERY_HOST:$ARCHIVEDIR 

pgpool_remove_start

#! /bin/sh

PGCTL=/usr/local/pgsql/bin/pg_ctl
RECOVERY_HOST=$1
RECOVERY_BASEDIR=$2

ssh -l postgres -T $RECOVERY_HOST $PGCTL -w -D $RECOVERY_BASEDIR start 2>/dev/null 1> /dev/null < /dev/null &

これら3ファイルに実行権限を付けて、各ノードサーバーのデータディレクトリ以下に配置します。

以上で、オンラインリカバリの準備は完了です。


では実際にオンラインリカバリを試してみます。
オンラインリカバリを行うには、いずれかのノードサーバーがpgpool側で異常検知されている必要があります。
今回は192.168.0.2のPostgreSQLを止めてからオンラインリカバリをしてみます。


% /usr/local/pgsql/bin/pg_ctl -D /path/to/pgsql/data stop

% /usr/local/pgsql/bin/psql -p 9999  // ←pgpoolへ接続
postgres=# show pool_nodes;
 node_id |   hostname   | port | status | lb_weight |  role  | select_cnt 
---------+--------------+------+--------+-----------+--------+------------
 0       | 192.168.0.1  | 5432 | 2      | 0.500000  | master | 1200
 1       | 192.168.0.2  | 5432 | 3      | 0.500000  | slave  | 884
(2 rows)

192.168.0.2が停止しています。

この状態で、pcp_recovery_nodeコマンドでオンラインリカバリを行います。

% /path/to/pgpool/bin/pcp_recovery_node -h 192.168.0.1 -p 9898 -U postgres -n 1

-h ... PCP(pgpool Communication Manager Connection)の稼働ホスト?
-p ... PCPの稼働ポート
-U ... pgpoo.confに記したrecovery_user名
-n ... 何番のノードを起動させるか。今回はnode_id=1の192.168.0.2

以上で、問題なければオンラインリカバリが成功するはずです。
ただ、オンラインリカバリを行うのは意外と時間かかる場合があるので気長に待つ必要も大切です。


【実際に試してみた】

サービス稼働中を模して、
無限ループでINSERTさせながらオンラインリカバリをやってみました。
...が、ターミナル上はSuccess!と出たのですが、
実際にデータを確認してみると2件レコードのズレがありました...。
やはり、データ誤差が出た場合は一旦サービス止めてdata/ディレクトリ丸ごとコピーの方が安全なのでしょうか。。?


以上でぇぇぇぇす!

1 件のコメント:

匿名 さんのコメント...

拝見させて頂きました。

オンラインリカバリの2ndステージはクライアントからの接続を拒否するのでしたっけ・・・
2件のズレから考えると、システム停止必須でpg_basebackupの方が安全そうですね。

参考になりました。