論理レプリケーションの復旧方法 ~ ストリーミングレプリケーションのフェイルオーバー併用時 ~
PostgreSQLインサイド

論理レプリケーション(ロジカルレプリケーション)の仕組みと設定方法については、「論理レプリケーション解説 ~ 仕組み、設定方法 ~」で説明しました。可用性が高いシステムでは、ストリーミングレプリケーションを用いてデータベースを冗長化している場合があります。その環境上で論理レプリケーションを用いる場合、ストリーミングレプリケーションがフェイルオーバーした際に、論理レプリケーションも同様に切替え、停止したサーバーを適切に復旧させる必要があります。そこで、この記事では、このような場面での手順や障害時の対応方法についてコマンド実行例や図を用いて丁寧に解説します。
なお、本記事では、PostgreSQL 15で設定可能なパラメーターおよび機能を使用して説明しています。

目次

ストリーミングレプリケーションと論理レプリケーションを併用する理由

ここでは、ストリーミングレプリケーションと論理レプリケーションを併用する理由から併用時の注意点について説明します。

可用性の考え方

業務システムにおいて、論理レプリケーションを同期モードで運用することで、リアルタイムにデータを複製できます。ただし、論理レプリケーションには、冗長化の範囲がテーブル内のデータのみで、可用性全般を担保する機構がありません。そのため、実際の業務においては、ストリーミングレプリケーション環境上で論理レプリケーションを使用するケースが多いと考えられます(図1と図2参照)。

ストリーミングレプリケーションと論理レプリケーション(パブリケーション)を併用した構成例

図1:ストリーミングレプリケーションと論理レプリケーション(パブリケーション)を併用した構成例

ストリーミングレプリケーションと論理レプリケーション(サブスクリプション)を併用した構成例

図2:ストリーミングレプリケーションと論理レプリケーション(サブスクリプション)を併用した構成例

ストリーミングレプリケーションと併用するときの制限事項

ストリーミングレプリケーション環境上で論理レプリケーションを併用する場合、論理レプリケーションのパブリケーションはストリーミングレプリケーションのプライマリへ定義できます(スタンバイにパブリケーションの定義はできません)。一方、論理レプリケーションのサブスクリプションは、ストリーミングレプリケーションのプライマリとスタンバイに定義できます。

フェイルオーバー時の対処方法

本記事公開時点の論理レプリケーションには、自動復旧させる機構がありません。そのため、ストリーミングレプリケーション環境がフェイルオーバーした後に、パブリケーションとサブスクリプションの設定を復旧させる運用手順を考える必要があります。詳細に関しては、以降で解説します。

障害によるフェイルオーバー発生時の復旧の流れ

ストリーミングレプリケーションと論理レプリケーションを併用した構成において、構成サーバーで障害が発生し、ストリーミングレプリケーションでフェイルオーバーが行われた場合、ストリーミングレプリケーションと論理レプリケーションの復旧が必要です。このような障害が発生した場合、「パブリッシャー」や「サブスクライバー」が停止します。以降で、各パターンの復旧の流れを説明します。

パブリッシャー側が停止した場合

パブリッシャーを配置したプライマリ側が停止した場合の復旧の流れを解説します。なお、復旧には「サブスクライバー側のテーブルデータを残した状態で復旧する方法」と、「サブスクライバー側のテーブルデータを空にして初期データ同期から復旧する方法」があります。表1を参照していずれかを選択してください。

まず、ストリーミングレプリケーションのスタンバイが新プライマリへ昇格後に論理レプリケーションが実施されていないことを確認します(図3参照)。

論理レプリケーションの確認

図3:論理レプリケーションの確認

続いて、表1の復旧方法のいずれかにより、サブスクライバーの接続先を変更します(図4参照)。「サブスクライバー側のテーブルデータを空にして初期データ同期から復旧」を選択した場合、初期データ同期とWAL適用を実施します。一方の「サブスクライバー側のテーブルデータを残した状態で復旧」を選択した場合、WAL適用のみ実施されます。そのため、表1に示したメリットとデメリットが挙げられます。 初期データ同期やWAL適用の流れに関しては、以下の記事で解説しています。

表1 サブスクライバーの復旧方法

方法 メリット デメリット
サブスクライバー側のテーブルデータを残した状態で復旧 即座に論理レプリケーションの状態に復旧できる データの欠落の可能性がある(論理レプリケーション停止中の更新が反映されない)
サブスクライバー側のテーブルデータを空にして初期データ同期から復旧 新プライマリからテーブル内のデータをすべて取得し直すため、データの欠落が発生しない データ量が多い場合には、初期データ同期に時間がかかる(早期復旧ができない)

