Pgpool-IIを使用した高可用性構成を試してみたい

はじめに

Postgres標準のストリーミングレプリケーションだけでは、スタンバイは自動的にプライマリに昇格せずオペレータの介在を必要とします。

ここでは、Pgpool-IIを使用して複数のクラスタを制御し、プライマリへの自動昇格を行わせます。

環境のセットアップ

ゼロから構築するのは割とつらいので、pgpool_setupを使用してテスト環境を構築します。

このツールはテスト環境を手早くでっち上げるためのツールなので、本番には使えません。

ローカルからパスワード無しでsshログインが出来る必要があるので、鍵を生成してそのまま自分の公開鍵リストに突っ込みます。

ssh-keygen -t ed25519 -C localhost
cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys

PostgresやPgpool-IIのインストール先がデフォルトと異なるので、それぞれのインストール先を環境変数に設定していきます。

export PGPOOL_INSTALL_DIR=/home/jyuch/local/pgpool
export PGBIN=/home/jyuch/local/pg/11/bin 
export PGLIB=/home/jyuch/local/pg/11/lib

データベースクラスタや設定ファイル群を格納するディレクトリを作成し、その中にテスト環境をセットアップします。

mkdir ~/pgdata/pgpooltest && cd ~/pgdata/pgpooltest
pgpool_setup -s

以下のコマンドでシステム全体が起動します。

./startall

起動すると(変更していなければ)Pgpool-IIは11000ポートで待ち受けます。 任意のデータベースに対してshow pool_nodes疑似SQLを投入すると参加しているクラスタの状況が見られます。 pgpool_setuptestデータベースを自動的に作成するので、今回はこれを使用します。

$ psql -p 11000 -c "show pool_nodes" test
-[ RECORD 1 ]----------+--------------------
node_id                | 0
hostname               | /tmp
port                   | 11002
status                 | up
lb_weight              | 0.500000
role                   | primary
select_cnt             | 0
load_balance_node      | false
replication_delay      | 0
replication_state      |  
replication_sync_state |  
last_status_change     | 2021-08-11 11:08:24
-[ RECORD 2 ]----------+--------------------
node_id                | 1
hostname               | /tmp
port                   | 11003
status                 | up
lb_weight              | 0.500000
role                   | standby
select_cnt             | 0
load_balance_node      | true
replication_delay      | 0
replication_state      | streaming
replication_sync_state | async
last_status_change     | 2021-08-11 11:08:24

レプリケーション

ここでは、テストデータとしてpgbenchのデータを流し込みます。

$ pgbench -i -p 11000 test

ベンチマークを走らせて、結果をそれぞれのDBに問い合わせると同じ答えが返ってくるので、問題なさそうです。

$ pgbench -p 11000 -T 10 test
psql -p 11002 -c "SELECT sum(abalance) FROM pgbench_accounts" test
  sum  
-------
 92663
(1 row)

psql -p 11003 -c "SELECT sum(abalance) FROM pgbench_accounts" test
  sum  
-------
 92663
(1 row)

フェイルオーバー

プライマリを停止させ、スタンバイが正常にプライマリに昇格するか確認します。

プライマリを疑似的に異常終了させます。

pg_ctl -m immediate -D data0 stop

すると、スタンバイが自動でプライマリに昇格します。

psql -x -p 11000 -c "show pool_nodes" test
-[ RECORD 1 ]----------+--------------------
node_id                | 0
hostname               | /tmp
port                   | 11002
status                 | down
lb_weight              | 0.500000
role                   | standby
select_cnt             | 690
load_balance_node      | false
replication_delay      | 0
replication_state      |  
replication_sync_state |  
last_status_change     | 2021-08-11 11:38:28
-[ RECORD 2 ]----------+--------------------
node_id                | 1
hostname               | /tmp
port                   | 11003
status                 | up
lb_weight              | 0.500000
role                   | primary
select_cnt             | 0
load_balance_node      | true
replication_delay      | 0
replication_state      |  
replication_sync_state |  
last_status_change     | 2021-08-11 11:38:28

この状態でもpgbenchは完走します。

$ pgbench -p 11000 -T 10 test                                       
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 1
query mode: simple
number of clients: 1
number of threads: 1
duration: 10 s
number of transactions actually processed: 1195
latency average = 8.375 ms
tps = 119.403809 (including connections establishing)
tps = 119.429839 (excluding connections establishing)

オンラインリカバリ

ノードを復帰させるコマンドを投入します。

pg_ctlを使用して手動で再起動するとわけわかんない事になるのでやってはいけません。(1敗)

$ pcp_recovery_node -p 11001 -n 0
Password:  # ← 詳しい話は分からないが、とりあえず pgpool_setup を実行したユーザ名と同じであれば大丈夫っぽい
pcp_recovery_node -- Command Successful
$ psql -x  -p 11000 -c "show pool_nodes" test
-[ RECORD 1 ]----------+--------------------
node_id                | 0
hostname               | /tmp
port                   | 11002
status                 | up
lb_weight              | 0.500000
role                   | standby
select_cnt             | 0
load_balance_node      | false
replication_delay      | 0
replication_state      | streaming
replication_sync_state | async
last_status_change     | 2021-08-11 12:19:20
-[ RECORD 2 ]----------+--------------------
node_id                | 1
hostname               | /tmp
port                   | 11003
status                 | up
lb_weight              | 0.500000
role                   | primary
select_cnt             | 0
load_balance_node      | true
replication_delay      | 0
replication_state      | 
replication_sync_state | 
last_status_change     | 2021-08-11 12:18:27

すると、何となくノード0が復帰します。

おわり