StackPractices
advanced Por Mathias Paulenko

Plantilla de Prueba de Failover Cross-Region

Plantilla tipo runbook para planificar, ejecutar y documentar una prueba de failover entre regiones con criterios de aborto y failback.

Temas: devops

Ejecuta tu próximo simulacro de failover entre regiones con esta plantilla y saldrás con evidencias en lugar de suposiciones. Se sitúa un nivel por debajo del Plan de Pruebas de Disaster Recovery, que define el alcance del programa y la cadencia de cumplimiento; esta página es el documento de ejecución para mover un servicio de su región primaria a la secundaria y de vuelta.

Visión General

Una prueba de failover que termina con un “el tráfico se movió, parece bien” no te dice casi nada. Una prueba útil deja un registro: cuánto tardó cada etapa, dónde se desvió el plan de la realidad y si lograste volver. Esta plantilla impone esa disciplina: asigna roles, fija puertas de go/no-go antes de que nadie toque producción, mide cada paso contra el objetivo de RTO y trata el failback como parte de la prueba, no como un trámite posterior.

Conviene fijar algunos términos antes de copiar nada:

  • Failover es mover el tráfico y la autoridad de escritura de la región primaria a la secundaria. En un simulacro es planificado; un incidente real nunca lo es, y de eso va el simulacro.
  • Failback es el viaje de regreso: restablecer la replicación, volver a promover la primaria original y mover el tráfico de vuelta sin perder los datos escritos mientras la secundaria estaba al mando.
  • RTO (recovery time objective) es cuánto tiempo puede estar degradado o caído el servicio. Mídelo desde que arranca el reloj de decisión, no desde el primer comando que ejecutas.
  • RPO (recovery point objective) es cuántos datos puedes permitirte perder, determinado directamente por el lag de replicación en el momento de la promoción.
  • Split-brain es el modo de fallo en que ambas regiones aceptan escrituras a la vez. Prevenirlo es un problema de fencing (aislamiento de escrituras), no de DNS.

La plantilla asume un stack con forma AWS (Route 53, Aurora, Auto Scaling) porque es a lo que apunta el script, pero cada sección tiene un equivalente en GCP o Azure. Donde no aplique a tu stack, borra la sección en lugar de rellenarla con texto que nadie leerá durante un incidente.

Cuándo Usar

Usa esta plantilla cuando:

  • Un servicio tiene un RTO/RPO contractual o regulatorio y necesitas un simulacro documentado para demostrar que puedes cumplirlo. Los auditores piden evidencias, y una copia completada de este documento es una evidencia.
  • Estás poniendo en marcha una región secundaria y quieres validarla en condiciones controladas antes de que importe.
  • La infraestructura cambió desde la última prueba: motor de base de datos nuevo, proveedor de DNS nuevo, un balanceador migrado, o un equipo que nunca ha ejecutado el procedimiento.
  • Un incidente pasado o un game day expuso carencias, y quieres pruebas de que están cerradas.

No la uses cuando:

  • El fallo que te preocupa es de una sola zona de disponibilidad. Ese caso lo cubre multi-AZ; ese escenario merece su propio simulacro, más barato.
  • El servicio no guarda estado y ya corre activo-activo entre regiones. En ese esquema nada se mueve; confías en health checks, no en un procedimiento.
  • La replicación entre regiones aún no está montada en la capa de datos. Arregla eso primero; un simulacro contra una secundaria fría mide velocidad de aprovisionamiento, no recuperación.
  • El canal de coordinación tiene que estar cubierto toda la ventana; un simulacro a medias produce resultados en los que se confía a medias.

La Plantilla

Copia el bloque siguiente a tu runbook, wiki o herramienta de incidentes y rellena cada valor entre corchetes antes de que se abra la ventana de prueba. Cualquier cosa que quede en blanco se convierte en una decisión que alguien toma bajo presión, que es justo lo que la plantilla pretende evitar.

# Prueba de Failover Cross-Region: `<nombre-servicio>`

## 1. Metadatos del Servicio

| Campo | Valor |
|-------|-------|
| Servicio | `<nombre-servicio>` |
| Región primaria | `us-east-1` |
| Región secundaria | `eu-west-1` |
| Objetivo RTO | `15 min` |
| Objetivo RPO | `5 min` |
| Replicación de datos | `Aurora Global / asíncrona` |
| Última prueba | `YYYY-MM-DD` |
| Responsable | `@equipo-o-persona` |

