Recuperación ante desastres (DR) avanzada con ranura de conmutación por error lógica

En esta página, se describe cómo usar la ranura de conmutación por error lógica para configurar la replicación lógica de Cloud SQL para PostgreSQL de modo que funcione sin problemas con las operaciones de recuperación ante desastres (DR) avanzada, específicamente la conmutación y la conmutación por error de réplicas en instancias con la edición Cloud SQL Enterprise Plus.

Las funciones avanzadas de recuperación ante desastres (DR) de Cloud SQL permiten capacidades sólidas de recuperación ante desastres. Cuando se combina con la replicación lógica de PostgreSQL, es fundamental que el flujo de replicación permanezca ininterrumpido después de una conmutación o una conmutación por error de la réplica.

Si usas la recuperación ante desastres (DR) avanzada con la replicación lógica de PostgreSQL, puedes asegurarte de que tus suscriptores lógicos no experimenten pérdida de datos y puedan volver a conectarse automáticamente a la nueva instancia principal después de un evento de recuperación ante desastres, lo que garantiza la continuidad empresarial.

Puedes usar esta funcionalidad en instancias de Cloud SQL que tengan la siguiente configuración:

  • PostgreSQL versión 17 o posterior
  • Edición Enterprise Plus de Cloud SQL
  • Acceso privado a servicios

    Te recomendamos que uses el extremo de escritura del servicio de nombres de dominio (DNS) de acceso privado a servicios para habilitar las reconexiones lógicas automáticas de los suscriptores.

Antes de comenzar

Configura la recuperación ante desastres (DR) avanzada con replicación lógica

El proceso para configurar la recuperación ante desastres (DR) avanzada con la replicación lógica de PostgreSQL tiene los siguientes pasos generales:

  1. Configura las variables de entorno y la VM de bastión.
  2. Crea y configura la instancia principal.
  3. Crea y designa una réplica de DR.
  4. Crea y configura una instancia de suscriptor lógica.
  5. Crea una suscripción de replicación lógica.
  6. Realiza un cambio o una conmutación por error de réplica.
  7. Valida la replicación.
  8. Limpia la ranura de replicación huérfana en la réplica nueva.
  9. Opcional: Realiza una reversión.

Configura variables de entorno y una VM de bastión

  1. Configura las siguientes variables de entorno:

    # 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
    

    Reemplaza lo siguiente:

    • PROJECT_ID: el ID de tu proyecto.
    • PRIMARY_INSTANCE: Es el nombre de la instancia principal de Cloud SQL.
    • DR_REPLICA: Es el nombre de la réplica.
    • SUBSCRIBER_INSTANCE: Es el nombre de la instancia de suscriptor.
    • BASTION_VM: Es el nombre de la VM de bastión.
    • PRIMARY_REGION: Es la región en la que se encuentra la instancia principal.
    • REPLICA_REGION: Es la región en la que se encuentra la réplica. La réplica debe estar en una región diferente a la de la instancia principal.
    • SUBSCRIBER_REGION: Es la región en la que se encuentra el suscriptor.
    • VM_ZONE: Es la zona en la que se encuentra la VM de host.
    • NETWORK: Es el nombre de tu red de VPC.
    • PASSWORD: la contraseña del usuario postgres.
  2. Crea una VM de bastión de Compute Engine.

    Las instancias de Cloud SQL usan una IP privada. Por lo tanto, crea una VM de host de bastión de Compute Engine en tu red de VPC.

    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. Conéctate a la VM de bastión.

    gcloud compute ssh $BASTION_VM_NAME \
      --zone=$VM_ZONE \
      --project=$PROJECT
    
  4. En la VM de bastión, instala el cliente de PostgreSQL.

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

Los comandos de PostgreSQL en los pasos posteriores se deben ejecutar desde la VM de bastión.

