「pgpool-II」でオンラインリカバリの手順

「pgpool-II」でオンラインリカバリの手順

pgpool-IIの新機能である、「オンラインリカバリ」を検証した手順メモ。

【環境】

以下の環境でテストしました

| サービス | ホスト | バージョン | OS |
| pgpool-II | 192.168.11.145 | pgpool-II-3.0.5 | CentOS5.6 |
| postgresql0(ノード0) | 192.168.11.145 | postgresql-8.1.23-1 | CentOS5.6 |
| postgresql1(ノード1) | 192.168.11.146 | postgresql-8.1.23-1 | CentOS5.6 |

各サービスはインストール済みであるとします
参考: PostgreSQL用クラスタリングツール「pgpool-II」のインストール

【ノード0と1の共通設定】

アーカイブディレクトリの作成

$ sudo su – postgres
postgres$ initdb -D /var/lib/pgsql/data

設定ファイルの変更

$ sudo vim /var/lib/pqsql/data/postgresql.conf
… 以下を変更
listen_addresses = ‘*’
archive_command = ‘cp %p /usr/local/pgsql/data/archive_log/%f’

$ sudo vim /var/lib/pgsql/data/pg_hba.conf
…以下を追加
host all all 192.168.11.0/24 trust

オンラインリカバリ用Shellの作成

$ sudo su – postgres
$ cd /var/lib/pgsql/data
$ vim recovery_1st_stage.sh
\#!/bin/bash

PSQL=/usr/bin/psql

MASTER_BASEDIR=$1
RECOVERY_HOST=$2
RECOVERY_BASEDIR=$3

¥# ベースバックアップの開始
$PSQL -c “SELECT pg_start_backup(‘pgpool-recovery’)” postgres

¥# リカバリ先用のrecovry.confファイル生成
echo “restore_command = ‘cp $RECOVERY_BASEDIR/archive_log/%f %p'” > $MASTER_BASEDIR/recovery.conf

¥# リカバリ先のデータベースクラスタを念のためにバックアップ
ssh -T $RECOVERY_HOST rm -rf $RECOVERY_BASEDIR.bk
ssh -T $RECOVERY_HOST mv -f $RECOVERY_BASEDIR{,.bk}

¥# データベースクラスタ=ベースバックアップをリカバリ先に転送
rsync -acz -e ssh $MASTER_BASEDIR/ $RECOVERY_HOST:$RECOVERY_BASEDIR/

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

¥# リカバリ先に転送したので、不要になったrecovery.confを削除
rm -f $MASTER_BASEDIR/recovery.conf

¥# ベースバックアップの終了
$PSQL -c “SELECT pg_stop_backup()” postgres

$ vim recovery_2nd_stage.sh
\#! /bin/bash

PSQL=/usr/local/pgsql/bin/psql

MASTER_BASEDIR=$1
RECOVERY_HOST=$2
RECOVERY_BASEDIR=$3

¥# 最新のアーカイブログを保存
$PSQL -c ‘SELECT pg_switch_xlog()’ postgres

¥# 最新のアーカイブログをリカバリ先に転送
rsync -az -e ssh $MASTER_BASEDIR/archive_log/ $RECOVERY_HOST:$RECOVERY_BASEDIR/archive_log/

$ vim pgpool_remote_start
\#!/bin/sh

PGCTL=/usr/bin/pg_ctl

RECOVERY_HOST=$1
RECOVERY_BASEDIR=$2

¥# リカバリ先のPostgreSQLを起動
ssh -T $RECOVERY_HOST $PGCTL -w -D $RECOVERY_BASEDIR start 2>/dev/null 1> /dev/null < /dev/null &

パーミッション設定

chmod 755 recovery_1st_stage.sh recovery_2nd_stage.sh pgpool_remote_start

【pgpool設定】

pool_hba.confの設定

$ sudo vim /usr/local/etc/pool_hba.conf
… 以下を追加
host all all 192.168.11.0/24 trust

pgpool.confの設定

$ sudo vim /usr/local/etc/pgpool.conf
… 以下を変更
\# – online recovery –
\# online recovery user
recovery_user = ‘postgres’

\# online recovery password
recovery_password = ”

\# execute a command in first stage.
recovery_1st_stage_command = ‘recovery_1st_stage.sh’

\# execute a command in second stage.
recovery_2nd_stage_command = ‘recovery_2nd_stage.sh’

【サービス起動】

ノード0と、ノード1でPostgresqlを起動する

$ sudo /etc/rc.d/init.d/postgresql start

【sshキーの作成】

ノード0で、以下を実行

$ sudo su – postgres
postgres $ ssh-keygen -t dsa
postgres $ scp ~/.ssh/id_dsa.pub 192.168.11.146:~/
postgres $ ssh 192.168.1.101
postgres@postgres1 $ cat id_dsa.pub >> ~/.ssh/authorized_keys2
postgres@postgres1 $ rm id_dsa.pub

ノード1で、以下を実行

$ sudo su – postgres
postgres $ ssh-keygen -t dsa
postgres $ scp ~/.ssh/id_dsa.pub 192.168.1.100:~/
postgres $ ssh 192.168.1.100
postgres@postgres0 $ cat id_dsa.pub >> ~/.ssh/authorized_keys2
postgres@postgres0 $ rm id_dsa.pub

それぞれのノードから、相手先ノードへパスフレーズなしでSSHできることを確認する

【C言語関数のインストール】

各ノードで、以下のコマンドを実行

pgpool-recoveryのインストール