サブスクライバーの接続先を変更

図4:サブスクライバーの接続先を変更

最後に、新スタンバイ復旧後にスロットを削除します(図5参照)。

スロットの削除

図5:スロットの削除

各流れの詳細に関しては、「検証:パブリッシャー側が停止した場合の復旧手順」で解説します。

サブスクライバー側が停止した場合

サブスクライバーを配置したプライマリ側が停止しスタンバイ側にフェイルオーバーした場合、スロットやサブスクリプションの接続先は変わりません。また、サブスクリプション側の設定がそのままスタンバイにも引き継がれます。これにより論理レプリケーションへの影響はなく、スロットの再割り当てや接続情報を変更する必要がないため、論理レプリケーションをそのまま継続できます。

復旧前後の構成(サブスクライバー側のフェイルオーバー)

図6:復旧前後の構成(サブスクライバー側のフェイルオーバー)

検証:パブリッシャー側が停止した場合の復旧手順

図7の構成で、パブリッシャー側で障害が発生した際の復旧手順および検証手順を、実行するべきコマンドを示しながら解説します。

検証環境(フェイルオーバー前)

図7:検証環境(フェイルオーバー前)

検証環境(フェイルオーバー後)

図8:検証環境(フェイルオーバー後)

手順1:ストリーミングレプリケーションの構成を作成

ストリーミングレプリケーションの機能概要と設定については、以下の記事で解説しています。設定例が記載されていますので、ぜひお読みください。

手順2:論理レプリケーションの構成を作成

論理レプリケーションの機能概要と設定方法については、以下の記事で解説しています。図やコマンド例を用いてわかりやすく説明していますので、ぜひお読みください。

