Comprendiendo y Ejecutando Escenarios de Failover vs. Switchover en PostgreSQL

Aprende cuándo usar switchover o failover en PostgreSQL, cómo verificar la seguridad de la réplica y cómo evitar el split-brain durante eventos de alta disponibilidad.

Comprendiendo y Ejecutando Escenarios de Failover vs. Switchover en PostgreSQL

La diferencia entre failover y switchover en PostgreSQL no es académica cuando eres tú quien tiene el buscapersonas. Un switchover es planificado: aún tienes un primario saludable, puedes drenar escrituras y elegir el mejor momento para mover el rol de escritura a un standby. Un failover es lo que haces cuando el primario ha desaparecido, es inalcanzable o no es seguro mantenerlo sirviendo tráfico.

Esa única diferencia lo cambia todo. Durante un switchover, tu tarea principal es la paciencia: demostrar que el standby se ha puesto al día antes de la promoción. Durante un failover, tu tarea principal es la contención: asegurarte de que el antiguo primario no pueda seguir aceptando escrituras después de que se promocione un standby. La mayoría de los incidentes desagradables de alta disponibilidad en PostgreSQL provienen de apresurar una de esas dos tareas.

Fundamentos de Replicación: La Base de la Alta Disponibilidad

La Alta Disponibilidad de PostgreSQL se basa en la replicación en streaming, donde un servidor actúa como Primario (o Maestro) y uno o más servidores actúan como Standbys (o Réplicas). El Primario transmite registros del registro de escritura anticipada (WAL) a los Standbys para mantenerlos sincronizados.

Para gestionar estos roles de manera efectiva, se necesitan configuraciones específicas tanto en los nodos primarios como en las réplicas:

Configuraciones Críticas

Estas configuraciones gobiernan cómo opera la replicación y cómo los nodos se identifican entre sí:

  • wal_level: Debe establecerse en replica o superior (idealmente logical si se utilizan herramientas que requieren decodificación lógica) en el Primario.
  • max_wal_senders: Define el número máximo de conexiones de emisores WAL concurrentes. Dimensiónalo para todos los standbys físicos, copias de seguridad base y herramientas de replicación que puedan conectarse al mismo tiempo.
  • hot_standby: Debe establecerse en on en el archivo postgresql.conf del servidor standby para permitir consultas de solo lectura durante la replicación.
  • synchronous_commit: Controla cuándo se confirma una transacción. Solo proporciona una mayor durabilidad con replicación síncrona correctamente configurada; por sí solo, no hace que un standby esté al día.
  • primary_conninfo: Se establece en el standby, detallando la información de conexión (host, puerto, usuario, contraseña) para conectarse al Primario actual.

Mejor Práctica: Coloca un endpoint estable frente a PostgreSQL, como HAProxy, PgBouncer detrás de una IP virtual, un registro de descubrimiento de servicios o la abstracción de servicios de tu plataforma. Las aplicaciones no deberían necesitar saber qué nodo es primario hoy.

Switchover: La Transición Planificada

Un Switchover es un proceso controlado y elegante donde el nodo Primario activo se da de baja intencionalmente y un Standby designado es promocionado para ocupar su lugar. Este procedimiento se utiliza típicamente para mantenimiento planificado, actualizaciones de versión o reemplazos de hardware.

Pasos para un Switchover Controlado

El objetivo de un switchover es garantizar cero pérdida de datos esperando a que todas las transacciones en vuelo se repliquen antes de la promoción.

  1. Detener Escrituras en el Primario Actual: El primer paso es evitar que se confirmen nuevas transacciones en el Primario actual. Esto se logra a menudo estableciendo default_transaction_read_only = on o cerrando temporalmente las conexiones de los clientes.
  2. Esperar la Puesta al Día de la Replicación: Asegúrate de que el Standby designado haya recibido y aplicado todos los registros WAL restantes del Primario. Puedes verificar el retraso de replicación usando pg_stat_replication en el Primario o examinando el estado de recuperación del standby.
  3. Iniciar la Promoción del Standby: Ejecuta el comando para promocionar el servidor Standby elegido al rol de Primario. El comando específico depende de la herramienta de gestión utilizada (por ejemplo, pg_ctl promote o un comando del gestor de clúster).
  4. Reconfigurar el Antiguo Primario: Una vez que el Standby se promociona exitosamente, el antiguo Primario debe reconfigurarse para seguir al nuevo Primario como un Standby. Esto implica actualizar su primary_conninfo.
  5. Redirigir las Aplicaciones: Actualiza el balanceador de carga o el pool de conexiones para dirigir el tráfico al nuevo servidor Primario.

Una lista de verificación práctica para un switchover suele parecer más ordinaria que dramática. Anuncia una breve pausa de escritura, detén los trabajos en segundo plano que siguen escribiendo, pon la aplicación en modo de mantenimiento o drena el pool de escritores, y luego verifica la posición de replicación. En el antiguo primario, pg_stat_replication muestra si el standby ha recibido y vaciado el WAL. En el standby, pg_last_wal_receive_lsn() y pg_last_wal_replay_lsn() te ayudan a ver si el WAL simplemente ha llegado o si realmente se ha reproducido.

