Una base de datos productiva debe sobrevivir a la caída de su servidor primario sin intervención manual. La alternativa al script casero ("si pings fallan, hacer pg_promote") es un orquestador robusto: Patroni, junto con un DCS (Distributed Configuration Store) como etcd, gestiona el cluster con garantías de seguridad y trazabilidad.
El problema del failover manual
Sin orquestación, el flujo típico ante una caída es:
- 1. Alguien se da cuenta de que el primario no responde.
- 2. Verifica que la réplica está al día.
- 3. Ejecuta
pg_ctl promoteo equivalente. - 4. Reconfigura las aplicaciones para apuntar a la nueva IP.
- 5. Si vuelve el viejo primario, hay que evitar el split-brain (dos primarios escribiendo).
Cada paso es una oportunidad para errores humanos. Patroni automatiza todo el flujo y añade salvaguardas que un script casero no contempla.
Arquitectura: Patroni + DCS
Un cluster Patroni consta de tres componentes:
- Nodos PostgreSQL con un demonio Patroni en cada uno.
- DCS (etcd, Consul, ZooKeeper o Kubernetes API) que mantiene el estado distribuido del cluster.
- Proxy (HAProxy, pgBouncer, AWS NLB) que enruta a la IP del leader actual.
flowchart TB
A[Aplicacion] --> B[HAProxy]
B -->|leader=pg-1| C[Nodo pg-1<br/>PRIMARY]
B -.->|standby| D[Nodo pg-2<br/>STANDBY]
B -.->|standby| E[Nodo pg-3<br/>STANDBY]
C --> F[(etcd cluster<br/>quorum 3 nodos)]
D --> F
E --> F
F -->|leader key TTL| C
El DCS mantiene una clave leader con un TTL corto (15-30 segundos). El nodo primario renueva el TTL constantemente. Si deja de hacerlo, las réplicas detectan la expiración, una de ellas adquiere la clave (leader election) y Patroni la promueve automáticamente.
Instalación básica
Patroni se distribuye como paquete pip:
pip install patroni[etcd]
Cada nodo necesita un fichero YAML de configuración. Un ejemplo mínimo para un cluster de tres nodos:
scope: produccion-cluster
namespace: /service/
name: pg-1
restapi:
listen: 0.0.0.0:8008
connect_address: 10.0.0.1:8008
etcd:
hosts: 10.0.0.10:2379,10.0.0.11:2379,10.0.0.12:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
parameters:
max_connections: 200
wal_level: replica
hot_standby: "on"
max_wal_senders: 10
max_replication_slots: 10
wal_keep_size: 1GB
postgresql:
listen: 0.0.0.0:5432
connect_address: 10.0.0.1:5432
data_dir: /var/lib/postgresql/data
bin_dir: /usr/lib/postgresql/16/bin
authentication:
replication:
username: replicator
password: <secret>
superuser:
username: postgres
password: <secret>
Las contraseñas reales se gestionan con secret managers (Vault, AWS Secrets Manager, Kubernetes Secrets). Nunca se comprometen en repositorios.
Comandos principales
Patroni añade un cliente CLI patronictl para operar el cluster:
# Estado del cluster
patronictl -c /etc/patroni.yml list
# Member | Host | Role | State | TL | Lag
# pg-1 | 10.0.0.1 | Leader | running | 12 | 0
# pg-2 | 10.0.0.2 | Replica | running | 12 | 0
# pg-3 | 10.0.0.3 | Replica | running | 12 | 0
# Failover manual planificado (mantenimiento)
patronictl -c /etc/patroni.yml switchover --master pg-1 --candidate pg-2
# Reinicializar una replica desde cero
patronictl -c /etc/patroni.yml reinit produccion-cluster pg-3
# Pausar el cluster (deshabilitar failover automatico)
patronictl -c /etc/patroni.yml pause
El switchover es la operación segura para mantenimiento: se asegura de que la nueva primaria esté al día antes de promoverla y degradar la antigua. Failover es el escenario de fallo no planificado.
Cómo se evita el split-brain
El split-brain (dos nodos creyéndose primarios simultáneamente y escribiendo) es el peor escenario en HA. Patroni lo evita con varias salvaguardas:
- Quórum en el DCS: solo el nodo que adquiere la clave
leaderen etcd se promueve. Si la red se parte y un nodo queda aislado del DCS, no puede ser leader. - Watchdog (opcional): el kernel reinicia el nodo si Patroni no responde, evitando que un nodo zombie siga escribiendo.
- Sincronía de réplicas configurable: con
synchronous_commit = onysynchronous_standby_names, el primario solo confirma escrituras cuando una réplica las ha persistido.
postgresql:
parameters:
synchronous_commit: "on"
synchronous_standby_names: "ANY 1 (pg-2,pg-3)"
Con esa configuración, las escrituras solo se confirman cuando al menos una de las dos réplicas ha persistido el WAL. En caso de failover, esa réplica está garantizada de tener todos los datos confirmados.
Integración con HAProxy
Patroni expone una REST API en cada nodo (/health, /leader, /replica) que HAProxy usa para enrutar:
backend postgres-write
mode tcp
option httpchk GET /leader
http-check expect status 200
server pg-1 10.0.0.1:5432 check port 8008
server pg-2 10.0.0.2:5432 check port 8008
server pg-3 10.0.0.3:5432 check port 8008
backend postgres-read
mode tcp
balance roundrobin
option httpchk GET /replica
http-check expect status 200
server pg-1 10.0.0.1:5432 check port 8008
server pg-2 10.0.0.2:5432 check port 8008
server pg-3 10.0.0.3:5432 check port 8008
El backend postgres-write solo dirige tráfico al nodo que responde 200 a /leader (el primario actual). El backend postgres-read distribuye lecturas entre las réplicas. La aplicación apunta a la IP de HAProxy, no a IPs específicas de PostgreSQL.
Alternativas: repmgr y pgpool-II
Patroni no es la única opción de HA:
- repmgr (de 2ndQuadrant): herramienta más ligera, sin DCS externo. Apropiada para clusters pequeños o entornos donde añadir etcd resulta excesivo. El failover automático requiere
repmgrdcorriendo y tiene menos garantías frente a particiones de red. - pgpool-II: añade pooling de conexiones, balanceo y failover en un solo proceso, pero su modelo es más complejo y la documentación es densa. Apropiado cuando ya se usa pgpool por otras razones.
- PostgreSQL Operator (Kubernetes): para deployments en Kubernetes, operadores como
crunchy-postgres-operatorocloudnative-pgorquestan PostgreSQL con la API de Kubernetes como DCS implícito.
| Aspecto | Patroni | repmgr | pgpool-II | |---------|---------|--------|-----------| | DCS requerido | Sí | No | No | | Failover automático | Sí | Sí (repmgrd) | Sí | | Pooling | No | No | Sí | | Balanceo | No | No | Sí | | Madurez | Alta | Alta | Alta | | Recomendado para | Producción seria | Setups pequeños | Setups que necesitan pooling integrado |
Buenas prácticas operativas
- Cluster DCS de 3 o 5 nodos en zonas de disponibilidad distintas.
- Monitorización de etcd: cualquier degradación del DCS afecta la HA de PostgreSQL.
- Backups independientes del cluster: HA no sustituye backups (no protege contra borrado lógico).
- Probar failover periódicamente en preproducción.
- Documentar el runbook de recuperación: si se cae el DCS entero, ¿cómo se recupera?
- Versionar la configuración Patroni en Git con rotación automática de secretos.
El error más común en HA es asumir que funciona sin probarlo. Un calendario trimestral de pruebas de failover es la única forma de garantizar que el cluster responde como se espera el día que de verdad falla algo.
Patroni convierte la HA de PostgreSQL en una operación rutinaria. La inversión inicial en la configuración del cluster y el DCS se recupera la primera vez que un servidor cae a las 3 de la madrugada y el sistema sigue atendiendo peticiones sin que nadie tenga que despertarse.
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, SQL es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de SQL
Explora más contenido relacionado con SQL y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Comprender la arquitectura Patroni con DCS (etcd, Consul, ZooKeeper). Configurar un cluster de tres nodos con leader election y failover automático. Evitar split-brain mediante el quorum del DCS. Integrar HAProxy o pgBouncer para enrutar tráfico al leader. Diferenciar Patroni frente a alternativas como repmgr o pgpool-II.
Cursos que incluyen esta lección
Esta lección forma parte de los siguientes cursos estructurados con rutas de aprendizaje