PostgreSQL16のスタンバイからのロジカルレプリケーションにおけるスタンバイ昇格の影響調査

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">確かに、手元で試したら、スタンバイ昇格してもlogical walsenderの再起動などなく、ロジカルレプリケーションがそのまま続行されたっぽい！ <a href="https://twitter.com/hashtag/pg16?src=hash&amp;ref_src=twsrc%5Etfw">#pg16</a></p>&mdash; Fujii Masao (@fujii_masao) <a href="https://twitter.com/fujii_masao/status/1672230782528790528?ref_src=twsrc%5Etfw">June 23, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

以下は、PostgreSQL 16の新機能であるストリーミングレプリケーションのスタンバイ側からのロジカルレプリケーションについて、上記ツイートで試した手順の整理です。

前提として、検証手順では、以下のデータベースクラスタのディレクトリ名とポート番号で3つのPostgreSQLインスタンスを同一環境上で起動します。

| 項番 | データベースクラスタのディレクトリ名 | ポート番号 | インスタンスの用途 |
|:-:|:-:|:-:|:-|
| 1 | pri | 5432 | ストリーミングレプリケーションの**プライマリ** |
| 2 | sby | 5433 | ストリーミングレプリケーションの**スタンバイ**、かつ、ロジカルレプリケーションの**パブリケーション側** |
| 3 | sub | 5434 | ロジカルレプリケーションの**サブスクリプション側** |

# 検証手順
ストリーミングレプリケーションの**プライマリ**について、データベースクラスタを作成して、起動します。ロジカルレプリケーションを使うために、wal_levelはlogicalに設定します。

```bash
$ initdb -D pri --locale=C --encoding=UTF8
$ echo "wal_level = logical" >> pri/postgresql.conf
$ pg_ctl -D pri start
```

ストリーミングレプリケーションの**スタンバイ**について、プライマリのバックアップから起動します。

```bash
$ pg_basebackup -D sby -R
$ echo "port = 5433" >> sby/postgresql.conf
$ pg_ctl -D sby start
```

ロジカルレプリケーションの**サブスクリプション側**について、データベースクラスタを作成して、起動します。

```bash
$ initdb -D sub --locale=C --encoding=UTF8
$ echo "port = 5434" >> sub/postgresql.conf
$ pg_ctl -D sub start
```

今回の検証では、pgbenchのテーブル4つをロジカルレプリケーションします。pgbenchの初期データをプライマリで作成して、そのテーブルをロジカルレプリケーションするためのパブリケーションを作成します。これらの初期データとパブリケーションは、ストリーミングレプリケーションによりスタンバイに自動的に複製されます。

```bash
$ pgbench -i -s 10 -p 5432
$ psql -p 5432 -c "CREATE PUBLICATION pgbench_pub FOR TABLE pgbench_accounts, pgbench_branches, pgbench_tellers, pgbench_history"
```

サブスクリプション側では、初期データなしでpgbenchのテーブルだけ作成して、スタンバイからロジカルレプリケーションされるようにport=5433を指定してサブスクリプションを作成します。

```bash
$ pgbench -i -Itp -p 5434
$ psql -p 5434 -c "CREATE SUBSCRIPTION pgbench_sub CONNECTION 'port=5433' PUBLICATION pgbench_pub"
```

上記の```CREATE SUBSCRIPTION```が長時間完了しない場合は、プライマリに対して```CHECKPOINT```などの更新コマンドを実行することで完了することがあります。

```bash
$ psql -p 5432 -c "CHECKPOINT"
```

プライマリに対してpgbenchで10トランザクションを走らせ、pgbench_historyの10トランザクション分のレコードがサブスクリプション側にロジカルレプリケーションされていること(レコード件数が10件であること)を確認します。これで、スタンバイからのロジカルレプリケーションのセットアップが完了しました。

```bash
$ pgbench -p 5432 -t 10
$ psql -p 5434 -c "SELECT count(*) FROM pgbench_history"
```

スタンバイ昇格のロジカルレプリケーションへの影響を調査するため、ロジカルレプリケーションの「スタンバイ(昇格後は新プライマリ)上のwalsenderプロセスのPID」と「サブスクリプション上のlogical replication workerプロセスのPID」を確認します。

```bash
$ psql -p 5433 -c "SELECT * FROM pg_stat_replication"
$ psql -p 5434 -c "SELECT * FROM pg_stat_activity WHERE backend_type = 'logical replication worker'"
```

スタンバイを新プライマリに昇格させます。

```bash
$ pg_ctl -D sby promote
```

再度、ロジカルレプリケーションの「新プライマリ(昇格前は旧スタンバイ)上のwalsenderプロセスのPID」と「サブスクリプション上のlogical replication workerプロセスのPID」を確認します。前回と今回で各プロセスのPIDに変更がなければ、スタンバイ昇格によって各プロセスが再起動されることはなかったと確認できます。

```bash
$ psql -p 5433 -c "SELECT * FROM pg_stat_replication"
$ psql -p 5434 -c "SELECT * FROM pg_stat_activity WHERE backend_type = 'logical replication worker'"
```

プライマリに対してpgbenchで20トランザクションを走らせ、pgbench_historyの20トランザクション分のレコードがサブスクリプション側にロジカルレプリケーションされていること(レコード件数が20件であること)を確認します。これにより、スタンバイ昇格後も問題なくロジカルレプリケーションが動作していることを確認します。

```bash
$ pgbench -p 5433 -t 20
$ psql -p 5434 -c "SELECT count(*) FROM pgbench_history"
```