論理フェイルオーバー スロットを使用した高度な障害復旧(DR)

このページでは、論理フェイルオーバー スロットを使用して Cloud SQL for PostgreSQL の 論理レプリケーションを構成し、 高度な障害復旧(DR) オペレーション( Cloud SQL Enterprise Plus エディションのインスタンスでのスイッチオーバーとレプリカ フェイルオーバー)とシームレスに連携させる方法について説明します。

Cloud SQL の高度な障害復旧(DR)機能により、堅牢な障害復旧機能が実現します。PostgreSQL の論理レプリケーションと組み合わせる場合は、スイッチオーバーまたはレプリカ フェイルオーバーの後もレプリケーション ストリームが途切れないようにすることが重要です。

PostgreSQL の論理レプリケーションで高度な障害復旧(DR)を使用すると、論理サブスクライバーでデータ損失が発生せず、障害復旧イベント後に新しいプライマリ インスタンスに自動的に再接続できるため、ビジネス継続性を確保できます。

この機能は、次の構成の Cloud SQL インスタンスで使用できます。

  • PostgreSQL バージョン 17 以降
  • Cloud SQL Enterprise Plus エディション
  • プライベート サービス アクセス

    論理サブスクライバーの自動再接続を有効にするには、プライベート サービス アクセス ドメイン名サービス(DNS)書き込みエンドポイントを使用することをおすすめします。

始める前に

論理レプリケーションで高度な障害復旧(DR)を設定する

PostgreSQL の論理レプリケーションで高度な障害復旧(DR)を設定する手順は、次のとおりです。

  1. 環境変数と踏み台 VM を設定します
  2. プライマリ インスタンスを作成して設定します
  3. DR レプリカを作成して指定します
  4. 論理サブスクライバー インスタンスを作成して設定します
  5. 論理レプリケーション サブスクリプションを作成します
  6. スイッチオーバーまたはレプリカ フェイルオーバーを実行します
  7. レプリケーションを検証します
  8. 新しいレプリカで孤立したレプリケーション スロットをクリーンアップします
  9. 省略可: スイッチバックを実行します

環境変数と踏み台 VM を設定する

  1. 次の環境変数を設定します。

    # Project
    export PROJECT="PROJECT_ID"
    
    # Instance names
    export PRIMARY_INSTANCE_NAME="PRIMARY_INSTANCE"
    export DR_REPLICA_NAME="DR_REPLICA"
    export SUBSCRIBER_INSTANCE_NAME="SUBSCRIBER_INSTANCE"
    export BASTION_VM_NAME="BASTION_VM"
    
    # Regions and zones
    export PRIMARY_REGION="PRIMARY_REGION"
    export REPLICA_REGION="REPLICA_REGION"
    export SUBSCRIBER_REGION="SUBSCRIBER_REGION"
    export VM_ZONE="VM_ZONE"
    
    # Network
    export NETWORK_NAME="NETWORK"
    
    # Credentials
    export POSTGRES_PASSWORD="PASSWORD"
    
    # Set gcloud project
    gcloud config set project PROJECT_ID
    

    次のように置き換えます。

    • PROJECT_ID: 実際のプロジェクトの ID。
    • PRIMARY_INSTANCE: プライマリ Cloud SQL インスタンスの名前。
    • DR_REPLICA: レプリカの名前。
    • SUBSCRIBER_INSTANCE: サブスクライバー インスタンスの名前。
    • BASTION_VM: 踏み台 VM の名前。
    • PRIMARY_REGION: プライマリ インスタンスが配置されているリージョン。
    • REPLICA_REGION: レプリカが配置されているリージョン。レプリカは、プライマリ インスタンスとは異なるリージョンに配置する必要があります。
    • SUBSCRIBER_REGION: サブスクライバーが配置されているリージョン。
    • VM_ZONE: 踏み台 VM が配置されているゾーン。
    • NETWORK: VPC ネットワークの名前。
    • PASSWORD: postgres ユーザーのパスワード。
  2. Compute Engine 踏み台 VM を作成します。

    Cloud SQL インスタンスはプライベート IP を使用します。そのため、VPC ネットワークに Compute Engine 踏み台インスタンス VM を作成します。

    gcloud compute instances create $BASTION_VM_NAME \
      --zone=$VM_ZONE \
      --machine-type=e2-small \
      --network=projects/$PROJECT_ID/global/networks/$NETWORK_NAME \
      --image-project=debian-cloud \
      --image-family=debian-11 \
      --project=$PROJECT
    
  3. 踏み台 VM に接続します。

    gcloud compute ssh $BASTION_VM_NAME \
      --zone=$VM_ZONE \
      --project=$PROJECT
    
  4. 踏み台 VM に PostgreSQL クライアントをインストールします。

    sudo apt-get update
    sudo apt-get install -y postgresql-client
    exit
    