No promociones un standby solo porque está conectado. Un standby puede estar conectado y aún así estar segundos o minutos atrasado si está reproduciendo una transacción grande, esperando E/S de disco o recuperándose después de una pausa de red. Para un switchover planificado, quieres que la reproducción esté al día antes de la promoción. Si hay sesiones de solo lectura ejecutándose en el standby, verifica también si las consultas de larga duración están retrasando la reproducción del WAL.

Después de la promoción, prueba el rol directamente:

SELECT pg_is_in_recovery();

El nodo promocionado debería devolver false. El nodo degradado, después de haber sido reconstruido o reconectado como standby, debería devolver true.

El lado de la aplicación merece el mismo cuidado. Antes del switchover, conoce cómo los clientes descubren el escritor. Si se conectan a un nombre DNS, comprende el TTL de DNS y si los clientes almacenan en caché las direcciones por más tiempo del esperado. Si se conectan a través de PgBouncer, decide si necesitas pausar el pool, recargarlo o reiniciarlo. Si usas HAProxy, asegúrate de que la verificación de salud pruebe el estado de escritura, no solo si el puerto 5432 está abierto. Un standby con PostgreSQL en ejecución no es un objetivo de escritura válido.

También me gusta anotar el punto de reversión. Antes de la promoción, generalmente puedes detenerte, reabrir escrituras en el antiguo primario e intentarlo de nuevo más tarde. Después de la promoción, la reversión se convierte en un nuevo cambio de rol, no en una simple deshacer. Eso no significa que la promoción sea peligrosa; significa que el operador debe saber de qué lado de la línea se encuentra.

Failover: La Respuesta de Emergencia

Failover es un procedimiento inmediato y reactivo que se desencadena cuando el servidor Primario actual falla inesperadamente (por ejemplo, fallo de hardware, partición de red, error de software) y no puede recuperarse rápidamente.

El failover conlleva inherentemente un mayor riesgo de pérdida de datos porque no hay garantía de que las últimas transacciones confirmadas hayan tenido tiempo de transmitirse a los Standbys antes del fallo.

Ejecutando un Failover de Emergencia

Los procedimientos de failover están diseñados para la velocidad y la recuperación, a menudo utilizando herramientas especializadas para automatizar la promoción.

  1. Determinar el Estado del Antiguo Primario: Verifica que el Primario original realmente no está disponible y no solo experimenta un problema de red transitorio (esto evita escenarios peligrosos de 'split-brain').
  2. Seleccionar el Mejor Standby: Elige el Standby con el menor retraso de replicación (el que esté más adelantado en el flujo de WAL).
  3. Promocionar el Standby: Promociona inmediatamente el Standby seleccionado usando el comando de promoción (pg_ctl promote).
  4. Manejar la Pérdida de Datos (Si es Necesario): Si el clúster utiliza replicación asíncrona, los datos perdidos en el Primario fallido podrían necesitar ser reconciliados manualmente o simplemente aceptados, dependiendo de la tolerancia de la aplicación.
  5. Reconfigurar el Antiguo Primario: Una vez que el Primario original se recupera, debe limpiarse, reinicializarse (a menudo requiriendo una copia de seguridad base del nuevo Primario) y configurarse para seguir al nuevo Primario.

La parte difícil del failover no es escribir pg_ctl promote. La parte difícil es decidir que el antiguo primario debe ser tratado como inseguro hasta que se demuestre lo contrario. Si el antiguo primario sigue funcionando pero está aislado de la aplicación o del standby, puedes obtener un split-brain: dos servidores PostgreSQL escribibles aceptando historias diferentes. Una vez que eso sucede, PostgreSQL no fusionará las historias por ti. Estás mirando una reconciliación manual de datos o restaurar un lado desde una copia de seguridad.

En un incidente real, prefiero pasar un minuto extra aislando el antiguo primario que pasar el día siguiente explicando por qué dos registros de pedidos no coinciden. El aislamiento puede significar apagar la VM antigua, desconectar su interfaz de red, deshabilitar el endpoint de escritura o usar un mecanismo de nube/proveedor que garantice que el host antiguo no pueda recibir escrituras. El método exacto depende de tu infraestructura, pero el requisito es simple: antes de que los clientes escriban en el nuevo primario, el antiguo primario no debe ser escribible por esos clientes.

Después del failover, espera limpieza. Si el antiguo primario vuelve, no lo apuntes casualmente al nuevo primario esperando que se ponga al día. Puede contener WAL que pertenece a la línea de tiempo antigua. En muchos entornos, el camino más seguro es pg_rewind si se cumplen los requisitos previos, o una copia de seguridad base fresca del nuevo primario si no.

Un detalle que se pasa por alto durante el trabajo de emergencia es la historia de los slots de replicación. Si el antiguo primario usaba slots de replicación física para los standbys, esos slots no se mueven mágicamente con el standby promocionado a menos que tu herramienta de alta disponibilidad los gestione. Después del failover, verifica si el nuevo primario tiene los slots que tus standbys supervivientes necesitan, y verifica si algún slot abandonado está reteniendo WAL para siempre. Un slot olvidado puede llenar un disco horas después de que la interrupción visible haya terminado.