## 2. Roles

| Rol | Persona | Responsabilidad |
|-----|---------|-----------------|
| Dirección de prueba | | Lleva el reloj, decide go/no-go, puede abortar |
| Ejecución | | Corre el script, reporta cada paso |
| Validación de datos | | Revisa lag de replicación e integridad |
| Comunicación | | Página de estado, canal de interesados |
| Observación | | Registra la línea de tiempo, anota sorpresas |

## 3. Criterios Go/No-Go

La prueba solo avanza si TODO se cumple a T-30 min:

- [ ] Región secundaria sana (cómputo, réplica de base de datos, endpoints)
- [ ] Lag de replicación < 50% del objetivo RPO
- [ ] TTL del registro DNS ≤ 60s (verificado con `dig`, no asumido)
- [ ] Procedimiento de failback revisado y el ejecutor lo conoce
- [ ] Interesados notificados, página de estado lista
- [ ] Alguien tiene autoridad para abortar y lo dirá

## 4. Criterios de Aborto

Aborta de inmediato y vuelve atrás (o mantén el estado) si:

- Empieza un incidente real de producción en cualquiera de las regiones
- El lag de replicación supera el RPO tras la decisión de promoción
- Falla una verificación de integridad de datos post-failover
- Algún paso supera su presupuesto de tiempo por 2x sin causa conocida

## 5. Línea de Tiempo del Failover

| T+ | Acción | Verificar | Presupuesto |
|----|--------|-----------|-------------|
| 0 | Confirmar señal de fallo / declarar inicio | Dos señales independientes | 2 min |
| 2 | Fencing de la primaria: bloquear escrituras | Cero conexiones de escritura | 3 min |
| 5 | Promover base de datos secundaria | Acepta escrituras | 5 min |
| 10 | Escalar cómputo secundario a tamaño prod | Capacidad deseada alcanzada | 5 min |
| 15 | Actualizar DNS / enrutado a secundaria | `dig` desde 2+ ubicaciones | 2 min |
| 17 | Transacciones sintéticas contra el servicio | 100% éxito, 5 min | 5 min |
| 22 | Declarar failover completo, iniciar soak | — | — |
| 52 | Terminar soak, iniciar failback | Ver sección 6 | — |

## 6. Failback

| Paso | Acción | Verificación |
|------|--------|--------------|
| 1 | Restablecer replicación secundaria → primaria | Lag tendiendo a 0 |
| 2 | Esperar lag = 0, verificar checksums | Conteos de filas iguales |
| 3 | Fencing de escritores en secundaria | Cero conexiones de escritura |
| 4 | Devolver DNS a la primaria | `dig` lo confirma |
| 5 | Reducir secundaria a capacidad standby | Capacidad deseada |
| 6 | Confirmar replicación en estado estable | Lag < umbral |

## 7. Informe Post-Prueba

| Métrica | Objetivo | Real | Superado |
|---------|----------|------|----------|
| Detección a decisión | < 2 min | | |
| Decisión a promoción | < 10 min | | |
| Tiempo total de failover | < RTO | | |
| Pérdida de datos (lag al promover) | < RPO | | |
| Tiempo de failback | < 30 min | | |
| Errores durante el corte | < 0.5% | | |

### Sorpresas y desviaciones

- Qué tardó más de lo presupuestado y por qué:
- Qué paso no tenía procedimiento escrito:
- Qué alarma sonó o no sonó:
- Acciones pendientes (responsable, fecha):

Cómo Encaja la Prueba

Cada sección de la plantilla existe porque un failover real falló alguna vez ahí. La tabla de roles existe porque un ejecutor sin localizar convierte un RTO de 15 minutos en una búsqueda de 40 minutos de la persona correcta. La puerta go/no-go existe porque los simulacros que arrancan sobre una secundaria enferma producen una prueba fallida y un informe confuso. Alguien tiene que poder frenar el ejercicio si aparece un problema real de producción a mitad de la prueba; para eso están los criterios de aborto. Los tres apartados siguientes cubren dónde chocan con más fuerza la mecánica y el reloj en un failover.

RTO y RPO en la práctica