以降の手順の PostgreSQL コマンドは、踏み台 VM から実行します。

プライマリ インスタンスを作成して設定する

  1. プライマリ Cloud SQL インスタンスを作成します。

    gcloud sql instances create $PRIMARY_INSTANCE_NAME \
      --database-version=POSTGRES_17 \
      --edition=ENTERPRISE_PLUS \
      --region=$PRIMARY_REGION \
      --tier=db-perf-optimized-N-2 \
      --no-assign-ip \
      --network=projects/$PROJECT/global/networks/$NETWORK_NAME \
      --project=$PROJECT
    
  2. 論理デコードを有効にします。

    gcloud sql instances patch $PRIMARY_INSTANCE_NAME \
      --database-flags=cloudsql.logical_decoding=on \
      --project=$PROJECT
    
  3. プライマリで postgres ユーザーのパスワードを設定します。

    gcloud sql users set-password postgres \
      --instance=$PRIMARY_INSTANCE_NAME \
      --password="$POSTGRES_PASSWORD" \
      --project=$PROJECT
    
  4. 踏み台 VM からプライマリ インスタンスに接続します。

    1. プライマリ インスタンスのプライベート IP アドレスを取得します。

      gcloud sql instances describe $PRIMARY_INSTANCE_NAME \
        --format="value(ipAddresses[0].ipAddress)" \
        --project=$PROJECT
      

      プライマリ インスタンスのプライベート IP アドレスをコピーして保存します。

    2. 踏み台 VM に SSH で接続します。

      gcloud compute ssh $BASTION_VM_NAME --zone=$VM_ZONE --project=$PROJECT
      
    3. 踏み台 VM からプライマリ インスタンスに接続します。

      psql -h PRIMARY_PRIVATE_IP -U postgres
      

      PRIMARY_PRIVATE_IP は、この手順のステップ 4.a で取得した プライマリ インスタンスのプライベート IP に置き換えます。

    4. パスワードの入力を求められたら、変数 $POSTGRES_PASSWORD を入力します。

      これで、踏み台 VM が PostgreSQL を介してプライマリ インスタンスに接続されました。

  5. 権限を付与してパブリケーションを作成します。

    1. postgres ユーザーに REPLICATION 権限を付与します。

      ALTER USER postgres WITH REPLICATION;
      
    2. public スキーマとテーブルに必要な権限を付与します。

      GRANT SELECT ON ALL TABLES IN SCHEMA public TO postgres;
      
    3. すべてのテーブルのパブリケーションを作成します。

      CREATE PUBLICATION my_publication FOR ALL TABLES;
      
    4. exit と入力して PostgreSQL を終了し、もう一度 exit と入力して踏み台 VM の SSH セッションを閉じます。

