Una base de datos sin réplica es un punto único de falla. Si el disco muere, si el servidor se cae, si una actualización sale mal — tu ERP, tu CRM, tu e-commerce se detienen. Con replicación, una segunda copia de tu base de datos se mantiene sincronizada en otro servidor, lista para tomar el control en minutos.
En esta guía vas a configurar replicación streaming en PostgreSQL con un servidor primario y una réplica de solo lectura — el esquema de alta disponibilidad más común y práctico para la mayoría de las empresas.
Arquitectura
┌─────────────────┐ ┌─────────────────┐
│ PRIMARIO │ WAL │ RÉPLICA │
│ 10.0.1.10 │────────▶│ 10.0.1.11 │
│ │ stream │ │
│ Lecturas ✅ │ │ Lecturas ✅ │
│ Escrituras ✅ │ │ Escrituras ❌ │
│ │ │ (solo lectura) │
└─────────────────┘ └─────────────────┘
▲ ▲
│ │
App (ERP, CRM) Reportes, BI
Escrituras Consultas pesadas
El primario acepta todas las escrituras y envía los cambios (WAL — Write Ahead Log) a la réplica en tiempo real. La réplica aplica los cambios y está disponible para consultas de solo lectura. Si el primario falla, la réplica puede promoverse a primario.
Requisitos previos
Dos servidores Ubuntu 24.04 con PostgreSQL 16 instalado en ambos:
- Primario: 10.0.1.10
- Réplica: 10.0.1.11
Ambos servidores deben poder comunicarse por el puerto 5432. Configura tu firewall UFW:
# En el primario: permitir conexión desde la réplica
sudo ufw allow from 10.0.1.11 to any port 5432 comment 'PostgreSQL replicación'
# En la réplica: permitir conexión desde el primario (para pg_basebackup)
sudo ufw allow from 10.0.1.10 to any port 5432 comment 'PostgreSQL primario'
Paso 1: Configurar el servidor primario
Crear usuario de replicación
En el primario, crea un usuario dedicado para la replicación:
sudo -u postgres psql
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'contraseña_replica_segura';
Configurar pg_hba.conf
Permite la conexión de replicación desde la réplica:
sudo tee -a /etc/postgresql/16/main/pg_hba.conf > /dev/null <<EOF
# Replicación
host replication replicator 10.0.1.11/32 scram-sha-256
EOF
Configurar postgresql.conf
Edita la configuración del primario para habilitar la replicación:
sudo nano /etc/postgresql/16/main/postgresql.conf
Modifica o agrega estas líneas:
# Escuchar en todas las interfaces
listen_addresses = '*'
# WAL (Write Ahead Log)
wal_level = replica
max_wal_senders = 5
wal_keep_size = 1GB
# Archivado de WAL (recomendado para point-in-time recovery)
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/16/wal_archive/%f'
Crea el directorio de archivo WAL:
sudo mkdir -p /var/lib/postgresql/16/wal_archive
sudo chown postgres:postgres /var/lib/postgresql/16/wal_archive
Reinicia PostgreSQL:
sudo systemctl restart postgresql
Paso 2: Preparar la réplica
Detener PostgreSQL en la réplica
sudo systemctl stop postgresql
Limpiar el directorio de datos
La réplica necesita empezar con una copia exacta del primario. Borra los datos actuales:
sudo rm -rf /var/lib/postgresql/16/main/*
Cuidado
Este comando borra todos los datos de PostgreSQL en la réplica. Si la réplica tiene datos que necesitas conservar, haz un backup antes. En una instalación nueva, el directorio solo contiene la configuración por defecto.
Copiar los datos del primario con pg_basebackup
sudo -u postgres pg_basebackup \
-h 10.0.1.10 \
-U replicator \
-D /var/lib/postgresql/16/main \
-Fp -Xs -P -R
Desglose de los parámetros:
| Parámetro | Función |
|---|---|
-h 10.0.1.10 | IP del servidor primario |
-U replicator | Usuario de replicación |
-D ... | Directorio destino (datos de la réplica) |
-Fp | Formato plain (archivos tal cual) |
-Xs | Incluir WAL por streaming |
-P | Mostrar progreso |
-R | Crear automáticamente el archivo standby.signal y configurar la conexión |
El proceso tomará desde segundos hasta minutos dependiendo del tamaño de tu base de datos. Verás el progreso en porcentaje.
Paso 3: Verificar la configuración de la réplica
El flag -R de pg_basebackup creó automáticamente dos cosas:
standby.signal— archivo vacío que le dice a PostgreSQL que arranque como réplica- Conexión primaria en
postgresql.auto.conf— la cadena de conexión al primario
Verifica:
# Debe existir el archivo standby.signal
ls -la /var/lib/postgresql/16/main/standby.signal
# Debe tener la conexión al primario
cat /var/lib/postgresql/16/main/postgresql.auto.conf
Deberías ver algo como:
primary_conninfo = 'user=replicator password=contraseña_replica_segura host=10.0.1.10 port=5432'
Configurar la réplica como hot standby
Edita postgresql.conf de la réplica para permitir consultas de lectura:
sudo nano /etc/postgresql/16/main/postgresql.conf
hot_standby = on
Paso 4: Arrancar la réplica
sudo systemctl start postgresql
Verifica en los logs que la replicación está funcionando:
sudo tail -20 /var/log/postgresql/postgresql-16-main.log
Deberías ver mensajes como:
LOG: entering standby mode
LOG: redo starts at 0/3000028
LOG: started streaming WAL from primary at 0/4000000 on timeline 1
LOG: consistent recovery state reached at 0/4000110
Paso 5: Verificar la replicación
Desde el primario
sudo -u postgres psql -c "SELECT client_addr, state, sent_lsn, write_lsn, flush_lsn, replay_lsn FROM pg_stat_replication;"
Deberías ver la IP de la réplica con estado streaming:
client_addr | state | sent_lsn | write_lsn | flush_lsn | replay_lsn
-------------+-----------+------------+------------+------------+------------
10.0.1.11 | streaming | 0/4000110 | 0/4000110 | 0/4000110 | 0/4000110
Si todos los LSN coinciden, la réplica está sincronizada — cero retraso.
Desde la réplica
sudo -u postgres psql -c "SELECT pg_is_in_recovery();"
Debe devolver t (true) — confirmando que es una réplica.
Prueba funcional
Crea datos en el primario y verifica que aparecen en la réplica:
# En el primario
sudo -u postgres psql -c "CREATE TABLE test_replica (id serial, msg text, created_at timestamptz DEFAULT now());"
sudo -u postgres psql -c "INSERT INTO test_replica (msg) VALUES ('Hola desde el primario');"
# En la réplica (debería aparecer en menos de 1 segundo)
sudo -u postgres psql -c "SELECT * FROM test_replica;"
# Verificar que la réplica no acepta escrituras
sudo -u postgres psql -h 10.0.1.11 -c "INSERT INTO test_replica (msg) VALUES ('Intento escribir');"
# ERROR: cannot execute INSERT in a read-only transaction
Paso 6: Monitorear el retraso de replicación
El retraso de replicación (replication lag) es la métrica más importante. Si crece, significa que la réplica se está quedando atrás.
Desde el primario
SELECT
client_addr,
state,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS lag_bytes,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)) AS lag_pretty
FROM pg_stat_replication;
Desde la réplica
SELECT
now() - pg_last_xact_replay_timestamp() AS lag_time,
pg_is_in_recovery() AS is_replica;
Para monitoreo continuo, configura Prometheus con postgres_exporter y crea una alerta cuando el lag supere un umbral (por ejemplo, 30 segundos para replicación asíncrona).
Paso 7: Promover la réplica a primario (failover manual)
Si el primario falla y necesitas que la réplica tome el control:
# En la réplica
sudo -u postgres pg_ctlcluster 16 main promote
O con pg_ctl:
sudo -u postgres pg_ctl promote -D /var/lib/postgresql/16/main
Después de la promoción:
- La réplica elimina el archivo
standby.signal - Acepta escrituras
- Se convierte en el nuevo primario
El failover manual tiene riesgo
Promover la réplica manualmente es un proceso de emergencia. Si el primario original sigue vivo, puedes terminar con dos servidores que aceptan escrituras (split-brain). Para failover automático y seguro, usa Patroni — el estándar de la industria para alta disponibilidad de PostgreSQL.
Replicación síncrona (opcional)
Si no puedes perder ni una sola transacción (finanzas, facturación), puedes cambiar a replicación síncrona. En el primario:
# postgresql.conf del primario
synchronous_commit = on
synchronous_standby_names = 'replica1'
En la réplica, configura su application_name en el primary_conninfo:
primary_conninfo = '... application_name=replica1'
Con replicación síncrona, el primario no confirma una escritura al cliente hasta que la réplica la haya recibido. Esto garantiza cero pérdida de datos pero agrega latencia a cada escritura — úsala solo cuando la integridad de datos es más importante que la velocidad.
Siguientes pasos
Con la replicación funcionando, el siguiente nivel es:
- Patroni — failover automático con consenso distribuido (etcd/ZooKeeper) para que la réplica se promueva sola si el primario falla
- PgBouncer — connection pooling para manejar cientos de conexiones sin saturar PostgreSQL
- pgBackRest — backups incrementales con verificación de integridad y point-in-time recovery
- Múltiples réplicas — una local para HA, otra remota para DR, otra para BI
- Bases de datos administradas — nuestro servicio DBA as a Service con monitoreo, mantenimiento y soporte 24/7
Alta disponibilidad
¿Necesitas que tu base de datos nunca se detenga?
Implementamos replicación con failover automático, monitoreo de lag y pruebas de failover periódicas para tu PostgreSQL de producción.