Crea y configura la instancia principal

  1. Crea la instancia principal de 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. Habilita la decodificación lógica.

    gcloud sql instances patch $PRIMARY_INSTANCE_NAME \
      --database-flags=cloudsql.logical_decoding=on \
      --project=$PROJECT
    
  3. Establece la contraseña para el usuario postgres en el servidor principal.

    gcloud sql users set-password postgres \
      --instance=$PRIMARY_INSTANCE_NAME \
      --password="$POSTGRES_PASSWORD" \
      --project=$PROJECT
    
  4. Conéctate a la instancia principal desde la VM de bastión.

    1. Recupera la dirección IP privada de la instancia principal.

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

      Copia y guarda la dirección IP privada de la instancia principal.

    2. Conéctate a tu VM de host bastión a través de SSH.

      gcloud compute ssh $BASTION_VM_NAME --zone=$VM_ZONE --project=$PROJECT
      
    3. Desde la VM de bastión, conéctate a la instancia principal.

      psql -h PRIMARY_PRIVATE_IP -U postgres
      

      Reemplaza PRIMARY_PRIVATE_IP por la IP privada de la instancia principal que recuperaste en el paso 4a de este procedimiento.

    4. Cuando se te solicite la contraseña, ingresa la variable $POSTGRES_PASSWORD.

      Tu VM de host ahora está conectada a la instancia principal a través de PostgreSQL.

  5. Otorga permisos y crea la publicación.

    1. Otorga el privilegio REPLICATION al usuario postgres.

      ALTER USER postgres WITH REPLICATION;
      
    2. Otorga los privilegios necesarios en el esquema y las tablas públicos.

      GRANT SELECT ON ALL TABLES IN SCHEMA public TO postgres;
      
    3. Crea la publicación para todas las tablas.

      CREATE PUBLICATION my_publication FOR ALL TABLES;
      
    4. Escribe exit para salir de PostgreSQL y, luego, exit otra vez para cerrar la sesión de SSH de la VM de bastión.

Crea y designa una réplica de recuperación ante desastres (réplica de DR)

  1. Crea una réplica de 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. Designa esta réplica como la réplica de DR.

    gcloud sql instances patch $PRIMARY_INSTANCE_NAME \
      --failover-dr-replica-name=$DR_REPLICA_NAME \
      --project=$PROJECT
    
  3. Configura la réplica de DR para la sincronización de ranuras lógicas.

    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. Configura la replicación síncrona entre la instancia principal y la réplica de DR.

    Para evitar la posible pérdida de datos en el suscriptor lógico en caso de una interrupción repentina de la instancia principal y la posterior conmutación por error de la réplica, te recomendamos que configures la replicación síncrona entre la instancia principal y la réplica de DR.

    Establecer cloudsql.synchronized_standby_replicas en la instancia principal obliga al emisor del registro de escritura anticipada (WAL) de la replicación lógica de la instancia principal a esperar hasta que la réplica de DR haya recibido y vaciado el WAL para una transacción determinada antes de enviar esa transacción al suscriptor lógico. Esto garantiza que el estado de la réplica de DR siempre esté por delante o sea igual al estado del suscriptor lógico.

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

Crea y configura una instancia de suscriptor lógica

  1. Crea una instancia de suscriptor.

    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. Habilita la decodificación lógica en el suscriptor.

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

Crea una suscripción de replicación lógica

  1. Recupera el extremo de escritura de acceso privado a servicios de la instancia principal.

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

    Copia y guarda el endpoint de escritura.

  2. Conéctate a la instancia del suscriptor.

    1. Actualiza la contraseña del usuario postgres de la instancia del suscriptor.

      gcloud sql users set-password postgres \
        --instance=$SUBSCRIBER_INSTANCE_NAME \
        --password="$POSTGRES_PASSWORD" \
        --project=$PROJECT
      
    2. Recupera la dirección IP privada de la instancia del suscriptor.

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

      Copia y guarda la dirección IP privada.

    3. Conéctate a la VM de host bastión a través de SSH.

      gcloud compute ssh $BASTION_VM_NAME \
        --zone=$VM_ZONE \
        --project=$PROJECT
      
    4. Desde la VM de host, conéctate a la instancia de suscriptor a través de PostgreSQL.

      psql -h SUBSCRIBER_PRIVATE_IP -U postgres
      

      Reemplaza SUBSCRIBER_PRIVATE_IP por la IP privada de la instancia del suscriptor que copiaste en el paso 2b de este procedimiento.

    5. Cuando se te solicite la contraseña, ingresa la variable $POSTGRES_PASSWORD.

  3. Cree una suscripción.

    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);
    

    Reemplaza lo siguiente:

    • DR_CLUSTER_PSA_DNS_WRITE_ENDPOINT: Es el extremo de escritura de acceso a servicios privados que copiaste en el paso 1 de este procedimiento.
    • PASSWORD: Es el valor de la variable ${POSTGRES_PASSWORD}.
  4. Sal de PostgreSQL y de la sesión SSH de la VM de bastión.

  5. Es opcional. Verifica la persistencia de la ranura en la réplica de DR.

    Por lo general, esta transición a persistente (temporary = false) ocurre rápidamente, a menudo en segundos si el elemento principal tiene poca actividad. Con una carga de escritura pesada en el servidor principal, este proceso puede tardar más, generalmente alrededor de un minuto. La ranura debería persistir después de completar estos comandos manuales.

    1. Obtén la dirección IP privada de la réplica de DR.

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

      Copia y guarda la dirección IP privada de la réplica de DR.

    2. Conéctate a la VM de host bastión a través de SSH.

      gcloud compute ssh $BASTION_VM_NAME \
        --zone=$VM_ZONE \
        --project=$PROJECT
      
    3. Desde la VM de bastión, conéctate a la réplica de DR.

      psql -h DR_REPLICA_PRIVATE_IP -U postgres
      

      Reemplaza DR_REPLICA_PRIVATE_IP por la dirección IP privada de la réplica de DR que recuperaste en el paso 5a de este procedimiento.

    4. Cuando se te solicite la contraseña, ingresa la variable $POSTGRES_PASSWORD.

    5. Verifica el estado de la ranura.

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

      Espera a que la columna temporary se convierta en f. Este proceso suele tardar menos de un minuto.

    6. Sal de PostgreSQL y de la sesión SSH de la VM de bastión.

