Ubuntu 18.04でPostgreSQL 10を使用して論理レプリケーションをセットアップする方法

前書き

本番用にアプリケーションを設定する場合、データベースの複数のコピーを配置しておくと便利なことがよくあります。 データベースコピーの同期を維持するプロセスは、replicationと呼ばれます。 レプリケーションは、大量の同時読み取り操作に対して高可用性の水平スケーリングを提供し、読み取りレイテンシーを削減します。 また、地理的に分散したデータベースサーバー間でのピアツーピアレプリケーションも可能です。

PostgreSQLは、高度に拡張可能で、ACID(Atomicity、Consistency、Isolation、Durability)およびSQL標準に準拠したオープンソースのオブジェクトリレーショナルデータベースシステムです。 PostgreSQLのバージョン10.0では、physical replicationに加えて、logical replicationのサポートが導入されました。 論理レプリケーションスキームでは、高レベルの書き込み操作がmasterデータベースサーバーから1つ以上のreplicaデータベースサーバーにストリーミングされます。 物理レプリケーションスキームでは、代わりにバイナリ書き込み操作がマスターからレプリカにストリーミングされ、元のコンテンツのバイト単位の正確なコピーが生成されます。 オフロードレポート、パッチ適用、アップグレードなど、データの特定のサブセットを対象とする場合、論理レプリケーションは速度と柔軟性を提供します。

このチュートリアルでは、2つのUbuntu 18.04サーバーでPostgreSQL 10を使用して論理レプリケーションを構成します。一方のサーバーはマスターとして機能し、他方のサーバーはレプリカとして機能します。 チュートリアルの終わりまでに、論理レプリケーションを使用して、マスターサーバーからレプリカにデータをレプリケートできるようになります。

前提条件

このチュートリアルを実行するには、次のものが必要です。

  • 2つのUbuntu18.04サーバー(db-masterdb-replicaという名前を付けます)は、それぞれ通常のユーザーアカウントとsudo権限でセットアップされます。 これらを設定するには、this initial server setup tutorialに従います。

  • サーバー上のPrivate networking enabled。 プライベートネットワーキングを使用すると、データベースをパブリックインターネットに公開することに伴うセキュリティリスクなしにサーバー間の通信が可能になります。

  • How To Install and Use PostgreSQL on Ubuntu 18.04のステップ1に従って、両方のサーバーにPostgreSQL10がインストールされました。

[[step-1 -—- configuring-postgresql-for-logical-replication]] ==ステップ1—論理レプリケーション用のPostgreSQLの設定

サーバー間の論理複製を有効にするために変更する必要があるいくつかの構成設定があります。 まず、パブリックネットワーク経由でデータを公開することはセキュリティリスクであるため、パブリックインターフェイスではなくプライベートネットワークインターフェイスでリッスンするようにPostgresを構成します。 次に、db-replicaへのレプリケーションを許可するように適切な設定を構成します。

db-masterで、メインサーバー構成ファイルである/etc/postgresql/10/main/postgresql.confを開きます。

sudo nano /etc/postgresql/10/main/postgresql.conf

次の行を見つけます。

/etc/postgresql/10/main/postgresql.conf

...
#listen_addresses = 'localhost'         # what IP address(es) to listen on;
...

#を削除してコメントを解除し、db_master_private_ip_addressを追加してプライベートネットワークでの接続を有効にします。

[.note]#Note:この手順とそれに続く手順では、サーバーのパブリックIPではなく、サーバーのprivateIPアドレスを使用してください。 データベースサーバーをパブリックインターネットに公開することは、かなりのセキュリティリスクです。

/etc/postgresql/10/main/postgresql.conf

...
listen_addresses = 'localhost, db_master_private_ip_address'
...

これにより、db-masterは、ループバックインターフェイスに加えて、プライベートネットワーク上の着信接続をリッスンします。

次に、次の行を見つけます。

/etc/postgresql/10/main/postgresql.conf

...
#wal_level = replica                    # minimal, replica, or logical
...

コメントを外し、PostgreSQLのWrite Ahead Log(WAL)レベルをlogicalに設定するように変更します。 これにより、ログ内のエントリの量が増え、特定のデータセットの不一致または変更を抽出するために必要な情報が追加されます。

/etc/postgresql/10/main/postgresql.conf

...
wal_level = logical
...

このログのエントリはレプリカサーバーによって消費され、マスターからの高レベルの書き込み操作の複製が可能になります。

ファイルを保存して閉じます。

次に、許可されたホスト、認証、およびデータベースへのアクセスを制御するファイルである/etc/postgresql/10/main/pg_hba.confを編集しましょう。

sudo nano /etc/postgresql/10/main/pg_hba.conf

最後の行の後に、db-replicaからの着信ネットワーク接続を許可する行を追加しましょう。 db-replicaのプライベートIPアドレスを使用し、すべてのユーザーとデータベースからの接続を許可するように指定します。

/etc/postgresql/10/main/pg_hba.conf

...
# TYPE      DATABASE        USER            ADDRESS                               METHOD
...
host         all            all             db_replica_private_ip_address/32      md5