Piensa en el RTO como un presupuesto que vas gastando. Si tu objetivo son 15 minutos y solo la detección consume 5, todo lo demás dispone de 10 minutos en total. Por eso la tabla de tiempos presupuesta cada paso: la primera prueba casi siempre revela que el cuello de botella no es la promoción de base de datos que te preocupaba, sino las dos personas que no tenían claro quién podía dar el visto bueno. Escribe el paso de decisión explícitamente en la línea de tiempo, con un nombre asignado.

El RPO lo fija tu tecnología de replicación, no lo que escribas en el documento. Aurora Global Database reporta el lag con la métrica AuroraGlobalDBRPOLag de CloudWatch en milisegundos; la replicación por streaming de PostgreSQL expone replay_lag en el standby. Revisa la métrica real antes de la prueba, no un valor nominal del diagrama de arquitectura. Si el número del día de la prueba es peor que tu RPO declarado, el resultado honesto es “no-go” o una excepción documentada, no una anulación silenciosa.

Para un simulacro planificado sobre Aurora Global Database, prefiere switchover-global-cluster, que sincroniza la secundaria antes de promoverla y entrega RPO = 0. Reserva failover-global-cluster para el camino de desastre real, ya que acepta pérdida de datos hasta el lag actual. Ejercitar el camino de switchover toca casi todas las dependencias que importan y deja el simulacro recuperable.

DNS suele ser el cuello de botella

El cómputo y las bases de datos pueden promoverse en minutos; el DNS responde a un reloj que configuraste hace meses. Si el TTL del registro de failover es de 3600 segundos, un resolvedor que cacheó la respuesta antigua en T-1 seguirá mandando usuarios a una región muerta durante hasta una hora. Los health checks de Route 53 con políticas de enrutado por failover eliminan el paso manual por completo, y el enrutado por latencia o geolocalización reparte el radio de impacto para una audiencia global.

Dos prácticas se pagan solas: mantener el TTL del registro de failover en 60 segundos o menos todo el año (el coste son más consultas DNS, algo despreciable) y, durante la prueba, medir la propagación real desde varios puntos con dig contra resolvedores públicos como 8.8.8.8 y 1.1.1.1. El número que registres se convierte en la estimación real de propagación del año siguiente.

Fencing antes de promover

El split-brain es el peor resultado que un simulacro puede producir: ambas regiones escribiendo a la vez, con datos divergentes que reconciliar después. Aquí la secuencia importa más que cualquier comando. Bloquea primero las escrituras en la primaria (regla de security group, parámetro de base de datos, revocación de la cadena de conexión, lo que tu stack permita), confirma que las conexiones de escritura bajan a cero y solo entonces promueve la secundaria. Si la primaria es realmente inalcanzable, documenta que el fencing fue asumido y no verificado, y marca el riesgo residual en el informe.

Soak antes del failback

No tengas prisa por volver atrás. Un soak de 30 minutos en la secundaria saca a la luz los problemas que solo aparecen con tráfico real: cachés frías, secretos que faltan, un consumidor de cola que nunca se configuró en la región B. Esos hallazgos son la razón de ser del simulacro.

Script de Ejecución del Failover

El script de abajo se ocupa de los pasos mecánicos y deja a las personas observar y decidir. Cada valor llega por variable de entorno, --dry-run imprime cada acción sin tocar nada, y una ejecución real se niega a continuar hasta que alguien escribe FAILOVER en el prompt.

#!/usr/bin/env bash
# cross-region-failover.sh — simulacro controlado para Aurora Global + Route 53
# Requisitos: aws cli v2, jq, curl, dig, date de GNU (gdate en macOS).
# Uso: ./failover.sh --dry-run   y luego   ./failover.sh
set -euo pipefail

PRIMARY_REGION="${PRIMARY_REGION:-us-east-1}"
SECONDARY_REGION="${SECONDARY_REGION:-eu-west-1}"
GLOBAL_CLUSTER_ID="${GLOBAL_CLUSTER_ID:?Define GLOBAL_CLUSTER_ID con el nombre del clúster global Aurora}"
SECONDARY_CLUSTER_ARN="${SECONDARY_CLUSTER_ARN:?Define SECONDARY_CLUSTER_ARN del clúster a promover}"
SECONDARY_CLUSTER_ID="${SECONDARY_CLUSTER_ID:?Define SECONDARY_CLUSTER_ID (nombre del clúster para métricas de lag)}"
HOSTED_ZONE_ID="${HOSTED_ZONE_ID:?Define HOSTED_ZONE_ID de la zona Route 53}"
DNS_RECORD="${DNS_RECORD:?Define DNS_RECORD, p. ej. api.example.com}"
SECONDARY_CNAME="${SECONDARY_CNAME:?Define SECONDARY_CNAME, el endpoint regional de destino}"
SECONDARY_HEALTH_URL="${SECONDARY_HEALTH_URL:?Define SECONDARY_HEALTH_URL, p. ej. https://eu-west-1.api.internal/health}"
ASG_NAME="${ASG_NAME:?Define ASG_NAME del Auto Scaling group secundario}"
ASG_DESIRED="${ASG_DESIRED:-10}"
RPO_MAX_MS="${RPO_MAX_MS:-300000}"   # 5 minutos en milisegundos
DRY_RUN=0