手順3:ストリーミングレプリケーションのプライマリに障害が発生しスタンバイを昇格

  1. プライマリの疑似的な故障を発生させるために、プライマリ上(VM#0)で以下のコマンドを実行してください。

$ pg_ctl stop -m immediate -w
  1. スタンバイをプライマリに昇格させるために、スタンバイ上(VM#1)で以下のコマンドを実行します。

$ pg_ctl promote

コマンド実行後、以下のようなメッセージが出力された場合、スタンバイをプライマリに昇格できたと判断できます。


waiting for server to promote.... done
server promoted

手順4:論理レプリケーションの確認

論理レプリケーションが行われていないことを確認するために、サブスクライバー側(VM#2)で以下のコマンドを実行してください。システムカタログpg_stat_subscriptionのpidが空、received_lsnが空である場合、論理レプリケーションが行われていない状態であることを把握できます。

postgres=# SELECT subname, pid, received_lsn FROM pg_stat_subscription WHERE subname = 'sub';
-[ RECORD 1 ]---------+------
subname               | sub
pid                   |
received_lsn          |

手順5:サブスクライバーの復旧

サブスクライバーには2つの復旧方法があります。表1に記載したメリットとデメリットを考慮し復旧方法を選択してください。「サブスクライバー側のテーブルデータを残した状態で復旧する」を選択した場合は手順5-1を、それ以外は手順5-2を実施してください。

手順5-1:サブスクライバー側のテーブルデータを残した状態で復旧

本手順のコマンドは、サブスクライバー側(VM#2)で実行してください。

  1. サブスクリプションを停止させるために、以下のコマンドを実行します。

postgres=# ALTER SUBSCRIPTION sub DISABLE;

サブスクリプションが停止したことを確認するために、以下のコマンドを実行してください。システムカタログpg_subscriptionのsubenabledがfである場合、サブスクリプションが停止状態であることを把握できます。


postgres=# SELECT subenabled FROM pg_subscription WHERE subname = 'sub';
-[ RECORD 1 ]----+-----------------------------------------------------------
subenabled       | f
  1. レプリケーションスロットとの対応を無効化するために、以下のコマンドを実行します。

postgres=# ALTER SUBSCRIPTION sub SET (slot_name = NONE);
  1. サブスクリプションを削除するために、以下のコマンドを実行します。

postgres=# DROP SUBSCRIPTION sub;

サブスクリプションが削除されたことを確認するために、以下のコマンドを実行してください。データが何も出力されなかった場合、サブスクリプションを削除できたことを把握できます。


postgres=# SELECT * FROM pg_subscription WHERE subname = 'sub';
  1. サブスクリプションを再作成するために、以下のコマンドを実行します。copy_data = falseを指定することで、サブスクリプション作成後の初期データ同期を無効化できます。以下のコマンド実行直後から論理レプリケーションが再開されます。

postgres=# CREATE SUBSCRIPTION sub CONNECTION 'host=node002 port=5432 user=logi_repl_user dbname=postgres' PUBLICATION pub WITH (copy_data = false);

手順5-2:サブスクライバー側のテーブルデータを空にして初期データ同期から復旧

本手順のコマンドは、サブスクライバー側(VM#2)で実行してください。

  1. サブスクリプションを停止するために、以下のコマンドを実行します。

postgres=# ALTER SUBSCRIPTION sub DISABLE;

サブスクリプションが停止したことを確認するために、以下のコマンドを実行してください。システムカタログpg_subscriptionのsubenabledがfである場合、サブスクリプションが停止状態であることを把握できます。


postgres=# SELECT subenabled FROM pg_subscription WHERE subname = 'sub';
-[ RECORD 1 ]----+-----------------------------------------------------------
subenabled       | f 
  1. レプリケーションスロットとの対応を無効化するために、以下のコマンドを実行します。

postgres=# ALTER SUBSCRIPTION sub SET (slot_name = NONE);
  1. サブスクリプションを削除するために、以下のコマンドを実行しましょう。

postgres=# DROP SUBSCRIPTION sub;

サブスクリプションが削除されたことを確認するために、以下のコマンドを実行してください。データが何も出力されなかった場合、サブスクリプションを削除できたことを把握できます。


postgres=# SELECT * FROM pg_subscription WHERE subname = 'sub';
  1. 論理レプリケーションの対象テーブルのデータを削除するために、以下のコマンドを実行してください。

postgres=# TRUNCATE TABLE tbl;

対象テーブルのデータが削除されたことを確認するために、以下のコマンドを実行しましょう。データが格納されていない場合、対象テーブルのデータが削除された状態であることを把握できます。


postgres=# SELECT * FROM tbl;
  1. サブスクリプションを再作成するために、以下のコマンドを実行します。以下のコマンド実行直後から論理レプリケーションが再開されます。

postgres=# CREATE SUBSCRIPTION sub CONNECTION 'host=node002 port=5432 user=logi_repl_user dbname=postgres' PUBLICATION pub;

手順6:論理レプリケーションの復旧確認

論理レプリケーションが復旧したことを確認するために、サブスクライバー側(VM#2)で以下のコマンドを実行します。システムカタログpg_subscriptionのsubenabledがtである場合、論理レプリケーションが実施状態であることを把握できます。

postgres=# SELECT subenabled FROM pg_subscription WHERE subname = 'sub';
-[ RECORD 1 ]----+-----------------------------------------------------------
subenabled       | t 

手順7:ストリーミングレプリケーションの復旧

ストリーミングレプリケーションの復旧手順については、以下の記事で解説しています。図を用いてわかりやすく説明していますので、ぜひお読みください。

手順8:不要なレプリケーションスロットの削除

新スタンバイ側で論理レプリケーションのために使用したレプリケーションスロットを削除するために、新スタンバイ側(VM#0)で以下のコマンドを実行します。

postgres=# SELECT pg_drop_replication_slot('sub');

以上の手順により、ストリーミングレプリケーション環境上の論理レプリケーションを復旧できます。

ストリーミングレプリケーションがフェイルオーバーした際に論理レプリケーションを復旧する方法について解説しました。ストリーミングレプリケーション機能と併用し、データベースの高可用化にお役立てください。

可用性をさらに高めたい場合、Fujitsu Enterprise Postgres を利用する方法があります。Fujitsu Enterprise Postgres は、PostgreSQLの機能をエンタープライズ向けに強化した製品であり、異常検知や自動フェイルオーバーの機能として「データベース多重化機能」、データベースへの接続先を切替える機能として「Connection Manager機能」があります。
本機能の詳細に関しては、以下をご覧ください。

2023年7月28日公開

オンデマンド(動画)セミナー

    • PostgreSQLに関連するセミナー動画を公開中。いつでもセミナーをご覧いただけます。
      • 【事例解説】運送業務改革をもたらす次世代の運送業界向けDXプラットフォームの構築
      • ハイブリッドクラウドに最適なOSSベースのデータベースご紹介

本コンテンツに関するお問い合わせ

お電話でのお問い合わせ

Webでのお問い合わせ

当社はセキュリティ保護の観点からSSL技術を使用しております。

ページの先頭へ