着信ネットワーク接続は、パスワードハッシュ(md5)によって認証されたdb-replicaから許可されるようになります。

ファイルを保存して閉じます。

次に、db-replicaからdb-masterのポート5432へのトラフィックを許可するようにファイアウォールルールを設定しましょう。

sudo ufw allow from db_replica_private_ip_address to any port 5432

最後に、PostgreSQLサーバーを再起動して、変更を有効にします。

sudo systemctl restart postgresql

論理レプリケーションを許可するように構成を設定したら、データベース、ユーザーロール、およびテーブルの作成に進むことができます。

[[step-2 -—- setting-up-a-database-user-role-and-table]] ==ステップ2—データベース、ユーザーロール、およびテーブルの設定

レプリケーション設定の機能をテストするために、データベース、テーブル、ユーザーロールを作成しましょう。 サンプルテーブルを使用してexampleデータベースを作成します。これを使用して、サーバー間の論理レプリケーションをテストできます。 また、専用ユーザーを作成し、データベースとテーブルの両方に対する特権を割り当てます。

まず、db-masterdb-replicaの両方で次のコマンドを使用して、postgresユーザーとしてpsql promptを開きます。

sudo -u postgres psql
sudo -u postgres psql

両方のホストにexampleという名前の新しいデータベースを作成します。

CREATE DATABASE example;
CREATE DATABASE example;

[.note]#Note:これらのコマンドの最後の;は必須です。 対話型セッションでは、PostgreSQLはセミコロンで終了するまでSQLコマンドを実行しません。 メタコマンド(\q\cなどのバックスラッシュで始まるコマンド)は、psqlクライアント自体を直接制御するため、このルールは免除されます。 メタコマンドとpsqlクライアントの詳細については、PostgreSQL documentation
#を参照してください。

\connectメタコマンドを使用して、各ホストで作成したデータベースに接続します。

\c example
\c example

両方のホストに任意のフィールドを持つwidgetsという名前の新しいテーブルを作成します。

CREATE TABLE widgets
(
    id SERIAL,
    name TEXT,
    price DECIMAL,
    CONSTRAINT widgets_pkey PRIMARY KEY (id)
);
CREATE TABLE widgets
(
    id SERIAL,
    name TEXT,
    price DECIMAL,
    CONSTRAINT widgets_pkey PRIMARY KEY (id)
);

db-replicaのテーブルは、対応するdb-masterと同一である必要はありません。 ただし、テーブルのdb-masterに存在するすべての列が含まれている必要があります。 追加の列には、NOT NULLまたはその他の制約があってはなりません。 実行すると、レプリケーションは失敗します。

db-masterで、REPLICATIONオプションとログインパスワードを使用して新しいユーザーロールを作成しましょう。 REPLICATION属性は、レプリケーションに使用されるすべてのロールに割り当てる必要があります。 ユーザーをsammyと呼びますが、これを独自のユーザー名に置き換えることができます。 my_passwordも必ず独自の安全なパスワードに置き換えてください。

CREATE ROLE sammy WITH REPLICATION LOGIN PASSWORD 'my_password';

後でdb-replicaを使用してレプリケーションを設定するため、パスワードをメモしておきます。

引き続きdb-masterで、作成したばかりのユーザーロールにexampleデータベースに対する完全な特権を付与します。

GRANT ALL PRIVILEGES ON DATABASE example TO sammy;

次に、データベースに含まれるすべてのテーブルに対する特権をユーザーに付与します。

GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO sammy;

public schemaは、テーブルが自動的に配置される各データベースのデフォルトスキーマです。

これらの権限を設定すると、exampleデータベース内のテーブルをレプリケーションで使用できるようにすることに進むことができます。

[[step-3 -—- setting-up-a-publication]] ==ステップ3—パブリケーションの設定

Publicationsは、PostgreSQLがテーブルをレプリケーションに使用できるようにするために使用するメカニズムです。 データベースサーバーは、特定のパブリケーションに関連付けられたレプリカサーバーの接続およびレプリケーションステータスを内部的に追跡します。 db-masterで、subscribersに送信されるデータのマスターコピーとして機能するパブリケーションmy_publicationを作成します。この場合はdb-replicaです。 。

db-masterで、my_publicationというパブリケーションを作成します。

CREATE PUBLICATION my_publication;

以前に作成したwidgetsテーブルを追加します。

ALTER PUBLICATION my_publication ADD TABLE widgets;

パブリケーションを配置したら、そこからデータをプルするサブスクライバーを追加できます。

[[ステップ-4 -—-サブスクリプションの作成]] ==ステップ4—サブスクリプションの作成

Subscriptionsは、既存のパブリケーションに接続するためにPostgreSQLによって使用されます。 パブリケーションは、異なるレプリカサーバー間で多くのサブスクリプションを持つことができ、レプリカサーバーはサブスクライバーとの独自のパブリケーションを持つこともできます。 db-masterで作成したテーブルのデータにアクセスするには、前の手順で作成したパブリケーションmy_publicationのサブスクリプションを作成する必要があります。

