論理フェイルオーバー スロットを使用した高度な障害復旧(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 を入力します。

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

  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. PostgreSQL を介して、要塞 VM からサブスクライバー インスタンスに接続します。

      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 レプリカがプライマリに昇格します。論理サブスクライバーのデータ損失のリスクを最小限に抑えるには、障害復旧レプリカ(DR レプリカ)を作成して指定するで推奨されているように、プライマリ インスタンスに cloudsql.synchronized_standby_replicas が設定されていることを確認してください。

    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. 新しいレプリカのプライベート IP アドレス($PRIMARY_INSTANCE_NAME)を取得します。

    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"

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