for arg in "$@"; do
  case "$arg" in
    --dry-run) DRY_RUN=1 ;;
    *) echo "Flag desconocido: $arg" >&2; exit 2 ;;
  esac
done

log() { printf '%s %s\n' "$(date -u +%H:%M:%SZ)" "$*"; }
run() { if [ "$DRY_RUN" -eq 1 ]; then log "DRY-RUN: $*"; else "$@"; fi; }

if [ "$DRY_RUN" -eq 0 ]; then
  read -r -p "Escribe FAILOVER para promover $SECONDARY_REGION: " answer
  [ "$answer" = "FAILOVER" ] || { log "Abortado por el operador."; exit 1; }
fi

START=$(date +%s)

# 1. Salud de la secundaria
log "[1/6] Comprobando salud de la región secundaria"
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 "$SECONDARY_HEALTH_URL" || true)
[ "$code" = "200" ] || { log "FALLO: secundaria no sana (HTTP ${code:-ninguno})"; exit 1; }
log "  secundaria sana"

# 2. Lag de replicación dentro del RPO (AuroraGlobalDBRPOLag, en milisegundos)
log "[2/6] Leyendo lag de replicación desde CloudWatch"
LAG_MS=$(aws cloudwatch get-metric-statistics \
  --region "$PRIMARY_REGION" --namespace AWS/RDS \
  --metric-name AuroraGlobalDBRPOLag \
  --dimensions Name=DBClusterIdentifier,Value="$SECONDARY_CLUSTER_ID" \
  --start-time "$(date -u -d '2 minutes ago' +%FT%TZ)" \
  --end-time "$(date -u +%FT%TZ)" --period 60 --statistics Maximum \
  --query 'Datapoints[-1].Maximum' --output text)
[ "$LAG_MS" != "None" ] || { log "FALLO: sin datos de lag"; exit 1; }
log "  lag = ${LAG_MS} ms (presupuesto ${RPO_MAX_MS} ms)"
awk -v lag="$LAG_MS" -v max="$RPO_MAX_MS" 'BEGIN{exit !(lag <= max)}' \
  || { log "FALLO: el lag supera el presupuesto RPO"; exit 1; }

# 3. Promover la base de datos secundaria (switchover planificado; para un
#    incidente no planeado usa failover-global-cluster, y para réplicas
#    de lectura sin clúster global, promote-read-replica-db-cluster)
log "[3/6] Ejecutando switchover del clúster global a la secundaria"
run aws rds switchover-global-cluster \
  --global-cluster-identifier "$GLOBAL_CLUSTER_ID" \
  --target-db-cluster-identifier "$SECONDARY_CLUSTER_ARN"
if [ "$DRY_RUN" -eq 0 ]; then
  aws rds wait db-cluster-available \
    --region "$SECONDARY_REGION" \
    --db-cluster-identifier "$SECONDARY_CLUSTER_ARN"
fi
log "  clúster secundario promovido"

# 4. Escalar el cómputo secundario
log "[4/6] Escalando el ASG secundario a $ASG_DESIRED"
run aws autoscaling set-desired-capacity \
  --region "$SECONDARY_REGION" \
  --auto-scaling-group-name "$ASG_NAME" \
  --desired-capacity "$ASG_DESIRED"

# 5. Mover el DNS
log "[5/6] Actualizando el registro Route 53 $DNS_RECORD"
CHANGE_BATCH=$(jq -n --arg n "$DNS_RECORD" --arg v "$SECONDARY_CNAME" '{
  Changes: [{Action: "UPSERT", ResourceRecordSet: {
    Name: $n, Type: "CNAME", TTL: 60,
    ResourceRecords: [{Value: $v}]}}]}')
