冗長化構成にしてみよう～PostgreSQLロジカルレプリケーション編～

皆さんこんにちは！haruです。

前回はPostgreSQLを使用してストリーミングレプリケーションをセットアップしてみました。
次はロジカルレプリケーションをセットアップしていきます。

## ロジカルレプリケーションとは
**概要**
前回の記事でも説明しましたが、一応おさらいです。
簡単にいうとロジカルレプリケーションは、異なるバージョン間や一部のテーブルのみをレプリケーションしたい時におすすめな冗長化構成です。

ストリーミングレプリケーションとは異なり、TRUNCATEに関するデータ操作等できないこともあります。
[制限事項について詳しくはこちら](https://www.postgresql.jp/document/13/html/logical-replication-restrictions.html)

**呼称**
また、ストリーミングレプリケーションでは、プライマリ側の WAL(データ更新情報)をそのままスタンバイ側でリカバリしていたため、プライマリ-スタンバイの呼称でした。
一方、ロジカルレプリケーションでは、パブリッシャー側のWALをデコードしてサブスクライバー側に渡します。
このように同じレプリケーションでもデータ連携の仕組みが異なるため、呼称自体も異なります。

英語でいうと、パブリッシャーは出版社、サブスクライバーは購読者になるので、
出版社の一部の雑誌を定期購読している構図をイメージするとわかりやすいかもしれません。

## 使用環境
使用する環境は以下です。
- パブリッシャー側
OS:RHEL8
DB:PostgreSQL-15
HOST:pub

- サブスクライバー側
OS:RHEL8
DB:PostgreSQL-15
HOST:sub

## パブリッシャー側の設定
#### postgresql.conf
以下のパラメータを設定します。
wal_level : WAlの出力レベル
max_wal_senders : wal senders に同時接続する最大数

※最低限、[ネットワーク設定](https://qiita.com/haru4989/items/b0de4d50162f3d91cd16)とwal_level のみ設定できていれば構成が可能です。
```
[postgres@primary ~]$ vi /var/lib/pgsql/15/data/postgresql.conf
wal_level = logical
max_wal_senders = 10
```
PostgreSQL のサービスを再起動し、設定を反映させます。
```
[postgres@primary ~]$ su
パスワード:
[root@primary pgsql]# systemctl restart postgresql-15
```
#### ロジカルレプリケーション対象のテーブル作成
レプリケーションを行う対象となるテーブルを任意のデータベース配下に作成しておきます。
```
[postgres@pub ~]$ psql -U postgres
psql (15.0)
"help"でヘルプを表示します。

postgres=# create database mydb;
CREATE DATABASE
postgres=# \c mydb
データベース"mydb"にユーザー"postgres"として接続しました。
mydb=# create table testta (id integer,name varchar(10));
CREATE TABLE
```
#### ロジカルレプリケーションの定義
パブリッシャー側で対象のテーブルに対してロジカルレプリケーションの定義を行います。
```
mydb=# create publication pub_a for table testta;
CREATE PUBLICATION
*/正常に定義されていると「CREATE PUBLICATION」が表示されます。/*
```
## サブスクライバー側の設定
#### 
パブリッシャー側のスキーマ情報を取得します。
```
[root@sub pgsql]# su postgres
bash-4.4$ /usr/pgsql-15/bin/pg_dump -h <パブリッシャー側のIPアドレス> -p 5432 --username=postgres --schema-only --table testta mydb > testta_schema.sql
bash-4.4$ exit
exit
[root@sub pgsql]# ll
合計 4
drwx------. 4 postgres postgres  33 10月 27 03:49 15
-rw-r--r--. 1 postgres postgres 756 10月 27 09:57 testta_schema.sql */このファイルが確認できれば、スキーマ情報が取得できています。/*
```
ここで接続系のエラーが発生した場合は、一旦、パブリッシャー側のデータベースに対してPGAdmin から接続可能かを確認してみてください。

また、クライアント接続のセットアップ方法については、以下のQiitaをご参考にして頂ければ幸いです。
[行き当たりばったり学習～PostgreSQL PGAdmin接続編(RHEL8)～](https://qiita.com/haru4989/items/b0de4d50162f3d91cd16)

#### ロジカルレプリケーションの利用を宣言
以下のコマンドを実行することで利用を宣言します。
```
mydb=# CREATE SUBSCRIPTION sub_a CONNECTION 'dbname=mydb host=<パブリッシャー側のIPアドレス>' PUBLICATION pub_a;
NOTICE:  created replication slot "sub_a" on publisher
CREATE SUBSCRIPTION
```
## 同期状況を確認
```
**パブリッシャー側**
[postgres@pub log]$ tail -n postgresql-Thu.log|grep "START_REPLICATION SLOT"
tail: 無効な行数です: `postgresql-Thu.log'
[postgres@pub log]$ tail -n 50 postgresql-Thu.log|grep "START_REPLICATION SLOT"
2022-10-27 10:04:37.520 EDT [2612] STATEMENT:  START_REPLICATION SLOT "sub_a" LOGICAL 0/0 (proto_version '3', publication_names '"pub_a"')
2022-10-27 10:04:37.520 EDT [2612] STATEMENT:  START_REPLICATION SLOT "sub_a" LOGICAL 0/0 (proto_version '3', publication_names '"pub_a"')
2022-10-27 10:04:37.567 EDT [2613] STATEMENT:  START_REPLICATION SLOT "pg_16393_sync_16389_7159097010397109263" LOGICAL 0/19F46D8 (proto_version '3', publication_names '"pub_a"')
2022-10-27 10:04:37.567 EDT [2613] STATEMENT:  START_REPLICATION SLOT "pg_16393_sync_16389_7159097010397109263" LOGICAL 0/19F46D8 (proto_version '3', publication_names '"pub_a"')

**サブスクライバー側**
[postgres@sub log]$ tail -n 50 postgresql-Thu.log | grep "finish"
2022-10-27 10:04:37.569 EDT [3652] LOG:  logical replication table synchronization worker for subscription "sub_a", table "testta" has finished
```

## ロジカルレプリケーションの動作確認
**パブリッシャー側**
```
[postgres@pub log]$ psql -U postgres
psql (15.0)
"help"でヘルプを表示します。

postgres=# \c mydb
データベース"mydb"にユーザー"postgres"として接続しました。
mydb-# \t
「タプルのみ表示」は on です。
mydb-# \d
 public   | testta | テーブル | postgres

mydb=# insert into testta values(2,'a');
INSERT 0 1
mydb=# insert into testta values(2,'c');
INSERT 0 1
mydb=# insert into testta values(2,'b');
INSERT 0 1
```

**サブスクライバー側**
```
[postgres@sub log]$ psql -U postgres
psql (15.0)
"help"でヘルプを表示します。

postgres=# \c mydb
データベース"mydb"にユーザー"postgres"として接続しました。
mydb=# \d
            リレーション一覧
 スキーマ |  名前  |  タイプ  |  所有者
----------+--------+----------+----------
 public   | testta | テーブル | postgres
(1 行)

mydb=# select * from testta;
 id | name
----+------
  2 | a
  2 | c
  2 | b
(3 行)
```
パブリッシャー側の更新情報がサブスクライバー側でも確認できました。
ロジカルレプリケーションのセットアップは完了です。
以上です！