La replicación streaming de PostgreSQL proporciona un mecanismo robusto para mantener copias en tiempo real de tu base de datos en múltiples servidores. Ya sea que necesites alta disponibilidad, recuperación ante desastres o escalado de lecturas, la replicación streaming ofrece consistencia a nivel de bytes con un lag mínimo. Esta guía te lleva paso a paso a través de la configuración de una arquitectura primario-standby desde cero, la configuración del archivado WAL, el monitoreo de la salud de la replicación y la planificación de estrategias de failover.

Requisitos Previos

  • Dos servidores Linux (Ubuntu 22.04+ o RHEL 9+) con conectividad de red
  • PostgreSQL 16 o posterior instalado en ambos servidores
  • Suficiente espacio en disco para archivos WAL y backups base
  • Acceso root o sudo en ambas máquinas
  • Puerto 5432 abierto entre los servidores primario y standby
  • Familiaridad básica con los archivos de configuración de PostgreSQL

Entendiendo la Replicación en PostgreSQL

PostgreSQL soporta dos modos principales de replicación: replicación streaming y replicación lógica. La replicación streaming opera a nivel de bytes WAL (Write-Ahead Log), enviando un flujo continuo de registros WAL del primario a los standbys. Esto crea una copia binaria exacta del clúster completo.

El proceso de replicación sigue este flujo:

  1. El primario escribe los cambios en segmentos WAL
  2. El proceso WAL sender transmite los registros a los standbys conectados
  3. El WAL receiver del standby escribe los registros en el WAL local
  4. El proceso startup del standby reproduce los registros WAL para actualizar los archivos de datos

La replicación streaming puede operar en modo asíncrono (predeterminado) o síncrono. El modo asíncrono ofrece mejor rendimiento con lag mínimo, mientras que el síncrono garantiza cero pérdida de datos a costa de latencia en escritura.

Configuración del Servidor Primario

Edita el archivo postgresql.conf del servidor primario para habilitar la replicación:

# /etc/postgresql/16/main/postgresql.conf

listen_addresses = '*'
wal_level = replica
max_wal_senders = 5
wal_keep_size = '1GB'
hot_standby = on

El parámetro wal_level = replica asegura que el WAL contenga suficiente información para la replicación. max_wal_senders controla cuántas conexiones de streaming concurrentes se permiten. wal_keep_size previene que el primario recicle segmentos WAL antes de que el standby los haya consumido.

A continuación, configura pg_hba.conf para permitir que el standby se conecte para replicación:

# /etc/postgresql/16/main/pg_hba.conf

# TYPE  DATABASE        USER            ADDRESS              METHOD
host    replication     replicator      10.0.1.20/32         scram-sha-256

Reemplaza 10.0.1.20 con la dirección IP de tu servidor standby.

Crea un usuario dedicado para replicación:

CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'your_secure_password';

Reinicia PostgreSQL para aplicar los cambios de configuración:

sudo systemctl restart postgresql

Configuración del Servidor Standby

En el servidor standby, detén PostgreSQL y limpia el directorio de datos existente:

sudo systemctl stop postgresql
sudo rm -rf /var/lib/postgresql/16/main/*

Ejecuta pg_basebackup para clonar los datos del primario:

sudo -u postgres pg_basebackup \
  -h 10.0.1.10 \
  -U replicator \
  -D /var/lib/postgresql/16/main \
  -Fp -Xs -P -R

Las banderas tienen propósitos específicos:

  • -Fp: Formato de salida plano
  • -Xs: Transmite WAL durante el backup para evitar brechas
  • -P: Muestra el progreso
  • -R: Crea automáticamente standby.signal y escribe primary_conninfo en postgresql.auto.conf

Si prefieres configuración manual, crea la señal de standby y los parámetros de conexión tú mismo:

touch /var/lib/postgresql/16/main/standby.signal

Agrega a postgresql.conf en el standby:

primary_conninfo = 'host=10.0.1.10 port=5432 user=replicator password=your_secure_password application_name=standby1'
hot_standby = on

Inicia el servidor standby:

sudo systemctl start postgresql

Archivado WAL

El archivado WAL proporciona una red de seguridad adicional al copiar segmentos WAL completados a una ubicación de archivo. Esto permite la recuperación a un punto en el tiempo (PITR) y protege contra escenarios donde el standby se queda muy atrás.

Configura el archivado en el primario:

# /etc/postgresql/16/main/postgresql.conf

archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/wal_archive/%f'

Crea el directorio de archivo:

sudo mkdir -p /var/lib/postgresql/wal_archive
sudo chown postgres:postgres /var/lib/postgresql/wal_archive

Para entornos de producción, usa rsync o una solución de almacenamiento en la nube en lugar de cp local:

archive_command = 'rsync -a %p backup-server:/wal_archive/%f'

Configura el standby para usar WAL archivado como respaldo con restore_command:

# En el postgresql.conf del standby
restore_command = 'cp /mnt/wal_archive/%f %p'

Esto permite que el standby recupere segmentos WAL del archivo cuando el streaming se queda atrás.

Monitoreo del Lag de Replicación

Monitorear el lag de replicación es crítico para asegurar que tu standby se mantenga actualizado. En el servidor primario, consulta pg_stat_replication:

SELECT
  client_addr,
  application_name,
  state,
  sent_lsn,
  write_lsn,
  flush_lsn,
  replay_lsn,
  pg_wal_lsn_diff(sent_lsn, replay_lsn) AS replay_lag_bytes,
  write_lag,
  flush_lag,
  replay_lag
FROM pg_stat_replication;

En el servidor standby, verifica el estado del receptor y calcula el lag:

SELECT
  status,
  received_lsn,
  latest_end_lsn,
  last_msg_send_time,
  last_msg_receipt_time
FROM pg_stat_wal_receiver;

-- Estimación del lag basada en tiempo
SELECT
  now() - pg_last_xact_replay_timestamp() AS replication_delay;

Configura una alerta cuando el lag exceda tu umbral:

#!/bin/bash
LAG_BYTES=$(psql -h primary -U monitor -t -c \
  "SELECT pg_wal_lsn_diff(sent_lsn, replay_lsn) FROM pg_stat_replication WHERE application_name='standby1';")

if [ "$LAG_BYTES" -gt 104857600 ]; then
  echo "ALERTA: El lag de replicación excede 100MB ($LAG_BYTES bytes)" | mail -s "PG Replication Alert" admin@example.com
fi

Estrategias de Failover

Cuando el primario falla, necesitas un plan claro de failover. PostgreSQL proporciona varios métodos de promoción:

Promoción manual:

# Usando pg_ctl
sudo -u postgres pg_ctl promote -D /var/lib/postgresql/16/main

# Usando SQL (PostgreSQL 12+)
SELECT pg_promote(wait := true, wait_seconds := 60);

Promoción por archivo trigger:

Configura promote_trigger_file en el postgresql.conf del standby:

promote_trigger_file = '/tmp/postgresql.trigger'

Crea el archivo para activar la promoción:

touch /tmp/postgresql.trigger

Failover automatizado con Patroni:

Para entornos de producción, usa una herramienta como Patroni con etcd:

# /etc/patroni/patroni.yml (extracto)
scope: pg-cluster
namespace: /db/
name: node1

restapi:
  listen: 0.0.0.0:8008

etcd:
  hosts: 10.0.1.100:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    maximum_lag_on_failover: 1048576

postgresql:
  listen: 0.0.0.0:5432
  data_dir: /var/lib/postgresql/16/main
  authentication:
    replication:
      username: replicator
      password: your_secure_password

Después del failover, el antiguo primario debe reintroducirse como standby usando pg_rewind:

sudo -u postgres pg_rewind \
  --target-pgdata=/var/lib/postgresql/16/main \
  --source-server="host=10.0.1.20 port=5432 user=postgres"

Comparativa: Streaming vs Replicación Lógica

CaracterísticaReplicación StreamingReplicación Lógica
Nivel de replicaciónNivel de bytes (WAL)Nivel de fila (cambios decodificados)
Alcance del clústerClúster completoPor tabla o por base de datos
Soporte entre versionesRequiere misma versión mayorSoporta versiones mayores diferentes
Escritura en standbySolo lectura (hot standby)Lectura-escritura en el suscriptor
Replicación de DDLAutomáticaManual (no se replica)
Sobrecarga de rendimientoMuy bajaModerada (costo de decodificación)
Complejidad de configuraciónSimpleModerada
Caso de usoHA y recuperación ante desastresReplicación selectiva y migraciones

Elige replicación streaming para alta disponibilidad del clúster completo. Elige replicación lógica cuando necesites replicación selectiva de tablas, actualizaciones entre versiones o suscriptores con escritura.

Escenario del Mundo Real

Administras una base de datos de producción de comercio electrónico que maneja 5,000 transacciones por segundo. El negocio requiere menos de 30 segundos de inactividad durante cualquier fallo. Así es como diseñas la solución:

El servidor primario (10.0.1.10) maneja todas las escrituras. El standby síncrono (10.0.1.20) en el mismo centro de datos asegura cero pérdida de datos. El standby asíncrono (10.0.2.10) en un centro de datos remoto proporciona recuperación ante desastres.

Configura la replicación síncrona en el primario:

synchronous_standby_names = 'FIRST 1 (standby_dc1, standby_dc2)'
synchronous_commit = on

Dirige las consultas de lectura a los standbys usando PgBouncer o HAProxy:

# /etc/haproxy/haproxy.cfg (extracto)
listen pg-read
    bind *:5433
    mode tcp
    balance roundrobin
    option pgsql-check user haproxy
    server standby1 10.0.1.20:5432 check
    server standby2 10.0.2.10:5432 check

Esta arquitectura proporciona cero pérdida de datos para fallos locales y pérdida mínima para eventos a nivel de centro de datos, mientras descarga el tráfico de lectura a los standbys.

Errores Comunes y Casos Especiales

  • Eliminación de segmentos WAL: Si el standby se desconecta más tiempo del que permite wal_keep_size, no puede ponerse al día vía streaming. Siempre configura archivado WAL como red de seguridad o usa slots de replicación: SELECT pg_create_physical_replication_slot('standby1_slot');
  • Slots de replicación y uso de disco: Los slots de replicación no utilizados previenen la limpieza de WAL, potencialmente llenando el disco. Monitorea pg_replication_slots y elimina los slots inactivos
  • Transacciones grandes: Una sola transacción masiva (importación masiva) genera enormes volúmenes de WAL que pueden sobrecargar el standby o la red. Divide las operaciones grandes en lotes
  • Latencia de commit síncrono: Habilitar synchronous_commit = on con standbys síncronos agrega el tiempo de ida y vuelta de la red a cada commit. Prueba el throughput de escritura antes de habilitarlo
  • Divergencia de timeline: Después de promover un standby, el antiguo primario está en un timeline diferente. Debes usar pg_rewind o reconstruirlo completamente antes de reintroducirlo como standby
  • Contraseña en primary_conninfo: Almacena las credenciales en .pgpass en lugar de texto plano en los archivos de configuración

Solución de Problemas

El standby no se conecta:

# Verificar logs del standby
sudo tail -f /var/log/postgresql/postgresql-16-main.log

# Verificar conexiones de replicación en el primario
sudo -u postgres psql -c "SELECT * FROM pg_stat_replication;"

# Probar conectividad desde el standby
psql -h 10.0.1.10 -U replicator -d postgres -c "IDENTIFY_SYSTEM;"

El lag de replicación crece:

-- Verificar si el standby está reproduciendo
SELECT pg_is_in_recovery(), pg_last_wal_replay_lsn();

-- Verificar consultas de larga duración bloqueando la reproducción
SELECT pid, query, state, wait_event FROM pg_stat_activity
WHERE state != 'idle' AND backend_type = 'client backend';

El archivo WAL se llena:

# Verificar estado del archivado
sudo -u postgres psql -c "SELECT * FROM pg_stat_archiver;"

# Limpiar archivos antiguos manualmente (mantener al menos 1 día)
find /var/lib/postgresql/wal_archive -mtime +1 -delete

Resumen

  • La replicación streaming de PostgreSQL crea copias binarias en tiempo real de todo tu clúster de base de datos
  • Configura wal_level = replica, max_wal_senders y un usuario de replicación en el primario
  • Usa pg_basebackup con la bandera -R para inicializar standbys con configuración automática
  • El archivado WAL proporciona una red de seguridad para standbys que se quedan atrás del streaming
  • Monitorea el lag de replicación vía pg_stat_replication y pg_stat_wal_receiver
  • Usa Patroni o herramientas similares para failover automatizado en producción
  • Los slots de replicación previenen la eliminación de WAL pero requieren monitoreo para evitar el agotamiento del disco
  • Siempre prueba tu procedimiento de failover antes de necesitarlo en una emergencia

Artículos Relacionados