Realiza un cambio o una conmutación por error de réplica

Elige la operación que deseas realizar según tu situación:

  • Cambio (inversión de roles planificada): Elige esta opción para el mantenimiento planificado, las pruebas de recuperación ante desastres o para cambiar los roles cuando la instancia principal esté en línea y en buen estado. Esta operación garantiza que no haya pérdida de datos en la replicación física.

    gcloud sql instances switchover $DR_REPLICA_NAME \
      --project=$PROJECT
    
  • Replica Failover (recuperación ante desastres): Elige esta opción cuando la instancia principal no esté disponible o no responda. Esta operación promueve la réplica de DR a principal. Para minimizar el riesgo de pérdida de datos para el suscriptor lógico, asegúrate de que cloudsql.synchronized_standby_replicas se haya configurado en la instancia principal como se recomienda en Crea y designa una réplica de recuperación ante desastres (réplica de DR).

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

    El ascenso de $DR_REPLICA_NAME se produce rápidamente. Sin embargo, la instancia principal original ($PRIMARY_INSTANCE_NAME) solo se reconfigura como una réplica de la instancia principal nueva una vez que vuelve a estar en línea. Puedes hacer un seguimiento de esto buscando la operación RECONFIGURE_OLD_PRIMARY que se complete en $PRIMARY_INSTANCE_NAME en el registro de operaciones. Ejecuta el comando siguiente:

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

    La configuración de recuperación ante desastres se restablece por completo solo después de que se completa esta fase.

Después de cualquiera de las operaciones, el suscriptor se vuelve a conectar automáticamente al nuevo $DR_REPLICA_NAME principal a través del extremo de escritura de acceso privado a servicios.

Administración de marcas

Los flujos de trabajo de Cloud SQL administran automáticamente las marcas de bases de datos necesarias en ambas instancias dentro del clúster de recuperación ante desastres durante y después de las operaciones de conmutación y conmutación por error de réplica, incluidas las siguientes:

  • Se garantiza que las marcas de sincronización de ranuras lógicas (cloudsql.logical_decoding, hot_standby_feedback, sync_replication_slots, cloudsql.logical_slot_sync_dbname) sean correctas en la instancia que se convierte en la nueva réplica.
  • La marca cloudsql.synchronized_standby_replicas en la instancia que se convierte en la nueva principal se actualiza automáticamente para que apunte al nombre de la nueva réplica de DR.

No es necesario que vuelvas a aplicar o cambiar manualmente estos parámetros después de una operación de conmutación o conmutación por error de réplica. Cloud SQL mantiene la configuración correcta para los roles de instancia principal y réplica.

Valida la replicación

  1. Verifica el estado del suscriptor.

    1. Desde la VM de bastión, ejecuta el siguiente comando.

      psql -h SUBSCRIBER_PRIVATE_IP -U postgres
      

      Reemplaza SUBSCRIBER_PRIVATE_IP por la dirección IP privada de la instancia del suscriptor.

    2. En la instancia del suscriptor, ejecuta el siguiente comando.

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

      El estado debe ser streaming.

  2. Verifica el estado de la ranura de replicación de la nueva instancia principal. La nueva instancia principal es la antigua réplica de DR ($DR_REPLICA_NAME).

    1. Obtén la dirección IP privada del nuevo principal.

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

      Copia y guarda la dirección IP privada del nuevo servidor principal.

    2. Conéctate a la VM de host bastión a través de SSH.

      psql -h NEW_PRIMARY_PRIVATE_IP -U postgres
      

      Reemplaza NEW_PRIMARY_PRIVATE_IP por la dirección IP privada del nuevo servidor principal que copiaste en el paso anterior.

    3. En la nueva instancia principal, ejecuta los siguientes comandos.

      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';
      

      La ranura (por ejemplo, my_subscription) debe ser active = t.

      SELECT
          application_name,
          state
      FROM pg_stat_replication;
      

      pg_stat_replication debería mostrar que el suscriptor está conectado.