障害復旧レプリカ(DR レプリカ)を作成して指定する

  1. DR レプリカを作成します。

    gcloud sql instances create $DR_REPLICA_NAME \
      --master-instance-name=$PRIMARY_INSTANCE_NAME \
      --edition=ENTERPRISE_PLUS \
      --tier=db-perf-optimized-N-2 \
      --region=$REPLICA_REGION \
      --no-assign-ip \
      --network=projects/$PROJECT/global/networks/$NETWORK_NAME \
      --project=$PROJECT
    
  2. このレプリカを DR レプリカとして指定します。

    gcloud sql instances patch $PRIMARY_INSTANCE_NAME \
      --failover-dr-replica-name=$DR_REPLICA_NAME \
      --project=$PROJECT
    
  3. 論理スロットの同期用に DR レプリカを構成します。

    gcloud sql instances patch $DR_REPLICA_NAME \
      --database-flags="^:^cloudsql.logical_decoding=on:hot_standby_feedback=on:sync_replication_slots=on:cloudsql.logical_slot_sync_dbname=postgres" \
      --project=$PROJECT
    
  4. プライマリ インスタンスと DR レプリカ間の同期レプリケーションを構成します。

    プライマリ インスタンスが突然停止し、その後にレプリカ フェイルオーバーが発生した場合に、論理サブスクライバーでデータが失われる可能性を防ぐため、プライマリ インスタンスと DR レプリカ間の同期レプリケーションを構成することをおすすめします。

    プライマリ インスタンスで cloudsql.synchronized_standby_replicas を設定すると、プライマリ インスタンスの論理レプリケーション先行書き込みログ(WAL)送信者は、DR レプリカが特定のトランザクションの WAL を受信してフラッシュするまで待機してから、そのトランザクションを論理サブスクライバーに送信します。これにより、DR レプリカの状態が常に論理サブスクライバーの状態以上になります。

    gcloud sql instances patch $PRIMARY_INSTANCE_NAME \
      --database-flags="^:^cloudsql.logical_decoding=on:cloudsql.synchronized_standby_replicas=$DR_REPLICA_NAME" \
      --project=$PROJECT
    

論理サブスクライバー インスタンスを作成して設定する

  1. サブスクライバー インスタンスを作成します。

    gcloud sql instances create $SUBSCRIBER_INSTANCE_NAME \
      --database-version=POSTGRES_17 \
      --tier=db-perf-optimized-N-2 \
      --region=$SUBSCRIBER_REGION \
      --no-assign-ip \
      --network=projects/$PROJECT/global/networks/$NETWORK_NAME \
      --project=$PROJECT
    
  2. サブスクライバーで論理デコードを有効にします。

    gcloud sql instances patch $SUBSCRIBER_INSTANCE_NAME \
      --database-flags=cloudsql.logical_decoding=on \
      --project=$PROJECT
    