run aws route53 change-resource-record-sets \
  --hosted-zone-id "$HOSTED_ZONE_ID" --change-batch "$CHANGE_BATCH"

# 6. Verificar resolución y tráfico
log "[6/6] Verificando DNS y tráfico"
for i in 1 2 3 4 5 6; do
  resolved=$(dig +short "$DNS_RECORD" @1.1.1.1 | tail -1)
  [ "$resolved" = "$SECONDARY_CNAME" ] && break
  log "  intento $i: obtuve '${resolved:-nada}', esperando 10s"
  sleep 10
done
[ "$resolved" = "$SECONDARY_CNAME" ] || { log "FALLO: el DNS no convergió"; exit 1; }

code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 "https://$DNS_RECORD/health" || true)
log "  salud pública: HTTP ${code:-ninguno}"
log "=== Completado en $(( $(date +%s) - START ))s — soak de 30 min antes del failback ==="

Cómo leer el script

Los pasos 1 y 2 son las puertas go/no-go en forma ejecutable: si la secundaria no sirve un health check o la réplica va con más retraso que el presupuesto RPO, el script sale antes de cambiar nada. El paso 3 usa switchover-global-cluster porque un simulacro es una operación planificada; los comentarios nombran los comandos para los otros dos casos (failover-global-cluster para recuperación no planificada, o promote-read-replica-db-cluster cuando la secundaria es una réplica de lectura entre regiones independiente y no un miembro de Aurora Global). Los pasos 4 y 5 dimensionan el cómputo y mueven el DNS, y el paso 6 sondea un resolvedor público hasta que el registro converge en lugar de fiarse de la respuesta de la API.

Mantén set -euo pipefail y las guardas :? en las variables. Son lo que convierte un entorno medio configurado en un error limpio al arrancar, en vez de un failover a medias.

Flujo de Decisión del Failover

flowchart diagram: Señal de fallo en la primaria

En la práctica, los simulacros mueren en esos dos rombos. El primero es admitir que la caída es real (la gente espera, con la esperanza de que se resuelva solo). El segundo es el lag: todos los planes dicen “revisa el lag”, pero ese paso solo significa algo si alguien decidió de antemano qué pasa cuando el número sale en rojo.

Variantes de Arquitectura

ArquitecturaCómo funciona el failoverPerfil RTO/RPOPerfil de coste
Backup y restoreReconstruir la región desde snapshotsHoras / horasEl más bajo
Pilot lightLos datos replican, el cómputo apagadoDecenas de minutos / minutosBajo
Warm standbyCopia reducida siempre en marchaMinutos / segundosMedio
Activo-pasivo (en caliente)Secundaria completa en esperaMinutos / segundosAlto
Activo-activoAmbas sirven tráfico, se redirige al fallarCasi cero / casi ceroEl más alto
Basado en celdasUsuarios fijados a una celda, se evacúa la celdaMinutos / segundosEl más alto, más capa de enrutado

La línea de tiempo de la plantilla asume warm standby o activo-pasivo, que es donde aterriza la mayoría de los equipos: un pilot light que tarda 40 minutos en calentar no puede cumplir un RTO de 15 por muy bueno que sea el runbook. Si tu servicio es por celdas, sustituye los pasos de DNS por evacuación de celda; las puertas go/no-go, el fencing, la captura de evidencias y el failback siguen aplicando sin cambios.

Escenarios de Prueba que Merecen la Pena

El simulacro no está para ensayar solo el camino feliz. Rota entre estos escenarios en las pruebas trimestrales:

  1. Caída regional limpia. Simula una caída total (blackhole del ALB primario o bloquéalo con una ACL de red). Mide el RTO de base y confirma que el orden del runbook sigue funcionando.
  2. Degradada pero viva. Limita la primaria a un 20% de éxito. Es la decisión más difícil: ¿un 20% de éxito justifica el corte? Los equipos sin umbral escrito conmutan demasiado tarde o se pasan la ventana discutiendo.
  3. Replicación atrasada. Pausa la replicación unos minutos y luego inicia la prueba. La verificación de lag debería bloquear la promoción hasta que la réplica se ponga al día. Si no lo hace, tu puerta es decorativa.
  4. Sorpresa de DNS. Ejecuta la prueba la semana después de que alguien suba el TTL “temporalmente”. El tiempo real de propagación reemplaza al asumido en tus cuentas de RTO.
  5. Failback bajo carga. Deja el tráfico sintético corriendo durante todo el failback. Los datos escritos en la secundaria durante el soak tienen que sobrevivir el viaje de vuelta; aquí es donde la verificación por conteo de filas y checksum se gana su sitio.
  6. Persona ausente. Ejecuta el simulacro sin el ejecutor habitual. Si la prueba no puede avanzar sin un ingeniero concreto, eso es un hallazgo que corregir, no un éxito que registrar.

