PostgreSQL12でもストリーミングレプリケーションを試したい

はじめ

特にPostgresを使う予定は無かったのですが、『PostgresのSRでHA構成を組んだこと?ありますよ(ドヤァ』と言えるようになりたいのでとりあえずストリーミングレプリケーションをやってみることにします。

構成

今回の構成は以下のような感じです。

  • OS
    • Ubuntu 20.04.2 LTS (Focal Fossa)
  • Postgres
    • 12.8

また、今回はプライマリとスタンバイを同じホスト上にポートを変えて起動させます。

  • プライマリポート
    • 5432
  • スタンバイポート
    • 5433

ビルド

ディストリのパッケージをインストールするとクラスタを自動で作ってくれたりsystemdに登録してくれたりしますが、今回はそういうお節介は不要なのでソースからビルドすることにします。

qiita.com

上の記事を参考にして、サクッとビルドします。

$ sudo apt install build-essential libreadline-dev zlib1g-dev
$ mkdir -p ~/source && cd ~/source
$ wget https://ftp.postgresql.org/pub/source/v12.8/postgresql-12.8.tar.gz
$ tar zxf postgresql-12.8.tar.gz
$ cd postgresql-12.8
$ mkdir build_dir && cd build_dir
$ "$HOME/source/postgresql-12.8/configure" --prefix="$HOME/local/pg/12"
$ make
$ make install

あとは~/local/pg/12/binをパスに追加すればOKです。

プライマリデータベースクラスタの作成

以下の感じでプライマリのデータベースクラスタを作成します。

$ initdb --no-locale --encoding=UTF8 -D $PGDATA_PRIMARY
$ pg_ctl start -D $PGDATA_PRIMARY

そうしたら、レプリケーション用のユーザを作成します。 今回はログインメソッドをトラストでレプリケーションを行うのでパスワードの設定は不要です。

$ psql -p 5432 -c "CREATE ROLE repl_user LOGIN REPLICATION" postgres

本来はpg_hba.confをいい感じに編集する必要があるのですが、デフォルトでローカルループバックからのレプリケーション接続は許可されているのでこのままで大丈夫です。

あとはテキトーに初期データを投入しておきます。

$ psql -p 5432 -c "CREATE DATABASE test" postgres
CREATE DATABASE

$ psql -p 5432 -c "CREATE TABLE hoge (i timestamp, msg varchar(100))" test
CREATE TABLE

$ psql -p 5432 -c "INSERT INTO  hoge values (now(), 'poipoi')" test
INSERT 0 1

$ psql -p 5432 -c "SELECT * FROM  hoge" test    
             i              |  msg   
----------------------------+--------
 2021-08-17 12:14:16.468007 | poipoi
(1 row)

スタンバイクラスタの準備

スタンバイ側はpg_basebackupを使用してプライマリからコピーしてきます。 今回はレプリケーションスロットを新規で作成し、それを使用してレプリケートしています。

$ pg_basebackup -h localhost -D $PGDATA_STANDBY -X stream --progress -R -U repl_user --create-slot --slot=localhost_standby
31310/31310 kB (100%), 1/1 tablespace

--create-slot--slot=localhost_standbyオプションで、レプリケーションスロットをプライマリ側に生やしてそのスロット経由でデータを持ってきてくれます。

-Rオプションを使用することで、レプリケートに使用した接続情報とスロット情報がpostgres.auto.confにいい感じに書き込まれます。

あとはpostgres.confで待ち受けポートを変更すれば起動準備は完了します。

pg_ctl start -D $PGDATA_STANDBY

レプリケーションの確認

プライマリ側にデータを投入してみて、ちゃんとスタンバイ側に反映されるか確認してみましょう。

$ psql -p 5432 -c "INSERT INTO  hoge values (now(), 'puipui')" test
INSERT 0 1

$ psql -p 5432 -c "SELECT * FROM  hoge" test
             i              |  msg   
----------------------------+--------
 2021-08-17 12:14:16.468007 | poipoi
 2021-08-17 12:51:16.564552 | puipui
(2 rows)


$ psql -p 5433 -c "SELECT * FROM  hoge" test
             i              |  msg   
----------------------------+--------
 2021-08-17 12:14:16.468007 | poipoi
 2021-08-17 12:51:16.564552 | puipui
(2 rows)

レプリケーションの状態はpg_stat_replicatonで見られるようです。

$ psql -x -p 5432 -c "SELECT * FROM pg_stat_replication" postgres
-[ RECORD 1 ]----+------------------------------
pid              | 26102
usesysid         | 16384
usename          | repl_user
application_name | walreceiver
client_addr      | 127.0.0.1
client_hostname  | 
client_port      | 37472
backend_start    | 2021-08-17 12:46:51.287155+00
backend_xmin     | 
state            | streaming
sent_lsn         | 0/5000338
write_lsn        | 0/5000338
flush_lsn        | 0/5000338
replay_lsn       | 0/5000338
write_lag        | 
flush_lag        | 
replay_lag       | 
sync_priority    | 0
sync_state       | async
reply_time       | 2021-08-17 12:53:56.045178+00

www.postgresql.jp

もちろん、スタンバイ側へのINSERTなどのSQLはリジェクトされます。

$ psql -p 5433 -c "INSERT INTO  hoge values (now(), 'pui')" test   
ERROR:  cannot execute INSERT in a read-only transaction

スタンバイのプライマリへの昇格

プライマリが何らかの理由でダウンした場合、スタンバイ(のうちのどれか)を新プライマリに昇格させる必要があります。

$ pg_ctl stop -m immediate -D $PGDATA_PRIMARY

プライマリがダウンしても、スタンバイはリードオンリーモードで動作し続けます。 そのため、(スタンバイが複数ある場合は)最もプライマリの変更に追従できていたスタンバイを選択し手動で昇格させる必要があります。

$ psql -p 5433 -c "SELECT * FROM pg_promote()" postgres
 pg_promote 
------------
 t
(1 row)

pg_promote()でスタンバイがプライマリに昇格したので、今度は以下のコマンドは成功します。

$ psql -p 5433 -c "INSERT INTO  hoge values (now(), 'pui')" test
INSERT 0 1

$ psql -p 5433 -c "SELECT * FROM  hoge" test
             i              |  msg   
----------------------------+--------
 2021-08-17 12:14:16.468007 | poipoi
 2021-08-17 12:51:16.564552 | puipui
 2021-08-17 13:08:18.436671 | pui
(3 rows)

おわりに

標準機能でデータのレプリケーションはできますが、仮想IPを振って自動的にハンドオーバーしてくれたりプライマリがダウンしたらいい感じにスタンバイを昇格とかはしてくれません。

この辺をやるにはPgpool-IIとかが必要になるっぽいです。

おわり