Limpia la ranura de replicación huérfana en la réplica nueva

Una vez que se completan las operaciones de cambio y conmutación por error, la instancia principal original ($PRIMARY_INSTANCE_NAME) ahora es una réplica. Esta nueva instancia de réplica aún conserva la ranura de replicación lógica original llamada my_subscription en su disco. Esta ranura my_subscription ahora está huérfana porque se espera que el suscriptor se conecte al nuevo servidor principal ($DR_REPLICA_NAME) a través del extremo de escritura de acceso privado a servicios.

Cloud SQL no quita automáticamente esta ranura huérfana de la réplica nueva. Esto se debe a que Cloud SQL no puede determinar si el suscriptor se configuró para usar la dirección IP de la instancia en lugar del extremo de escritura del acceso privado a servicios. Es posible que el suscriptor siga intentando conectarse a este intervalo antiguo en la réplica nueva hasta que se modifique la suscripción de forma manual. Si se descarta automáticamente la ranura, se podrían interrumpir esas configuraciones.

La presencia de esta ranura huérfana en la réplica nueva ($PRIMARY_INSTANCE_NAME) hace que el proceso de trabajador slotsync en esta instancia genere errores en los registros. Es posible que veas un mensaje de error como el siguiente en el postgres.log de la nueva réplica. Este error se repite a medida que el trabajador slotsync sigue intentando.

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

Para evitar estos errores y permitir que el trabajador slotsync establezca correctamente una nueva versión sincronizada de la ranura my_subscription en esta réplica, debes descartar manualmente la ranura huérfana. Esto garantiza que la instancia esté preparada correctamente si planeas volver a cambiar en el futuro.

  1. Recupera la dirección IP privada de la nueva réplica ($PRIMARY_INSTANCE_NAME).

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

    Copia y guarda la dirección IP privada de la réplica nueva.

  2. Conéctate a la VM de host bastión a través de SSH.

    gcloud compute ssh $BASTION_VM_NAME \
      --zone=$VM_ZONE \
      --project=$PROJECT
    
  3. Desde la VM de bastión, conéctate a la réplica nueva.

    psql -h NEW_REPLICA_IP -U postgres
    

    Reemplaza NEW_REPLICA_IP por la dirección IP de la nueva réplica que copiaste en el paso 1 de este procedimiento.

  4. Cuando se te solicite la contraseña, ingresa la variable $POSTGRES_PASSWORD.

  5. En la réplica nueva ($PRIMARY_INSTANCE_NAME), descarta la ranura huérfana.

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

    Confirma que la ranura existe con synced = false y active = false, y luego suéltala.

    SELECT pg_drop_replication_slot('my_subscription');
    

    Se quita la ranura huérfana.

Resincronización automática de intervalos

Una vez que se descarta la ranura huérfana, el trabajador slotsync en la réplica nueva ($PRIMARY_INSTANCE_NAME) se conecta automáticamente al nuevo principal ($DR_REPLICA_NAME) en su próximo ciclo. Crea una nueva ranura my_subscription local que se sincroniza con la ranura activa de la instancia primaria nueva.

Puedes ver mensajes en la nueva réplica de postgres.log que indican que la operación se realizó correctamente, similares a los siguientes:

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

La nueva ranura sincronizada tiene failover=true y, finalmente, se vuelve persistente (temporary=false), lo que garantiza que, si vuelves a cambiar más adelante, esta instancia estará lista.

Opcional: Realiza el cambio

  1. Ahora, vuelve a cambiar y haz que $PRIMARY_INSTANCE_NAME sea la instancia principal nuevamente.

    gcloud sql instances switchover $PRIMARY_INSTANCE_NAME \
      --project=$PROJECT
    
  2. Realiza la verificación después de la reversión.

    1. Verifica el estado de la instancia del suscriptor.

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

      La suscripción debería seguir activa, es decir, is_active = t.

    2. Verifica el estado de la ranura de la nueva instancia principal ($PRIMARY_INSTANCE_NAME).

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

      La ranura debe estar activa y el suscriptor conectado.

Solucionar problemas

Problema Soluciona problemas

Error en la réplica nueva (es decir, la instancia principal anterior) después del cambio:

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

Sigue los pasos que se indican en Limpia la ranura de replicación huérfana en la réplica nueva.