$ cd /usr/local/src
$ sudo wget http://pgfoundry.org/frs/download.php/3164/pgpool-II-3.0.5.tar.gz
$ sudo tar zxf pgpool-II-3.0.5.tar.gz
$ cd pgpool-II-3.0.5/sql/pgpool-recovery
$ make install

$ sudo cp pgpool-recovery.so /usr/lib/pgsql
$ sudo cp /pgpool-recovery.sql /usr/share/pgsql/
$ psql -U postgres -c “\i /usr/share/pgsql/pgpool-recovery.sql” template1

【オンラインリカバリの実行】

  1. データベース作成

$ createdb -p 9999 bench -U postgres

  1. ノード1を停止する

$ sudo su – postgres
postgres$ pg_ctl -D /var/lib/pgsql/data -m immediate stop

  1. 片系ノード稼働中に、DBの変更を行う

$ pgbench -i -p 9999 bench

  1. 以下のコマンドで、オンラインリカバリを実行する

pcp_recovery_node timeout hostname port# username password

例(ノード0→ノード1へのオンラインリカバリ):

pcp_recovery_node 10 192.168.11.146 9898 postgres password 1

  1. 確認

$ psql -U postgres -h 192.168.11.145
$ psql -U postgres -h 192.168.11.146

【問題点】

以下のトラブルが未解決

  • オンラインリカバリ後、リカバリした側のPostgresqlがpidファイルなしで起動している
  • /etc/rc.d/init.d/postgresql restartなどが利用できなくなっている

といった問題点をのこしつつも、オンラインリカバリには成功

【参考】

ノード0:pg_hba.conf

\# TYPE DATABASE USER CIDR-ADDRESS METHOD

\# “local” is for Unix domain socket connections only
\#local all all ident sameuser
local all all trust
\# IPv4 local connections:
\#host all all 127.0.0.1/32 ident sameuser
host all all 127.0.0.1/32 trust
host all all 192.168.11.0/24 trust
host template1 nobody 192.168.11.0/24 trust
\# IPv6 local connections:
\#host all all ::1/128 ident sameuser

ノード0:postgresql.conf

\# – Connection Settings –

listen_addresses = ‘‘ # what IP address(es) to listen on;
# comma-separated list of addresses;
# defaults to ‘localhost’, ‘
‘ = all
port = 5432
max_connections = 100
\# – Archiving –

archive_command = ‘cp %p /usr/local/pgsql/data/archive_log/%’ # command to use to archive a logfile

pgpool:pgpool.conf

\# Host name or IP address to listen on: ‘‘ for all, ” for no TCP/IP
\# connections
listen_addresses = ‘

\# Port number for pgpool
port = 9999

\# Port number for pgpool communication manager
pcp_port = 9898

\# Logging directory
logdir = ‘/var/log/pgpool’

\# pid file name
pid_file_name = ‘/var/run/pgpool/pgpool.pid’

\# Replication mode
replication_mode = true

\# Load balancing mode, i.e., all SELECTs are load balanced.
load_balance_mode = true

\# If there’s a disagreement with the packet kind sent from backend,
\# then degenrate the node which is most likely “minority”. If false,
\# just force to exit this session.
replication_stop_on_mismatch = true

\# Health check timeout. 0 means no timeout.
health_check_timeout = 20

\# Health check period. 0 means no health check.
health_check_period = 30

\# Health check user
health_check_user = ‘nobody’

\# If true, trigger fail over when writing to the backend communication
\# socket fails. This is the same behavior of pgpool-II 2.2.x or
\# earlier. If set to false, pgpool will report an error and disconnect
\# the session.
fail_over_on_backend_error = true

\# If true, automatically locks a dummy row or a table with INSERT
\# statements to keep SERIAL data consistency. If the data does not have
\# SERIAL data type, no lock will be issued. An /INSERT LOCK/ comment
\# has the same effect. A /NO INSERT LOCK/ comment disables the effect.
insert_lock = true

\# system DB info
system_db_hostname = ‘localhost’
system_db_port = 5432
system_db_dbname = ‘pgpool’
system_db_schema = ‘pgpool_catalog’
system_db_user = ‘pgpool’
system_db_password = ”

\# backend_hostname, backend_port, backend_weight
\# here are examples
backend_hostname0 = ‘192.168.11.145’
backend_port0 = 5432
backend_weight0 = 1
backend_data_directory0 = ‘/var/lib/pgsql/data’
backend_hostname1 = ‘192.168.11.146’
backend_port1 = 5432
backend_weight1 = 1
backend_data_directory1 = ‘/var/lib/pgsql/data’

\# – online recovery –
\# online recovery user
recovery_user = ‘postgres’

\# online recovery password
recovery_password = ”

\# execute a command in first stage.
recovery_1st_stage_command = ‘recovery_1st_stage.sh’

\# execute a command in second stage.
recovery_2nd_stage_command = ‘recovery_2nd_stage.sh’

\# maximum time in seconds to wait for the recovering node’s postmaster
\# start-up. 0 means no wait.
\# this is also used as a timer waiting for clients disconnected before
\# starting 2nd stage
recovery_timeout = 90

pgpool:pg_hba.conf

\# TYPE DATABASE USER CIDR-ADDRESS METHOD

\# “local” is for Unix domain socket connections only
local all all trust
\# IPv4 local connections:
host all all 127.0.0.1/32 trust
host all all 192.168.11.0/24 trust

pgpool:pcp.conf

\# USERID:MD5PASSWD
postgres:e8a48653851e28c69d0506508fb27fc5