22
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PostgreSQL 10がやってくる!(その5) ロジカルレプリケーション基本編

Last updated at Posted at 2017-02-19

はじめに

今日はPostgreSQL 10の目玉機能の一つになるであろう、ロジカルレプリケーションを使ってみた話を書きますよ。

参考にしたもの

実はPostgreSQL 10のロジカルレプリケーションに関しては、postgresql-jp Slackで、篠田さん@HPEや前JPUG理事長の永安さんが簡単に検証した例を紹介しているので、そっちを見ればいいのだろうけど、まあこういうのは自分で手を動かさないと覚えないので、自分でもやってみることにする。

ロジカルレプリケーションって何よ?

名前のとおり、論理WALを伝播させてレプリケーションさせる機能。
PostgreSQL 9.0から導入されたストリーミングレプリケーションは物理レプリケーションであり、WALをそのままダイレクトに反映させる機構。なので、レプリケーション元/先のメジャーバージョンやOSアーキテクチャが異なると適用できなかった。
PostgreSQL 10のロジカルレプリケーションは、異なるバージョンや異なるOSアーキテクチャ間でも適用が可能になる(はず)。また、ストリーミングレプリケーションでは、データベースクラスタ全体がレプリケーション対象となるため、特定のテーブルのみをレプリケーションしたいという用途には使えなかった。

PostgreSQL 9.4からサポートされているロジカルデコーディングの技術をベースにしている。今まではプラグインや論理WALを反映させる機構の作成が必要だった。
自分もロジカルデコーディングを使って、PostgreSQLのWALをグラフデータベースNeo4jに反映させてみる、というを作って遊んでいたりしてたけど、まあ、ぶっちゃけ面倒です。
ロジカルレプリケーションでは、幾つかのSQLコマンドを叩くだけで、ロジカルデコーディングでやっていた論理WALへの変換とレプリケーション先への反映をやってくれるというものになっている(はず)。

じゃあ、早速使ってみようか。なお、検証に使った版は今日の最新ソースをベースにしたものなんだけど、まだまだ開発途中の版なので、beta版リリース時には仕様等、ちょっと変わっているかもしれないので悪しからず。

準備

postgresql.conf

ロジカルレプリケーションもストリーミングレプリケーションに類似した設定が必要になってくる。
ロジカルレプリケーションを動作させるためには、最低限、以下のパラメータの変更がレプリケーション元のサーバには必要になる。

パラメータ名 設定 説明
wal_level logical SRの場合にはreplicaでいいが、ロジカルレプリケーションの場合はlogical必須
max_wal_senders 1より大きい値 SRと併用する場合、その数の考慮要
max_replication_slots 1より大きい値 論理レプリケーション要のスロット数。SRでスロットを併用する場合はそれも考慮要

pg_hba.conf

ロジカルレプリケーションもレプリケーションプロトコルを使った接続を行うので、ストリーミングレプリケーションと同様にpg_hba.confにreplicationデータベースとして登録しておく。
今回は面倒なのでpostgresのままで設定したが、実際に運用する場合には、レプリケーション専用ロールを使って接続させるのが良さげ。

ロジカルレプリケーションの設定

レプリケーションの設定は、ソースと反映先の2つに設定が必要になる。
ひじょーにざっくり書くと、以下のような設定を行う。
Slony-Iとかの経験がある人だと、「あー、そんな用語だったねー」と思うはず。

  • レプリケーション元
    • レプリケーション対象のテーブルを指定する。PKを持つテーブルにしておくのが無難。
    • CREATE PUBLICATIONコマンドでレプリケーション元の設定を行う。このときにロジカルレプリケーション対象のテーブルを選択する。
    • たぶんDB全体とか、そういうまるっとした設定もできるはず。
  • レプリケーション先
    • レプリケーション先のテーブルを指定する。これもPKを持たせておかないと、後々いろいろ面倒なことになりそう。つーか、とりあえずはレプリケーション元に合わせて作っておくが吉。
    • CREATE SUBSCRIPTIONの購読先を指定する。このときには先だって作成していたロジカルレプリケーション元を指定する。

検証モデル

今回は同一Linuxマシン上にport=5432とport=5433の2つのデータベースクラスタを作成してそれを起動し、port=5432側(srv1)のtestdb内のjapan表をport=5433側(srv2)へ論理レプリケーションするモデルにした。
また、このモデルにより、町田問題が解決するのかを検証した。

検証その1

srv1側

まず、何も考えずテーブルを定義する(これが後で後悔する原因となる)。

