前書き
本番用にアプリケーションを設定する場合、データベースの複数のコピーを配置しておくと便利なことがよくあります。 データベースコピーの同期を維持するプロセスは、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-masterとdb-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-masterとdb-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に正常に複製されました。 今後、すべてのINSERT
、UPDATE
、および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-masterとdb-replicaの間に不一致のテーブル名またはフィールドがあります。
-
sammy
データベースロールに、db-master上のexample
データベースにアクセスするために必要な権限がありません。 -
sammy
データベースロールにdb-masterのREPLICATION
オプションがありません。 -
sammy
データベースロールに、db-masterのwidgets
テーブルにアクセスするために必要な権限がありません。 -
テーブルはdb-masterのパブリケーションに追加されませんでした。
既存の問題を解決した後、複製が自動的に行われます。 そうでない場合は、次のコマンドを使用して既存のサブスクリプションを削除してから、再作成します。
DROP SUBSCRIPTION my_subscription;
結論
このチュートリアルでは、2つのUbuntu 18.04サーバーにPostgreSQL 10を正常にインストールし、それらの間の論理レプリケーションを構成しました。
これで、レプリカサーバーを追加して、水平読み取りスケーリング、高可用性、PostgreSQLデータベースの地理的分布を試すために必要な知識が得られました。
PostgreSQL 10での論理レプリケーションの詳細については、PostgreSQLの公式ドキュメントのchapter on the topicと、CREATE PUBLICATION
およびCREATE SUBSCRIPTION
コマンドの手動エントリを参照してください。