ErogameScapeではpgpoolを使って負荷分散、PostgreSQL障害時の切り替えを実施しています。
PostgreSQLは同期レプリケーションでprimary、standbyの2台構成です。
primaryを正常に停止して(pg_ctl stopして)、standbyを昇格させた(pg_ctl promote)場合、旧primaryはrecovery.confに新primaryを指定して起動すれば、ちゃんとレプリケーションが開始されます。
ところが、pgpoolでfailover_commandとして、
1. 非同期モードに設定を変更(postgresql.confのsynchronous_standby_namesを''にしてreload)
2. standbyを昇格(pg_ctl promote)
というスクリプトを指定し、primaryをpg_ctl stopさせた、旧primaryに適切なrecovery.confを書いて起動させたにも関わらず、レプリケーションが開始出来ず、pg_rewindが必要になってしまいました。
ちゃんとした理由は未だに分からないのですが、おそらく、primaryのpg_ctl stopが完全に終わる前に、pgpoolがstandbyをpg_ctl promoteしてしまうからではないか…と想定しました。
※primaryをちゃんとstopせずに、standbyをpg_ctl promoteすると、経験上、多くの場合で、pg_rewindかpg_basebackupが必要になります。
そこで、failover_commandのスクリプトにsleepを10秒(根拠はありません…)いれてみたら、想定通りスイッチオーバーとしての動作となりました。
以下failover_commandのスクリプトです。
#! /bin/sh -x
# Execute command by failover.
# special values: %d = node id
# %h = host name
# %p = port number
# %D = database cluster path
# %m = new master node id
# %M = old master node id
# %H = new master node host name
# %P = old primary node id
# %R = new master database cluster path
# %r = new master port number
# %% = '%' character
falling_node=$1 # %d
old_primary=$2 # %P
new_primary=$3 # %H
pgdata=$4 # %R
old_hostname=$5 # %h
pghome=/usr/pgsql-11
log=/var/log/pgpool/failover.log
date >> $log
echo "failed_node_id=$falling_node old_primary=$old_primary new_primary=$new_primary old_hostname=$old_hostname UID=$UID" >> $log
if [ $falling_node = $old_primary ]; then
echo "failed_node_id=master" >> $log
if [ $UID -eq 0 ]; then
su postgres -c "ssh -T postgres@$new_primary $pgdata/synchronous_standby_names_change.sh"
su postgres -c "ssh -T postgres@$new_primary $pghome/bin/pg_ctl reload -D $pgdata"
sleep 10
su postgres -c "ssh -T postgres@$new_primary $pghome/bin/pg_ctl promote -D $pgdata"
su postgres -c "ssh -T postgres@$old_hostname cp -p $pgdata/recovery.conf.for.$old_hostname $pgdata/recovery.conf"
else
ssh -T postgres@$new_primary $pgdata/synchronous_standby_names_change.sh
ssh -T postgres@$new_primary $pghome/bin/pg_ctl reload -D $pgdata
sleep 10
ssh -T postgres@$new_primary $pghome/bin/pg_ctl promote -D $pgdata
ssh -T postgres@$old_hostname cp -p $pgdata/recovery.conf.for.$old_hostname $pgdata/recovery.conf
fi
exit 0;
else
echo "failed_node_id=standby" >> $log
if [ $UID -eq 0 ]; then
su postgres -c "ssh -T postgres@$new_primary $pgdata/synchronous_standby_names_change.sh"
su postgres -c "ssh -T postgres@$new_primary $pghome/bin/pg_ctl reload -D $pgdata"
else
ssh -T postgres@$new_primary $pgdata/synchronous_standby_names_change.sh
ssh -T postgres@$new_primary $pghome/bin/pg_ctl reload -D $pgdata
fi
fi;
exit 0;
synchronous_standby_names_change.shは、同期レプリケーションを非同期レプリケーションにするために、postgresql.confを書き換えるスクリプトです。
sed -i -e "/synchronous_standby_names/c\#synchronous_standby_names = 'sby' # standby servers that provide sync rep" /var/lib/pgsql/11/data/postgresql.conf