Captura de Evidencias

Cuando llegue un auditor o una revisión post-incidente, te va a pedir el informe post-prueba. Durante la prueba, el observador registra las horas reales de cada paso de la línea de tiempo, el valor de lag en el momento de la promoción, las mediciones de propagación DNS desde al menos dos resolvedores y las tasas de error durante la ventana de corte. Adjunta capturas de los dashboards y el log de salida del script al documento completado.

Compara lo real con los objetivos con honestidad. Que una prueba falle el RTO por cuatro minutos con el motivo documentado vale más que una que lo cumplió porque todos acordaron no mirar el reloj de cerca. Convierte cada sorpresa en una acción con responsable y fecha; esas acciones son el retorno del coste del simulacro.

Lo que Funciona

  • Ejecuta el simulacro en producción al menos cada trimestre. Las pruebas en staging verifican el script; solo producción verifica la ruta de carga, el DNS real y el tráfico real.
  • Mantén la secundaria lo bastante caliente para cumplir el RTO. Si la secundaria necesita 40 minutos para ser útil, tu RTO de 15 ya se fue antes de empezar el simulacro.
  • Escribe los criterios de aborto antes de la ventana, y asegúrate de que quien tiene autoridad para abortar sabe que la tiene.
  • Prueba el failback siempre. El camino de vuelta es donde viven la dirección de replicación no probada, los estados de secuencia olvidados y los bugs de split-brain.
  • Automatiza la detección y la captura de evidencias; mantén humana la decisión de promoción hasta que la tasa de falsos positivos de tus señales sea lo bastante baja para confiar en ella.

Errores Comunes

  • Tratar el failover como si fuera solo DNS. Mover tráfico es el último paso; datos, cómputo y fencing de escrituras van primero, en ese orden.
  • Dejar el registro de failover con un TTL de 3600 segundos hasta el día de la prueba y descubrir que el RTO nunca fue alcanzable.
  • Promover antes del fencing: así es como un simulacro acaba creando el split-brain que debía prevenir.
  • Saltarse el soak. Declarar victoria tras el primer 200 pasa por alto los fallos de caché, los secretos regionales caducados y los consumidores de cola que solo expone el tráfico real.
  • Reutilizar el mismo escenario cada trimestre, con lo que el equipo se vuelve bueno en el simulacro en lugar de bueno en el failover.
  • Cerrar el informe sin acciones pendientes. Lo que sorprende y no se documenta reaparece en la siguiente caída real.

Troubleshooting

  • La réplica no se promueve. En Aurora Global Database, una secundaria sin instancias (headless) no puede ser el destino de una promoción hasta que tenga al menos una instancia de base de datos, y el switchover exige versiones de motor coincidentes entre primaria y destino. Revisa el estado del clúster en la salida de describe-global-clusters antes de reintentar; un clúster en estado modifying no acepta la llamada.
  • El DNS se actualizó pero el tráfico sigue llegando a la primaria. Casi siempre es una respuesta cacheada: un TTL por encima de 60, un resolvedor que respeta registros caducados o una capa de CDN con su propio TTL de origen delante de Route 53. Mide con dig +trace y contra resolvedores públicos, y revisa cualquier CDN o global accelerator entre los clientes y el DNS.
  • El lag de replicación crece tras el failover. La nueva primaria ahora alimenta réplicas en la dirección contraria, y una capacidad secundaria subdimensionada (clase de instancia, IOPS, red) aparece como lag en los picos de escritura. El soak es donde aparecen las sorpresas de lag; vigílalo durante toda la ventana, no solo en la promoción.
  • Los health checks pasan pero los usuarios ven errores. Diferencias regionales: un secreto que falta en el almacén de parámetros de la secundaria, una política IAM que no existe en la región B, o una dependencia que nunca se replicó. Mantén una checklist de paridad por región y compárala antes de cada simulacro.
  • El failback deja escrituras huérfanas. Si algo escribió en la primaria antigua después del fencing, esas escrituras no están en la historia de la nueva primaria. La reconciliación consiste en identificar registros divergentes por timestamp o log de transacciones y reproducirlos o descartarlos deliberadamente; deja la decisión en el informe.
  • El script sale antes de tiempo. Lee qué puerta falló. Un fallo de health check significa arreglar primero la secundaria; un fallo de lag significa esperar o aceptar la pérdida explícitamente. Nunca puentees una puerta editando el script a mitad de prueba.

