「レプリケーションスロット」がまだ導入されていなかった時代には、WALセグメントの管理が課題でした。標準のストリーミングレプリケーションでは、マスターはスレーブのステータスを認識していません。スタンバイノードが数時間メンテナンスモードになっているときに(システムパッケージのアップグレード、ネットワークセキュリティの調整、ハードウェアのアップグレードなど)、大規模なトランザクションを実行するマスターの例を考えてみましょう。ある時点で、マスターはチェックポイントが通過するときにトランザクションログ(WALセグメント)を削除します。スレーブがメンテナンスから外れると、スレーブのラグが大きくなり、マスターに追いつく必要があります。最終的に、スレーブは以下のような致命的な問題を抱えることになります:
LOG: started streaming WAL from primary at 0/73000000 on timeline 1
FATAL: could not receive data from WAL stream: ERROR: requested WAL segment 000000010000000000000073 has already been removed
一般的なアプローチは、postgresql.confで、WALファイルを1つ以上の長期アーカイブの場所にコピーするWALアーカイブスクリプトを指定することです。スタンバイやその他のストリーミングレプリケーションクライアントがない場合、基本的に、アーカイブスクリプトが完了するか、OKと応答すると、サーバーはWALファイルを破棄できます。ただし、クラッシュリカバリにはまだいくつかの最近のWALファイルが必要です(最近のWALファイルのデータはクラッシュリカバリ中に再生されます。長いメンテナンス期間に配置されたスタンバイノードの例では、オンラインに戻って要求するときに問題が発生しますプライマリに存在しなくなったWALファイルのプライマリの場合、レプリケーションは失敗します。
この問題は、PostgreSQL9.4で「レプリケーションスロット」を介して解決されました。
レプリケーションスロットを使用しない場合、レプリケーションが失敗するリスクを減らす一般的な方法は、必要になる可能性のあるWALファイルがローテーションまたはリサイクルされないようにwal_keep_segmentsを十分に高く設定することです。このアプローチの欠点は、セットアップに最適な値を判断するのが難しいことです。毎日のメンテナンスは必要ありません。また、ディスクストレージを消費する大量のWALファイルを保持する必要もありません。これは機能しますが、マスターのディスクスペースを危険にさらすと、着信トランザクションが失敗する可能性があるため、理想的なソリューションではありません。
レプリケーションスロットを使用しない別のアプローチは、継続的なアーカイブを使用してPostgreSQLを構成し、restore_commandを提供してレプリカにアーカイブへのアクセスを許可することです。プライマリでのWALの蓄積を回避するために、WALファイル用に別のボリュームまたはストレージデバイス(SANやNFSなど)を使用できます。もう1つは、プライマリがスタンバイノードがトランザクションをコミットするのを待機する必要があるため、同期レプリケーションの場合です。これは、WALファイルがスタンバイノードに適用されていることを保証します。ただし、それでも、プライマリからアーカイブコマンドを提供して、WALがプライマリでリサイクルされたら、回復のためにWALバックアップがあるので安心することをお勧めします。状況によっては、同期レプリケーションは、非同期レプリケーションと比較してパフォーマンスのオーバーヘッドが発生するため、理想的なソリューションではありません。
レプリケーションスロットには、2つのタイプがあります。これらは次のとおりです。
論理レプリケーションは、物理レプリケーションスロットと同じことを行い、論理レプリケーションに使用されます。ただし、これらは論理デコードに使用されます。論理デコードの背後にある考え方は、ユーザーがトランザクションログに添付し、プラグインを使用してデコードする機会を与えることです。これにより、データベースに加えられた変更、したがってトランザクションログに加えられた変更を任意の形式および目的で抽出できます。
このブログでは、物理レプリケーションスロットを使用し、ClusterControlを使用してこれを実現する方法を説明します。
レプリケーションスロットは、一度有効にすると間違いなく有益です。デフォルトでは、「レプリケーションスロット」は有効になっていないため、手動で設定する必要があります。レプリケーションスロットを使用する利点には、次のようなものがあります
- マスターは、トランザクションログがすべてのレプリカによって消費された場合にのみ、トランザクションログをリサイクルできます。ここでの利点は、スレーブがそれほど遅れることがなく、再同期が必要になることはないということです。
- 孤立したレプリケーションスロットは、マスターからのWALファイルの積み重ねにより、無制限のディスク成長を引き起こす可能性があります
- 長期間(数日や数週間など)のメンテナンスが行われ、レプリケーションスロットに関連付けられているスレーブノードでは、マスターからのWALファイルが積み重なるため、ディスクが無制限に増加します。
これを監視するには、pg_replication_slotsにクエリを実行して、使用されていないスロットを特定します。これについては後でもう一度確認します。
前述のように、レプリケーションスロットには2つのタイプがあります。このブログでは、ストリーミングレプリケーションに物理レプリケーションスロットを使用します。
maximus_db=# \df pg_create_physical_replication_slot
Schema | pg_catalog
Name | pg_create_physical_replication_slot
Result data type | record
Argument data types | slot_name name, immediately_reserve boolean DEFAULT false, OUT slot_name name, OUT xlog_position pg_lsn
Type | normal
例: slot1という名前のレプリケーションスロットを作成します
postgres=# SELECT pg_create_physical_replication_slot('slot1');
-[ RECORD 1 ]-----------------------+---------
pg_create_physical_replication_slot | (slot1,)
レプリケーションスロット名とその基礎となる構成は、システム全体のみであり、クラスター全体ではありません。たとえば、nodeA(現在のマスター)とスタンバイノードnodeBおよびnodeCがあり、マスターnodeA、つまり「slot1」にスロットを作成している場合、データはnodeBおよびnodeCで使用できません。したがって、フェイルオーバー/スイッチオーバーが発生しようとしているときは、作成したスロットを再作成する必要があります。
maximus_db=# \df pg_drop_replication_slot
Schema | pg_catalog
Name | pg_drop_replication_slot
Result data type | void
Argument data types | name
Type | normal
ドロップするのは簡単です:
maximus_db=# select pg_drop_replication_slot('slot2');
-[ RECORD 1 ]------------+-
pg_drop_replication_slot |
PostgreSQLレプリケーションスロットの監視
レプリケーションスロットの監視は、見逃したくないものです。以下のように、プライマリ/マスターノードのビューpg_replication_slotsから情報を収集するだけです。
postgres=# select * from pg_replication_slots;
-[ RECORD 1 ]-------+-----------
slot_name | main_slot
plugin |
slot_type | physical
datoid |
database |
active | t
active_pid | 16297
xmin |
catalog_xmin |
restart_lsn | 2/F4000108
confirmed_flush_lsn |
-[ RECORD 2 ]-------+-----------
slot_name | main_slot2
plugin |
slot_type | physical
datoid |
database |
active | f
active_pid |
xmin |
catalog_xmin |
restart_lsn |
confirmed_flush_lsn |
上記の結果は、main_slotが取得されたことを示していますが、main_slot2は取得されていません。
あなたができるもう一つのことは、あなたが持っているスロットからどれだけ遅れているかを監視することです。これを実現するには、以下のサンプル結果に基づくクエリを使用するだけです。
postgres=# SELECT redo_lsn, slot_name,restart_lsn,
round((redo_lsn-restart_lsn) / 1024 / 1024 / 1024, 2) AS GB_behind
FROM pg_control_checkpoint(), pg_replication_slots;
redo_lsn | slot_name | restart_lsn | gb_behind
------------+-----------+-------------+-----------
1/8D400238 | slot1 | 0/9A000000 | 3.80
ただし、redo_lsnは9.6には存在しないため、redo_locationを使用する必要があるため、9.6では
imbd=# SELECT redo_location, slot_name,restart_lsn,
round((redo_location-restart_lsn) / 1024 / 1024 / 1024, 2) AS GB_behind
FROM pg_control_checkpoint(), pg_replication_slots;
-[ RECORD 1 ]-+-----------
redo_location | 2/F6008BE0
slot_name | main_slot
restart_lsn | 2/F6008CC0
gb_behind | 0.00
-[ RECORD 2 ]-+-----------
redo_location | 2/F6008BE0
slot_name | main_slot2
restart_lsn | 2/F6008CC0
gb_behind | 0.00
レプリケーションスロットを実装するには、手動で設定する必要があります。変更が必要で、postgresql.confで指定する必要がある変数があります。以下を参照してください:
- max_replication_slots – 0に設定されている場合、これはレプリケーションスロットが完全に無効になっていることを意味します。 PostgreSQL <10バージョンを使用している場合、このスロットは0(デフォルト)以外に指定する必要があります。 PostgreSQL 10以降、デフォルトは10です。この変数はレプリケーションスロットの最大数を指定します。現在存在するレプリケーションスロットの数よりも低い値に設定すると、サーバーを起動できなくなります。
- wal_level –少なくともレプリカ以上である必要があります(レプリカがデフォルトです)。 hot_standbyまたはarchiveを設定すると、レプリカにマップされます。物理レプリケーションスロットの場合、レプリカで十分です。論理レプリケーションスロットの場合、論理が優先されます。
- max_wal_senders –デフォルトで10に設定されています。9.6バージョンでは0に設定されています。これは、レプリケーションが無効になっていることを意味します。特にClusterControlで実行する場合は、これを少なくとも16に設定することをお勧めします。
- hot_standby –バージョン<10では、これをデフォルトでオフに設定する必要があります。これはスタンバイノードにとって重要です。つまり、オンの場合、リカバリ中またはスタンバイモードで接続してクエリを実行できます。
- primary_slot_name –この変数は、スタンバイノードのrecovery.confを介して設定されます。これは、送信者(またはプライマリ/マスター)と接続するときに受信者またはスタンバイノードが使用するスロットです。
これらの変数は、ほとんどの場合、新しい値を再ロードするためにデータベースサービスを再起動する必要があることに注意する必要があります。
ClusterControlPostgreSQL環境でのレプリケーションスロットの使用
では、物理レプリケーションスロットを使用して、ClusterControlによって管理されるPostgresセットアップ内に実装する方法を見てみましょう。
PostgreSQLデータベースノードの導入
今回は、PostgreSQL9.6バージョンを使用したClusterControlを使用した3ノードのPostgreSQLクラスターのデプロイを開始しましょう。
ClusterControlは、デフォルトに基づいて定義された次のシステム変数を使用してノードをデプロイしますまたは調整された値。で:
postgres=# select name, setting from pg_settings where name in ('max_replication_slots', 'wal_level', 'max_wal_senders', 'hot_standby');
name | setting
-----------------------+---------
hot_standby | on
max_replication_slots | 0
max_wal_senders | 16
wal_level | replica
(4 rows)
[email protected]:~# grep 'max_replication_slots' /etc/postgresql/9.6/main/postgresql.conf
# max_replication_slots = 0 # max number of replication slots
max_replication_slots = 5
[email protected]:~# pg_lsclusters
Ver Cluster Port Status Owner Data directory Log file
9.6 main 5432 online postgres /var/lib/postgresql/9.6/main pg_log/postgresql-%Y-%m-%d_%H%M%S.log
[email protected]:~# pg_ctlcluster 9.6 main restart
ClusterControlにはこれを行うオプションがないため、スロットを手動で作成する必要があります。この例では、ホスト192.168.30.100のプライマリにスロットを作成しました:
192.168.10.100:5432 [email protected]_db=# SELECT pg_create_physical_replication_slot('slot1'), pg_create_physical_replication_slot('slot2');
pg_create_physical_replication_slot | pg_create_physical_replication_slot
-------------------------------------+-------------------------------------
(slot1,) | (slot2,)
(1 row)
192.168.10.100:5432 [email protected]_db=# select * from pg_replication_slots;
slot_name | plugin | slot_type | datoid | database | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn
-----------+--------+-----------+--------+----------+--------+------------+------+--------------+-------------+---------------------
slot1 | | physical | | | f | | | | |
slot2 | | physical | | | f | | | | |
(2 rows)
スタンバイノードで、recovery.confを更新し、変数primary_slot_nameを追加し、application_nameを変更して、ノードを識別しやすくする必要があります。ホスト192.168.30.110のrecovery.confでは次のようになります。
[email protected]:/var/lib/postgresql/9.6/main/pg_log# cat ../recovery.conf
standby_mode = 'on'
primary_conninfo = 'application_name=node11 host=192.168.30.100 port=5432 user=cmon_replication password=m8rLmZxyn23Lc2Rk'
recovery_target_timeline = 'latest'
primary_slot_name = 'slot1'
trigger_file = '/tmp/failover_5432.trigger'
ホスト192.168.30.120でも同じことを行いますが、application_nameを変更し、primary_slot_name='slot2'を設定します。
レプリケーションスロットの状態を確認する:
192.168.10.100:5432 [email protected]_db=# select * from pg_replication_slots;
slot_name | plugin | slot_type | datoid | database | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn
-----------+--------+-----------+--------+----------+--------+------------+------+--------------+-------------+---------------------
slot1 | | physical | | | t | 24252 | | | 0/CF0A4218 |
slot2 | | physical | | | t | 11635 | | | 0/CF0A4218 |
(2 rows)
他に何が必要ですか?
現時点では、ClusterControlはレプリケーションスロットをサポートしていないため、考慮する必要があることがあります。これは何?詳細を見てみましょう。
ClusterControlを介した自動フェイルオーバーまたはスイッチオーバーが試行された場合、スロットはプライマリノードおよびスタンバイノードから保持されません。これを手動で再作成し、変数が正しく設定されているかどうかを確認し、それに応じてrecovery.confを変更する必要があります。
スレーブを再構築する場合、recovery.confは保持されません。これは、primary_slot_nameを持つrecovery.conf設定が消去されることを意味します。これを再度手動で指定し、pg_replication_slotsビューをチェックして、スロットが適切に使用されているか、孤立したままになっているかを判断する必要があります。
マスターからスレーブ/スタンバイノードを再構築する場合は、以下のコマンドのようにPGAPPNAMEenv変数を指定することを検討する必要がある場合があります。
$ export PGAPPNAME="app_repl_testnode15"; /usr/pgsql-9.6/bin/pg_basebackup -h 192.168.10.190 -U cmon_replication -D /var/lib/pgsql/9.6/data -p5434 -W -S main_slot -X s -R -P
-R paramを指定することは非常に重要であるため、recovery.confが再作成されます。一方、-Sは、スタンバイノードを再構築するときに使用するスロット名を指定します。
PostgreSQLでのレプリケーションスロットの実装は簡単ですが、覚えておく必要のある特定の注意事項があります。 ClusterControlを使用してデプロイする場合、フェイルオーバーまたはスレーブの再構築中にいくつかの設定を更新する必要があります。