CREATE TABLE japan (id int, pref text, city text, data text);
CREATE PUBLICATION pub_srv1_testdb_japan FOR TABLE japan;

2行目がレプリケーション元となるテーブルを指定するためのPUBLICATION構文である。

srv2側

レプリケーションの受け側でも、テーブルは同じように作成しておく。
レプリケーションの受け側ではPUBLICATION ではなく、SUBSCRIPTIONを作成する。

testdb=# CREATE TABLE japan (id int, pref text, city text, data text);
CREATE TABLE
testdb=# CREATE SUBSCRIPTION sub_srv2_testdb_japan CONNECTION 'dbname=testdb port=5432 user=postgres' PUBLICATION pub_srv1_testdb_japan;
NOTICE:  created replication slot "sub_srv2_testdb_japan" on publisher
CREATE SUBSCRIPTION

SUBSCRIPTIONのPUBLICATION句には、既に存在しているPUBLICATIONを指定する必要がある(が、存在チェックとかは今のところしてなさそう?)。
また、SUBSCRIPTIONに指定する名前と同じ名前のものが、レプリケーション送り元に生成されるっぽい。

これでjapanテーブルの内容がレプリケーションされるはず。

挿入内容をレプリケーションする

srv1側のjapanテーブルにINSERT文で挿入してみる。

testdb=# INSERT INTO japan VALUES (1, '東京', '大田', 'らーめん 潤');
INSERT 0 1
testdb=# INSERT INTO japan VALUES (2, '神奈川', '横浜', '麺恋亭');
INSERT 0 1
testdb=# TABLE japan;
 id |  pref  | city |    data
----+--------+------+-------------
  1 | 東京   | 大田 | らーめん 潤
  2 | 神奈川 | 横浜 | 麺恋亭
(2 rows)

srv2側のjapanテーブルを参照してみよう。

testdb=# SELECT * FROM japan;
 id |  pref  | city |    data
----+--------+------+-------------
  1 | 東京   | 大田 | らーめん 潤
  2 | 神奈川 | 横浜 | 麺恋亭
(2 rows)

やったね♪ きちんとsrv2側にも反映されました。

さて、ここでpgdata2のjapanにデータを挿入してみます。

testdb=# INSERT INTO japan VALUES (3, '神奈川', '町田', '竹之助');
INSERT 0 1
testdb=# TABLE japan;
 id |  pref  | city |    data
----+--------+------+-------------
  1 | 東京   | 大田 | らーめん 潤
  2 | 神奈川 | 横浜 | 麺恋亭
  3 | 神奈川 | 町田 | 竹之助
(3 rows)

prefが神奈川でcityが町田。何か間違ってるっけ?

ストリーミングレプリケーションとは異なり、反映先のテーブルにもフツーに挿入できます。これがロジカルレプリケーションの面白いところ。

さて、この状態でsrv1に、以下のようなINSERT文を使って挿入してみます。

testdb=# INSERT INTO japan VALUES (3, '神奈川', '町田', '竹之助');
INSERT 0 1
testdb=# TABLE japan;
 id |  pref  | city |    data
----+--------+------+-------------
  1 | 東京   | 大田 | らーめん 潤
  2 | 神奈川 | 横浜 | 麺恋亭
  3 | 神奈川 | 町田 | 竹之助
(3 rows)

あれ、フツーに挿入されちゃったよ。
この状態でsrv2側のjapanテーブルを参照してみると

testdb=# TABLE japan;
 id |  pref  | city |    data
----+--------+------+-------------
  1 | 東京   | 大田 | らーめん 潤
  2 | 神奈川 | 横浜 | 麺恋亭
  3 | 神奈川 | 町田 | 竹之助
  3 | 神奈川 | 町田 | 竹之助
(4 rows)

あ・・・これなんかアカンやつだw

TRUNCATEしてみる

とりあえず、きれいな状態に戻したいので、srv1側でTRUNCATEしてみる。

testdb=# TRUNCATE japan;
TRUNCATE TABLE
testdb=# TABLE japan;
 id | pref | city | data
----+------+------+------
(0 rows)

で、srv2側のjapanテーブルを参照してみると・・・

testdb=# TABLE japan;
 id |  pref  | city |    data
----+--------+------+-------------
  1 | 東京   | 大田 | らーめん 潤
  2 | 神奈川 | 横浜 | 麺恋亭
  3 | 神奈川 | 町田 | 竹之助
  3 | 神奈川 | 町田 | 竹之助