Mantener la Plantilla al Día

Asigna al documento un responsable y una fecha de revisión. Revísalo después de cada simulacro y de cada incidente relevante, retira los pasos que la infraestructura dejó atrás y rellena de nuevo los presupuestos de tiempo cuando los valores medidos deriven. Una plantilla que describe el stack del año pasado es peor que no tener plantilla, porque le presta una confianza falsa a quien la sostiene.

Lectura Adicional

Preguntas frecuentes

¿Con qué frecuencia debemos ejecutar una prueba de failover entre regiones?

Trimestralmente para cualquier cosa con RTO contractual, mensualmente para servicios tier-0 como pagos. Ejecútala en producción con tráfico real o sintético realista; un simulacro contra una copia de staging sin carga demuestra que el script corre, no que la región puede sostener el servicio.

¿Debería el failover estar totalmente automatizado?

Automatiza la detección, la captura de evidencias y cada paso mecánico. Mantén humana la decisión de promoción hasta conocer la tasa de falsos positivos de tus señales; conmutar por un parpadeo del monitoreo provoca la caída que intentabas evitar. Los servicios realmente stateless con RTO por debajo de dos minutos son la excepción que tolera automatización completa.

¿Cuál es la diferencia entre switchover y failover en Aurora?

El switchover es el camino planificado: Aurora sincroniza la secundaria con la primaria antes de promoverla, así que el RPO es cero y es la herramienta correcta para simulacros y rotación regional. El failover es para recuperación no planificada y acepta el lag de replicación existente en ese momento. Para una réplica de lectura entre regiones independiente que no forma parte de un clúster global, promote-read-replica-db-cluster es el comando de promoción equivalente.

¿Cómo manejamos el retraso de propagación del DNS?

Deja el TTL del registro de failover en 60 segundos o menos todo el año, no solo el día de la prueba. Prefiere health checks de Route 53 con enrutado por failover para que el cambio lo dirija la salud, no alguien editando un registro bajo presión. Mide la propagación real en cada simulacro desde varios resolvedores y registra el número; los resolvedores que ignoran tu TTL lo estirarán más allá de lo configurado.

¿Qué pasa si el lag de replicación supera el RPO cuando queremos hacer failover?

Cuando el lag se pone en rojo, el failover deja de ser la pregunta; la pregunta pasa a ser cuántos datos aceptas perder. Opciones: esperar a que la réplica se ponga al día si la caída es parcial, aceptar la pérdida documentada y registrarla en el informe, o abortar la prueba. Lo que no puedes hacer es promover de todas formas y llamarlo un éxito; así es como los simulacros enseñan la lección equivocada.

¿Cómo prevenimos el split-brain durante la prueba?

Haz fencing de la primaria antes de promover: revoca el acceso de escritura, bloquea el endpoint de escritura o pon la base de datos en solo lectura, y confirma que las conexiones de escritura llegan a cero. Con topología de escritor único, solo una región acepta escrituras a la vez. Si la primaria es inalcanzable y el fencing no puede verificarse, anótalo como riesgo residual conocido.

¿Qué hacemos con los datos escritos en la secundaria durante el soak?

Todo lo escrito durante el soak tiene que volver por la replicación. Durante el failback, espera a que el lag de replicación inversa llegue a cero y verifícalo con conteos de filas o checksums en unas pocas tablas de alto valor antes de devolver el DNS. Las escrituras que cayeron en la primaria antigua después del fencing necesitan una pasada de reconciliación, decidida registro a registro, no según qué base de datos parezca más nueva.

¿Podemos ejecutar esta prueba sin tocar el tráfico de producción?

Puedes ejecutar la mecánica (promoción, DNS, escalado) contra un endpoint sintético, pero eso solo valida la fontanería del runbook. No detectará cachés frías, configuración regional ausente ni déficits de capacidad. Corre la versión sin tráfico como ensayo, y luego programa un simulacro en producción dentro de una ventana para obtener el resultado que cuenta.