PostgreSQL12でもストリーミングレプリケーションを試したい
はじめ
特にPostgresを使う予定は無かったのですが、『PostgresのSRでHA構成を組んだこと?ありますよ(ドヤァ』と言えるようになりたいのでとりあえずストリーミングレプリケーションをやってみることにします。
構成
今回の構成は以下のような感じです。
- OS
- Ubuntu 20.04.2 LTS (Focal Fossa)
- Postgres
- 12.8
また、今回はプライマリとスタンバイを同じホスト上にポートを変えて起動させます。
- プライマリポート
- 5432
- スタンバイポート
- 5433
ビルド
ディストリのパッケージをインストールするとクラスタを自動で作ってくれたりsystemdに登録してくれたりしますが、今回はそういうお節介は不要なのでソースからビルドすることにします。
上の記事を参考にして、サクッとビルドします。
$ 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
もちろん、スタンバイ側への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とかが必要になるっぽいです。
おわり