Usa la misma disciplina para las copias de seguridad. Una vez que el clúster tiene un nuevo primario, confirma que las copias de seguridad y el archivado de WAL ahora siguen a ese primario. Un failover que restaura el servicio pero silenciosamente detiene las copias de seguridad es solo media recuperación.

Herramientas para una Promoción Segura: Repmgr vs. Patroni

Si bien la promoción manual usando pg_ctl es posible, los entornos robustos de alta disponibilidad dependen de herramientas dedicadas para gestionar la coreografía compleja requerida para el failover y el switchover, manejando automáticamente los cambios de configuración y la gestión del estado del clúster.

Repmgr (Replication Manager)

repmgr es una herramienta ligera que ayuda a registrar nodos, monitorear la replicación y realizar cambios de rol controlados. Los comandos exactos dependen de la versión y la disposición del clúster, pero el patrón común es:

  • Switchover: Ejecuta un repmgr standby switchover planificado desde el standby que debería convertirse en primario, después de confirmar la salud de la replicación.
  • Failover: Permite que repmgrd realice un failover automático solo si se comprenden y prueban el comportamiento de aislamiento y testigo/quórum.

Patroni

Patroni utiliza Almacenes de Consenso Distribuido (como etcd, ZooKeeper o Consul) para gestionar el estado del clúster, eligiendo automáticamente un nuevo Primario tras la detección de fallos. Patroni automatiza en gran medida tanto los switchovers como los failovers a través de llamadas API o operadores de Kubernetes, reduciendo drásticamente la intervención manual.

Ejemplo usando Patroni (Comando de Promoción Conceptual):

# Desencadenando un switchover a través de la API REST de Patroni
curl -X POST http://patroni-api-endpoint/switchover -H "Content-Type: application/json" -d '{"target": "standby_node_name"}'

Advertencia sobre Split-Brain: El mayor peligro durante el failover automatizado es el escenario de 'split-brain', donde dos nodos creen erróneamente que son el Primario debido a una partición de red. Herramientas como Patroni mitigan esto usando mecanismos de quórum, mientras que las configuraciones manuales requieren mecanismos de aislamiento estrictos (como controles de energía) para garantizar que solo exista un Primario.

Resumen de Diferencias

Característica Switchover (Planificado) Failover (Emergencia)
Desencadenante Mantenimiento, actualización, elección administrativa Fallo del Primario (caída, interrupción)
Riesgo de Pérdida de Datos Casi Cero (si se sincroniza adecuadamente) Medio a Alto (depende del modo de replicación)
Expectativa de Tiempo de Inactividad Tiempo de inactividad corto y controlado Tiempo de inactividad inmediato y reactivo
Preparación Requiere coordinación previa y confirmación de sincronización WAL Requiere acción inmediata y dependencia del estado del Standby

Un Pequeño Runbook que Puedes Adaptar

Para un switchover planificado, un runbook compacto podría verse así:

  1. Confirma que el standby elegido está saludable y reproduciendo WAL.
  2. Pausa las escrituras de la aplicación y los trabajos en segundo plano.
  3. Confirma que la reproducción de la replicación se ha puesto al día.
  4. Promociona el standby a través de la herramienta de alta disponibilidad.
  5. Mueve el endpoint de escritura.
  6. Confirma que pg_is_in_recovery() es false en el nuevo primario.
  7. Reconstruye o rebobina el antiguo primario como standby.
  8. Reanuda las escrituras y observa errores, replicación y conteos de conexiones.

Para failover, el orden cambia:

  1. Confirma que el primario ha fallado o es inseguro.
  2. Aísla el antiguo primario.
  3. Elige el standby más avanzado.
  4. Promociónalo a través de la herramienta de alta disponibilidad.
  5. Mueve el endpoint de escritura una vez.
  6. Confirma que las escrituras funcionan en el nuevo primario.
  7. Verifica réplicas, slots, copias de seguridad y archivado de WAL.
  8. Reintroduce el antiguo primario solo a través de rebobinado o reconstrucción.

Los comandos varían según las herramientas, pero las propiedades de seguridad no. Un primario escribible, estado de replicación conocido, enrutamiento de cliente probado y una forma limpia de traer de vuelta los nodos fallidos.

Antes de confiar en cualquier diseño de alta disponibilidad, ensaya ambos caminos en un entorno que no sea de producción. Un simulacro de switchover debería demostrar que las aplicaciones se reconectan limpiamente, el antiguo primario puede volverse un standby nuevamente y el monitoreo sigue el nuevo rol. Un simulacro de failover debería demostrar algo más estricto: el primario fallido está aislado, el standby elegido para la promoción es el mejor candidato disponible, el endpoint de escritura de la aplicación se mueve una vez y el antiguo primario no puede reincorporarse sin rebobinado o reconstrucción.

Los equipos de alta disponibilidad de PostgreSQL más seguros tratan el failover como un flujo de trabajo operativo probado, no como un comando heroico escrito durante una interrupción.