論理レプリケーション サブスクリプションを作成する

  1. プライマリ インスタンスのプライベート サービス アクセス書き込みエンドポイントを取得します。

    gcloud sql instances describe $PRIMARY_INSTANCE_NAME \
      --format="value(replicationCluster.psaWriteEndpoint)" \
      --project=$PROJECT
    

    書き込みエンドポイントをコピーして保存します。

  2. サブスクライバー インスタンスに接続します。

    1. サブスクライバー インスタンスの postgres ユーザーのパスワードを更新します。

      gcloud sql users set-password postgres \
        --instance=$SUBSCRIBER_INSTANCE_NAME \
        --password="$POSTGRES_PASSWORD" \
        --project=$PROJECT
      
    2. サブスクライバー インスタンスのプライベート IP アドレスを取得します。

      gcloud sql instances describe $SUBSCRIBER_INSTANCE_NAME \
        --format="value(ipAddresses[0].ipAddress)" \
        --project=$PROJECT
      

      プライベート IP アドレスをコピーして保存します。

    3. 踏み台 VM に SSH で接続します。

      gcloud compute ssh $BASTION_VM_NAME \
        --zone=$VM_ZONE \
        --project=$PROJECT
      
    4. 踏み台 VM から PostgreSQL を介してサブスクライバー インスタンスに接続します。

      psql -h SUBSCRIBER_PRIVATE_IP -U postgres
      

      SUBSCRIBER_PRIVATE_IP は、 この手順のステップ 2.b でコピーしたサブスクライバー インスタンスのプライベート IP に置き換えます。

    5. パスワードの入力を求められたら、変数 $POSTGRES_PASSWORD を入力します。

  3. サブスクリプションを作成します。

    CREATE SUBSCRIPTION my_subscription
    CONNECTION 'host=DR_CLUSTER_PSA_DNS_WRITE_ENDPOINT port=5432 dbname=postgres user=postgres password=PASSWORD'
    PUBLICATION my_publication
    WITH (failover = true);
    

    次のように置き換えます。

    • DR_CLUSTER_PSA_DNS_WRITE_ENDPOINT: この手順のステップ 1でコピーしたプライベート サービス アクセス書き込みエンドポイント。
    • PASSWORD:変数 ${POSTGRES_PASSWORD} の値。
  4. PostgreSQL と踏み台 VM の SSH セッションを終了します。

  5. 省略可。DR レプリカのスロットの永続性を確認します。

    この永続的な移行(temporary = false)は通常、迅速に行われます。プライマリのアクティビティが少ない場合は、数秒で完了します。プライマリに書き込み負荷が高い場合、このプロセスには時間がかかることがあります(通常は約 1 分)。 これらの手動コマンドが完了すると、スロットは永続的になります。

    1. DR レプリカのプライベート IP アドレスを取得します。

      gcloud sql instances describe $DR_REPLICA_NAME \
        --format="value(ipAddresses[0].ipAddress)" \
        --project=$PROJECT
      

      DR レプリカのプライベート IP アドレスをコピーして保存します。

    2. 踏み台 VM に SSH で接続します。

      gcloud compute ssh $BASTION_VM_NAME \
        --zone=$VM_ZONE \
        --project=$PROJECT
      
    3. 踏み台 VM から DR レプリカに接続します。

      psql -h DR_REPLICA_PRIVATE_IP -U postgres
      

      DR_REPLICA_PRIVATE_IP は、この手順のステップ 5.a で取得した DR レプリカのプライベート IP アドレスに置き換えます。

    4. パスワードの入力を求められたら、変数 $POSTGRES_PASSWORD を入力します。

    5. スロットのステータスを確認します。

      SELECT slot_name, slot_type, temporary, failover, synced
      FROM pg_replication_slots
      WHERE slot_type = 'logical' AND failover = true;
      

      temporary 列が f になるまで待ちます。通常は 1 分未満で完了します。

    6. PostgreSQL と踏み台 VM の SSH セッションを終了します。

スイッチオーバーまたはレプリカ フェイルオーバーを実行する