(4 rows)

(ノ∀`)アチャー
どうやら、現状はTRUNCATEはロジカルレプリケーションの対象になっていないようだ。
なので、TRUNCATEをかける場合には、レプリケーション元であるsrv1にもレプリケーション先であるsrv2の両方にTRUNCATEをかける必要があるようだ。めんどくせえ。
ぬーん、TRUNCATEのWALって出力されているはずなのに。
まあ、まだ開発中のバージョンだし、このへんは今後改善されていくと思います。
仕方ないのでpgdata2側も手動でTRUNCATEする。

testdb=# TRUNCATE japan;
TRUNCATE TABLE
testdb=# TABLE japan;
 id | pref | city | data
----+------+------+------
(0 rows)

COPYでバルクロードしてみる

srv1のjapanテーブルに対して、以下のようなデータをCOPYでバルクロードする。

$ cat /tmp/japan.txt
1       東京    品川    丸直
2       東京    八丈島  蓮華
3       静岡    熱海    雨風本舗
4       静岡    藤枝    池田屋
5       神奈川  横浜    麺恋亭
6       神奈川  横浜    吉村家
7       神奈川  川崎    クマさん
8       神奈川  川崎    ニュータンタン本舗 本店
9       神奈川  町田    竹の助

testdb=# COPY japan FROM '/tmp/japan.txt';
COPY 9
testdb=# TABLE japan;
 id |  pref  |  city  |          data
----+--------+--------+-------------------------
  1 | 東京   | 品川   | 丸直
  2 | 東京   | 八丈島 | 蓮華
  3 | 静岡   | 熱海   | 雨風本舗
  4 | 静岡   | 藤枝   | 池田屋
  5 | 神奈川 | 横浜   | 麺恋亭
  6 | 神奈川 | 横浜   | 吉村家
  7 | 神奈川 | 川崎   | クマさん
  8 | 神奈川 | 川崎   | ニュータンタン本舗 本店
  9 | 神奈川 | 町田   | 竹の助
(9 rows)

COPYもフツーに出来ますね。
この状態でsrv2側も参照してみる。

testdb=# TABLE japan;
 id |  pref  |  city  |          data
----+--------+--------+-------------------------
  1 | 東京   | 品川   | 丸直
  2 | 東京   | 八丈島 | 蓮華
  3 | 静岡   | 熱海   | 雨風本舗
  4 | 静岡   | 藤枝   | 池田屋
  5 | 神奈川 | 横浜   | 麺恋亭
  6 | 神奈川 | 横浜   | 吉村家
  7 | 神奈川 | 川崎   | クマさん
  8 | 神奈川 | 川崎   | ニュータンタン本舗 本店
  9 | 神奈川 | 町田   | 竹の助
(9 rows)

うん。COPYも問題なく使えそう。

UPDATE

じゃあ、次はUPDATEしてみよう。
町田は東京だという妄言を吐く人が町田のprefを東京に変えようとしてUPDATE文を発行してみるが、

testdb=# UPDATE japan SET pref = '東京' WHERE id = 9;
ERROR:  cannot update table "japan" because it does not have replica identity and publishes updates
HINT:  To enable updating the table, set REPLICA IDENTITY using ALTER TABLE.
testdb=#

アバーッ!このように、更新に失敗してしまう。
これは 町田が神奈川だから更新に失敗する のではなく、replica identityというものを設定しないとUPDATEとDELETEはできないっぽい。
とりあえずid にUNIQUE INDEX張って、ALTER TABLEでREPLICA IDENTITYを設定してみるか・・・。

testdb=# CREATE UNIQUE INDEX japan_id ON japan (id);
CREATE INDEX
testdb=#

testdb=# ALTER TABLE japan REPLICA IDENTITY USING INDEX japan_id ;
ERROR:  index "japan_id" cannot be used as replica identity because column "id" is nullable
testdb=#

グワーッ!UNIQUE+NULLABLEでないといけない,つまりPrimary Keyが存在し、それをREPLICA IDENTITYに設定しないといけないのな。
一旦、テーブルと、PUBLISHER、SUBSCRIBEを作り直すか・・・

PUBLISHERとSUBSCRIBEの削除

とりあえずsrv1側のjapanテーブルを削除してみる。

testdb=# DROP TABLE japan CASCADE ;
DROP TABLE
testdb=# 

これでPUBLICATIONも消えるのかな・・・と思ったら消えてない。

testdb=# TABLE pg_publication;
        pubname        | pubowner | puballtables | pubinsert | pubupdate | pubdelete
-----------------------+----------+--------------+-----------+-----------+-----------
 pub_srv1_testdb_japan |       10 | f            | t         | t         | t
(1 row)

どうやら、PUBLISHERはテーブルとは依存関係にはないようだ。
あれかなー、PCREATE PUBLICATIONは、対象が表だけじゃなくてDB全体とか指定ができたりするからかな。

仕方ないからDROP PUBLICATIONで削除する。

testdb=# DROP PUBLICATION pub_srv1_testdb_japan;
DROP PUBLICATION
testdb=# TABLE pg_publication;
 pubname | pubowner | puballtables | pubinsert | pubupdate | pubdelete
---------+----------+--------------+-----------+-----------+-----------
(0 rows)

pgdata2側のTABLEとSUBSCRIBERも同様に削除する。

testdb=# DROP SUBSCRIPTION sub_srv2_testdb_japan;
NOTICE:  dropped replication slot "sub_srv2_testdb_japan" on publisher
DROP SUBSCRIPTION
testdb=# DROP TABLE japan ;
DROP TABLE
testdb=# TABLE pg_subscription;
 subdbid | subname | subowner | subenabled | subconninfo | subslotname | subpublications
---------+---------+----------+------------+-------------+-------------+-----------------
(0 rows)

SUBSCRIPTIONを削除すると、publisher(pgdata1側)の同名slotも削除されるようだ。

とりあえずこれで仕切り直しだ。

検証2 - primary key制約付きの表で再作成

japanテーブルのidをprimary keyとするようにして再定義してみる。

testdb=# CREATE TABLE japan (id int, pref text, city text, data text);
CREATE TABLE
testdb=# CREATE UNIQUE INDEX japan_id ON japan (id);
CREATE INDEX
testdb=# ALTER TABLE japan ADD PRIMARY KEY USING INDEX japan_id ;
ALTER TABLE
testdb=#

え、なんでid intの定義にprimary key を指定しないかだって?
それはPostgreSQL 10のパーティションテーブルにprimary keyが設定できないからだよっ!(後々、パーティションの一部のテーブルだけロジカルレプリケーションするという検証をしたいので)

それはさておき、PUBLICATIONを再度設定してみる。

CREATE PUBLICATION pub_srv1_testdb_japan FOR TABLE japan;

pgdata2側も同じようにテーブル定義、インデックス定義、プライマリキー定義をしておく。

testdb=# CREATE TABLE japan (id int, pref text, city text, data text);
CREATE TABLE
testdb=# CREATE UNIQUE INDEX japan_id ON japan (id);
CREATE INDEX
testdb=# ALTER TABLE japan ADD PRIMARY KEY USING INDEX japan_id ;
ALTER TABLE
testdb=#

で、SUBSCRIPTIONを再度定義する。

CREATE SUBSCRIPTION sub_srv2_testdb_japan CONNECTION 'dbname=testdb port=5432 user=postgres' PUBLICATION pub_srv1_testdb_japan;
testdb=# CREATE SUBSCRIPTION sub_srv2_testdb_japan CONNECTION 'dbname=testdb port=5432 user=postgres' PUBLICATION pub_srv1_testdb_japan;
NOTICE:  created replication slot "sub_srv2_testdb_japan" on publisher
CREATE SUBSCRIPTION
testdb=#

UPDATE再検証

さっきと同じようにsrv1のjapanテーブルに対してCOPYでデータをロードしておく。
ロード後にsrv1はこうなっている。

testdb=# TABLE japan;
 id |  pref  |  city  |          data
----+--------+--------+-------------------------
  1 | 東京   | 品川   | 丸直
  2 | 東京   | 八丈島 | 蓮華
  3 | 静岡   | 熱海   | 雨風本舗
  4 | 静岡   | 藤枝   | 池田屋
  5 | 神奈川 | 横浜   | 麺恋亭
  6 | 神奈川 | 横浜   | 吉村家
  7 | 神奈川 | 川崎   | クマさん
  8 | 神奈川 | 川崎   | ニュータンタン本舗 本店
  9 | 神奈川 | 町田   | 竹の助
(9 rows)

少し経つと、srv2側のjapanテーブルにも更新内容が伝播されているのがわかる。

testdb=# TABLE japan;
 id |  pref  |  city  |          data
----+--------+--------+-------------------------
  1 | 東京   | 品川   | 丸直
  2 | 東京   | 八丈島 | 蓮華
  3 | 静岡   | 熱海   | 雨風本舗
  4 | 静岡   | 藤枝   | 池田屋
  5 | 神奈川 | 横浜   | 麺恋亭
  6 | 神奈川 | 横浜   | 吉村家
  7 | 神奈川 | 川崎   | クマさん
  8 | 神奈川 | 川崎   | ニュータンタン本舗 本店
  9 | 神奈川 | 町田   | 竹の助
(9 rows)

とりあえずUPDATEできるか再確認する。
pgdata2側も更新が伝播されてますねー。

testdb=# SELECT * FROM japan WHERE id = 9;
 id | pref | city |  data
----+------+------+--------
  9 | 東京 | 町田 | 竹の助
(1 row)

町田は東京に奪われました・・・ぐぬぬ。

重複エラーとなるINSERT

pgdata1からキー重複のあるINSERTももちろん、エラーになる。

testdb=# INSERT INTO japan VALUES (9, '神奈川', '町田', '竹之助');
ERROR:  duplicate key value violates unique constraint "japan_id"
DETAIL:  Key (id)=(9) already exists.
testdb=#

pgdata2から挿入しても同様。

testdb=# INSERT INTO japan VALUES (9, '神奈川', '町田', '竹之助');
ERROR:  duplicate key value violates unique constraint "japan_id"
DETAIL:  Key (id)=(9) already exists.
testdb=#

DELETE

こんなに苦しいのなら悲しいのなら……町田などいらぬ!というわけではないのだが、DELETEもやってみる。
が、今回はちょいと一捻り。

まずBEGINしてDELETEする。
そうするとpgdata1上はもちろんこうなる。

testdb=# BEGIN;
BEGIN
testdb=# DELETE FROM japan WHERE id = 9;
DELETE 1
testdb=# SELECT * FROM japan WHERE id = 9;
 id | pref | city | data
----+------+------+------
(0 rows)

では、このときにpgdata2上はどう見えてみるのか。

はい、もちろんCOMMITされていない=WALを生成していないのでpgdata2上は削除されていない。

testdb=# SELECT * FROM japan WHERE id = 9;
 id | pref | city |  data
----+------+------+--------
  9 | 東京 | 町田 | 竹の助
(1 row)

testdb=#

で、このときに、pgdata2上で町田の店を削除してCOMMITし、その後にpgdata1側をCOMMITするとどうなるのか。

testdb=# COMMIT;
COMMIT
testdb=#

pgdata1側でCOMMITしてみる。

testdb=# COMMIT;
COMMIT
testdb=#

あらら、この場合はしれっと両方とも削除とCOMMITに成功しちゃいますね。
なんかイヤーンな感じ。

挿入のコンフリクト

さて、現在はpgdata1→pgdata2の片方向のレプリケーションしか設定していない。しかし、pgdata2側のjapanは更新可能である。
では、両方の更新がコンフリクトしたらどうなるのか。
これはなかなか面倒そうな話ですねー。
コンフリクト検証は別途、みっちりやらねばと思うけど、とりあえず、簡単なケースを今回は1つだけやってみる。
INSERT時のキーが重複するようなケースだ。

まず、srv2側(反映先)のトランザクションを先にINSERTまで実施する。

testdb=# BEGIN;
BEGIN
testdb=# INSERT INTO japan VALUES (9, '東京都', '町田', 'RA-MEN 3SO');
INSERT 0 1
testdb=# SELECT * FROM japan WHERE id = 9;
 id |  pref  | city |    data
----+--------+------+------------
  9 | 東京都 | 町田 | RA-MEN 3SO
(1 row)

その後に、pgdata1側のトランザクションでINSERTまで実施する。

testdb=# BEGIN;
BEGIN
testdb=# INSERT INTO japan VALUES (9, '神奈川', '町田', 'RA-MEN 3SO');
INSERT 0 1
testdb=# SELECT * FROM japan WHERE id = 9;
 id |  pref  | city |    data
----+--------+------+------------
  9 | 神奈川 | 町田 | RA-MEN 3SO
(1 row)

この状態で、pgdata2側がコミットする。

testdb=# COMMIT;
COMMIT
testdb=# SELECT * FROM japan WHERE id = 9;
 id |  pref  | city |    data
----+--------+------+------------
  9 | 東京都 | 町田 | RA-MEN 3SO
(1 row)

pgdata1側がその後にコミットする

testdb=# COMMIT;
COMMIT
testdb=#

ふむ。
srv2側を見ると、

testdb=# SELECT * FROM srv WHERE id = 9;
 id |  pref  | city |    data
----+--------+------+------------
  9 | 東京都 | 町田 | RA-MEN 3SO
(1 row)

げげ、レプリケーションが破綻しとるがなw

testdb=# INSERT INTO japan VALUES (10, '山梨', '大月', '喜楽');
INSERT 0 1
testdb=# SELECT * FROM japan WHERE id = 10;
 id | pref | city | data
----+------+------+------
 10 | 山梨 | 大月 | 喜楽
(1 row)

この後にpgdata2側

testdb=# SELECT * FROM japan WHERE id = 10;
 id | pref | city | data
----+------+------+------
(0 rows)

を参照してみるが、レプリケーションされてない。
srv1側には実はこんなエラーがしれっと出ている。

2017-02-19 19:10:39.583 JST [7842] LOG:  starting logical decoding for slot "sub_srv2_testdb_japan"
2017-02-19 19:10:39.583 JST [7842] DETAIL:  streaming transactions committing after 0/16A0920, reading WAL from 0/16A0340
2017-02-19 19:10:39.583 JST [7842] LOG:  logical decoding found consistent point at 0/16A0340
2017-02-19 19:10:39.583 JST [7842] DETAIL:  There are no running transactions.
2017-02-19 19:10:39.585 JST [7842] LOG:  could not receive data from client: Connection reset by peer
2017-02-19 19:10:39.585 JST [7842] LOG:  unexpected EOF on standby connection

また、srv2側には実はこんなエラーがしれっと出ている。

2017-02-19 19:10:39.584 JST [7841] ERROR:  duplicate key value violates unique constraint "japan_id"
2017-02-19 19:10:39.584 JST [7841] DETAIL:  Key (id)=(9) already exists.
2017-02-19 19:10:39.585 JST [7108] LOG:  worker process: logical replication worker for subscription 16406 (PID 7841) exited with exit code 1
2017-02-19 19:10:44.586 JST [7115] LOG:  starting logical replication worker for subscription "sub_srv2_testdb_japan"
2017-02-19 19:10:44.588 JST [7847] LOG:  logical replication apply for subscription "sub_srv2_testdb_japan" has started
2017-02-19 19:10:44.592 JST [7847] ERROR:  duplicate key value violates unique constraint "japan_id"
2017-02-19 19:10:44.592 JST [7847] DETAIL:  Key (id)=(9) already exists.

さて、この状態からどうやって復旧するんだろう・・・

testdb=# SELECT * FROM japan WHERE id = 9;
 id |  pref  | city |    data
----+--------+------+------------
  9 | 東京都 | 町田 | RA-MEN 3SO
(1 row)

さて、このエラーだが、これは 東京が不当に町田を所有しているからエラー ・・・になるのではなく、id=9の行がpgdata2側に存在するために、pgdata1側のid=9のINSERTが成功せず、その後のINSERTも反映を待っている、ということなんだろう。
なので、pgdata2のid=9の行を削除する。

DELETE直後にみると

testdb=# SELECT * FROM japan WHERE id = 9;
 id | pref | city | data
----+------+------+------
(0 rows)

あれ?行がない。
が、ほんのすこし経過すると、

testdb=# SELECT * FROM japan WHERE id = 9;
 id |  pref  | city |    data
----+--------+------+------------
  9 | 神奈川 | 町田 | RA-MEN 3SO
(1 row)

testdb=# SELECT * FROM japan WHERE id = 10;
 id | pref | city | data
----+------+------+------
 10 | 山梨 | 大月 | 喜楽
(1 row)

pgdata1側のid=9のINSERTが反映され、その後のid=10のINSERTも反映される。
おもしろーい!

これから検証すること。

  • マルチマスタ構成
  • 様々なコンフリクト
  • パーティションとの組み合わせ
    これはいろいろ試しがいのある機能だぜ・・・。

まとめ

  • ロジカルレプリケーションではテーブル単位にレプリケーション対象が指定可能。
  • 反映元ではCREATE PUBLICAGTIONコマンドを実行させること。
  • 反映先では、CREATE SUBSCRIPTIONコマンドを実行させること。
  • 現状はTRUNCATEはロジカルレプリケーションはきちんと動作しないよ。要検証。
  • 反映元のテーブルにはPK相当を持たせること。でないとUPDATEやDELETEができなくなる。
  • 反映先へ更新がある場合、レプリケーション接続が切れるケースがある。要注意。
  • 挙動が変な場合、サーバログを確認すべし。
  • 町田は神奈川。
22
18
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?