db-replicaで、my_subscriptionというサブスクリプションを作成しましょう。 CREATE SUBSCRIPTIONコマンドはサブスクリプションに名前を付け、CONNECTIONパラメーターはパブリッシャーへの接続文字列を定義します。 この文字列には、マスターサーバーの接続の詳細とログイン資格情報が含まれます。これには、前に定義したユーザー名とパスワード、およびexampleデータベースの名前が含まれます。 繰り返しになりますが、db-masterのプライベートIPアドレスを使用し、my_passwordを自分のパスワードに置き換えることを忘れないでください。

CREATE SUBSCRIPTION my_subscription CONNECTION 'host=db_master_private_ip_address port=5432 password=my_password user=sammy dbname=example' PUBLICATION my_publication;

サブスクリプションを確認する次の出力が表示されます。

OutputNOTICE:  created replication slot "my_subscription" on publisher
CREATE SUBSCRIPTION

サブスクリプションを作成すると、PostgreSQLは既存のデータをマスターからレプリカに自動的に同期します。 この場合、widgetsテーブルが空であるため、同期するデータはありませんが、これは、既存のデータベースに新しいサブスクリプションを追加するときに便利な機能です。

サブスクリプションを設定したら、widgetsテーブルにデモデータを追加してセットアップをテストしましょう。

[[ステップ-5 ---テストとトラブルシューティング]] ==ステップ5—テストとトラブルシューティング

マスターとレプリカ間のレプリケーションをテストするために、widgetsテーブルにデータを追加して、正しくレプリケートされることを確認しましょう。

db-masterで、次のデータをwidgetsテーブルに挿入します。

INSERT INTO widgets (name, price) VALUES ('Hammer', 4.50), ('Coffee Mug', 6.20), ('Cupholder', 3.80);

db-replicaで、次のクエリを実行して、このテーブルのすべてのエントリをフェッチします。

SELECT * FROM widgets;

次のように表示されます。

Output id |    name    | price
----+------------+-------
  1 | Hammer     |  4.50
  2 | Coffee Mug |  6.20
  3 | Cupholder  |  3.80
(3 rows)

成功! エントリはdb-masterからdb-replicaに正常に複製されました。 今後、すべてのINSERTUPDATE、およびDELETEのクエリは、サーバー間で一方向に複製されます。

レプリカサーバーでの書き込みクエリに関する注意点の1つは、それらがマスタサーバーに複製されないことです。 PostgreSQLは現在、サーバー間のデータが異なる場合の競合を解決するための限定的なサポートを提供しています。 競合がある場合、レプリケーションは停止し、PostgreSQLはデータベース管理者が手動で問題を修正するまで待機します。 そのため、ほとんどのアプリケーションはすべての書き込み操作をマスターサーバーに指示し、読み取りを利用可能なレプリカサーバーに分散します。

これで、両方のサーバーでpsqlプロンプトを終了できます。

\q
\q

セットアップのテストが終了したので、自分でデータを追加および複製できます。

トラブルシューティング

レプリケーションが機能していないように思われる場合、最初のステップとして、db-replicaのPostgreSQLログでエラーの可能性を確認することをお勧めします。

tail /var/log/postgresql/postgresql-10-main.log

レプリケーションが機能しなくなる一般的な問題を次に示します。

  • プライベートネットワークが両方のサーバーで有効になっていないか、サーバーが異なるネットワークにあります。

  • db-masterは、正しいプライベートネットワークIPで接続をリッスンするように構成されていません。

  • db-masterの先行書き込みログレベルが正しく構成されていません(logicalに設定する必要があります)。

  • db-masterは、正しいdb-replicaプライベートIPアドレスからの着信接続を受け入れるように構成されていません。

  • UFWのようなファイアウォールは、ポート5432で着信PostgreSQL接続をブロックしています。

  • db-masterdb-replicaの間に不一致のテーブル名またはフィールドがあります。

  • sammyデータベースロールに、db-master上のexampleデータベースにアクセスするために必要な権限がありません。

  • sammyデータベースロールにdb-masterREPLICATIONオプションがありません。

  • sammyデータベースロールに、db-masterwidgetsテーブルにアクセスするために必要な権限がありません。

  • テーブルはdb-masterのパブリケーションに追加されませんでした。

既存の問題を解決した後、複製が自動的に行われます。 そうでない場合は、次のコマンドを使用して既存のサブスクリプションを削除してから、再作成します。

DROP SUBSCRIPTION my_subscription;

結論

このチュートリアルでは、2つのUbuntu 18.04サーバーにPostgreSQL 10を正常にインストールし、それらの間の論理レプリケーションを構成しました。

これで、レプリカサーバーを追加して、水平読み取りスケーリング、高可用性、PostgreSQLデータベースの地理的分布を試すために必要な知識が得られました。

PostgreSQL 10での論理レプリケーションの詳細については、PostgreSQLの公式ドキュメントのchapter on the topicと、CREATE PUBLICATIONおよびCREATE SUBSCRIPTIONコマンドの手動エントリを参照してください。

Related