シナリオに応じて、実行するオペレーションを選択します。

  • スイッチオーバー(計画されたロールの反転): 計画されたメンテナンス、 障害復旧テスト、またはプライマリ インスタンスが オンラインで正常な場合にロールを切り替える場合に選択します。このオペレーションにより、物理レプリケーションでデータ損失が発生しません。

    gcloud sql instances switchover $DR_REPLICA_NAME \
      --project=$PROJECT
    
  • レプリカ フェイルオーバー(障害復旧): プライマリ インスタンス が使用できない場合、または応答しない場合に選択します。このオペレーションにより、DR レプリカがプライマリに昇格します。論理サブスクライバーのデータ損失のリスクを最小限に抑えるため、プライマリ インスタンスに cloudsql.synchronized_standby_replicas が設定されていることを 確認してください。これは、障害復旧レプリカ(DR レプリカ)を作成して指定するで推奨されています。

    gcloud sql instances promote-replica $DR_REPLICA_NAME \
      --failover \
      --project=$PROJECT
    

    $DR_REPLICA_NAME の昇格は迅速に行われます。ただし、元のプライマリ インスタンス($PRIMARY_INSTANCE_NAME)は、オンラインに戻ったときにのみ、新しいプライマリのレプリカとして再構成されます。これを確認するには、オペレーション ログで $PRIMARY_INSTANCE_NAMERECONFIGURE_OLD_PRIMARY オペレーションが完了しているかどうかを確認します。次のコマンドを実行します。

    gcloud sql operations list --instance=$PRIMARY_INSTANCE_NAME --project=$PROJECT --limit=10`
    

    このフェーズが完了すると、障害復旧の設定が完全に復元されます。

どちらのオペレーションの後も、サブスクライバーはプライベート サービス アクセス書き込みエンドポイントを介して新しいプライマリ $DR_REPLICA_NAME に自動的に再接続します。

フラグの管理

Cloud SQL のワークフローは、スイッチオーバー オペレーションとレプリカ フェイルオーバー オペレーション中およびオペレーション後に、障害復旧クラスタ内の両方のインスタンスで必要なデータベース フラグを自動的に管理します。これには次のものがあります。

  • 新しいレプリカになるインスタンスで、論理スロットの同期フラグ(cloudsql.logical_decodinghot_standby_feedbacksync_replication_slotscloudsql.logical_slot_sync_dbname) が正しいことを確認します。
  • 新しいプライマリになるインスタンスの cloudsql.synchronized_standby_replicas フラグは、新しい DR レプリカの名前に自動的に更新されます。

スイッチオーバー オペレーションまたはレプリカ フェイルオーバー オペレーションの後に、これらのフラグを手動で再適用または変更する必要はありません。Cloud SQL は、プライマリ ロールとレプリカ ロールの正しい構成を維持します。

レプリケーションを検証する

  1. サブスクライバーのステータスを確認します。

    1. 踏み台 VM から、次のコマンドを実行します。

      psql -h SUBSCRIBER_PRIVATE_IP -U postgres
      

      SUBSCRIBER_PRIVATE_IP は、サブスクライバー インスタンスのプライベート IP アドレスに置き換えます。

    2. サブスクライバー インスタンスで、次のコマンドを実行します。

      SELECT subname, pid IS NOT NULL AS is_active
      FROM pg_stat_subscription;
      

      ステータスは streaming になります。

  2. 新しいプライマリのレプリケーション スロットのステータスを確認します。新しいプライマリは、以前の DR レプリカ($DR_REPLICA_NAME)です。

    1. 新しいプライマリのプライベート IP アドレスを取得します。

      gcloud sql instances describe $DR_REPLICA_NAME \
        --project=$PROJECT --format="value(ipAddresses[0].ipAddress)"
      

      新しいプライマリのプライベート IP アドレスをコピーして保存します。

    2. 踏み台 VM に SSH で接続します。

      psql -h NEW_PRIMARY_PRIVATE_IP -U postgres
      

      NEW_PRIMARY_PRIVATE_IP は、前の手順でコピーした新しいプライマリのプライベート IP アドレスに置き換えます。

    3. 新しいプライマリ インスタンスで、次のコマンドを実行します。

      SELECT
          slot_name,
          slot_type,
          active,
          synced,
          active_pid,
          pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn)) AS replication_lag
      FROM pg_replication_slots
      WHERE slot_type = 'logical';
      

      スロット(my_subscription など)は active = t になります。

      SELECT
          application_name,
          state
      FROM pg_stat_replication;
      

      pg_stat_replication に、サブスクライバーが接続されていることが表示されます。

新しいレプリカで孤立したレプリケーション スロットをクリーンアップする

スイッチオーバー オペレーションとフェイルオーバー オペレーションが完了すると、元のプライマリ インスタンス($PRIMARY_INSTANCE_NAME)はレプリカになります。この新しいレプリカ インスタンスは、ディスクに my_subscription という名前の元の論理レプリケーション スロットを保持しています。サブスクライバーはプライベート サービス アクセス書き込みエンドポイントを介して新しいプライマリ($DR_REPLICA_NAME)に接続することが想定されているため、この my_subscription スロットは孤立しています。

Cloud SQL は、この孤立したスロットを新しいレプリカから自動的に削除しません。これは、Cloud SQL が、サブスクライバーがプライベート サービス アクセス書き込みエンドポイントではなくインスタンスの IP アドレスを使用するように構成されているかどうかを判断できないためです。サブスクリプションが手動で変更されるまで、サブスクライバーが新しいレプリカの古いスロットに接続しようとする可能性があります。 スロットを自動的に削除すると、このような構成が破損する可能性があります。

新しいレプリカ($PRIMARY_INSTANCE_NAME)にこの孤立したスロットが存在すると、このインスタンスの slotsync ワーカー プロセスでログにエラーが生成されます。新しいレプリカの postgres.log に次のようなエラー メッセージが表示されることがあります。slotsync ワーカーが試行を続けるため、このエラーは繰り返されます。

ERROR: exiting from slot synchronization because same name slot "my_subscription" already exists on the standby

このようなエラーを防ぎ、slotsync ワーカーがこのレプリカで my_subscription スロットの新しい同期バージョンを正しく確立できるようにするには、孤立したスロットを手動で削除する必要があります。これにより、今後スイッチバックを行う場合に、このインスタンスを適切に準備できます。

  1. 新しいレプリカ($PRIMARY_INSTANCE_NAME)のプライベート IP アドレスを取得します。

    gcloud sql instances describe $PRIMARY_INSTANCE_NAME \
      --project=$PROJECT --format="value(ipAddresses[0].ipAddress)"
    

    新しいレプリカのプライベート IP アドレスをコピーして保存します。

  2. 踏み台 VM に SSH で接続します。

    gcloud compute ssh $BASTION_VM_NAME \
      --zone=$VM_ZONE \
      --project=$PROJECT
    
  3. 踏み台 VM から新しいレプリカに接続します。

    psql -h NEW_REPLICA_IP -U postgres
    

    NEW_REPLICA_IP は、この手順のステップ 1 でコピーした新しい レプリカの IP アドレスに置き換えます。

  4. パスワードの入力を求められたら、変数 $POSTGRES_PASSWORD を入力します。

  5. 新しいレプリカ($PRIMARY_INSTANCE_NAME)で、孤立したスロットを削除します。

    SELECT slot_name, slot_type, temporary, failover, synced, active
    FROM pg_replication_slots
    WHERE slot_name = 'my_subscription';
    

    synced = falseactive = false でスロットが存在することを確認し、削除します。

    SELECT pg_drop_replication_slot('my_subscription');
    

    孤立したスロットが削除されます。

スロットの自動再同期

孤立したスロットが削除されると、新しいレプリカ($PRIMARY_INSTANCE_NAME)の slotsync ワーカーは、次のサイクルで新しいプライマリ($DR_REPLICA_NAME)に自動的に接続します。新しいプライマリのアクティブ スロットと同期された新しいローカル my_subscription スロットが作成されます。

新しいレプリカの postgres.log に、次のような成功を示すメッセージが表示されます。

LOG: newly created slot "my_subscription" is sync-ready now

新しい同期スロットには failover=true が設定され、最終的に永続的(temporary=false)になります。これにより、後でスイッチバックする場合に、このインスタンスを準備できます。

省略可: スイッチバックを実行する

  1. スイッチバックして、$PRIMARY_INSTANCE_NAME を再びプライマリ インスタンスにします。

    gcloud sql instances switchover $PRIMARY_INSTANCE_NAME \
      --project=$PROJECT
    
  2. スイッチバック後に検証を行います。

    1. サブスクライバー インスタンスのステータスを確認します。

      SELECT subname, pid IS NOT NULL AS is_active
      FROM pg_stat_subscription;
      

      サブスクリプションはアクティブのままにする必要があります(is_active = t)。

    2. 新しいプライマリ($PRIMARY_INSTANCE_NAME)のスロットのステータスを確認します。

      SELECT slot_name, active FROM pg_replication_slots WHERE slot_type = 'logical';
      SELECT * FROM pg_stat_replication;
      

      スロットはアクティブで、サブスクライバーが接続されている必要があります。

トラブルシューティング

問題 トラブルシューティング

スイッチオーバー後に新しいレプリカ(つまり、古いプライマリ インスタンス)でエラーが発生する:

"exiting from slot synchronization because same name slot already exists on the standby"

新しいレプリカで孤立したレプリケーション スロットをクリーンアップする の手順に沿って操作します。