Replicación de Bases de Datos
Configura y gestiona replicación de bases de datos para alta disponibilidad, escalado de lecturas y disaster recovery con arquitecturas primaria-réplica.
Visión General
La replicación de bases de datos copia datos de una base de datos primaria a una o más réplicas. Esto habilita el escalado de lecturas, alta disponibilidad y disaster recovery. Ya sea usando streaming replication en PostgreSQL, binary log replication en MySQL, o replica sets nativos en MongoDB, entender el lag de replicación, failover y trade-offs de consistencia es esencial para construir capas de datos resilientes.
Cuándo Usar
Usa este recurso cuando:
- El tráfico de lecturas excede lo que una única instancia de base de datos puede manejar
- Necesitas failover con near-zero downtime para aplicaciones críticas
- La distribución geográfica requiere datos más cerca de los usuarios
- Los backups no deben impactar la performance de la base de datos primaria
Solución
PostgreSQL Streaming Replication
-- En primaria: configurar postgresql.conf
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
-- En primaria: crear usuario de replicación
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'secret';
-- En réplica: usar pg_basebackup
pg_basebackup -h primary-db.example.com -D /var/lib/postgresql/data \
-U replicator -P -v -R -X stream -C -S replica_1
MySQL Group Replication (Single-Primary)
-- En cada nodo
SET GLOBAL group_replication_bootstrap_group=OFF;
START GROUP_REPLICATION;
-- Verificar estado de miembros
SELECT * FROM performance_schema.replication_group_members;
-- Verificar lag de replicación
SELECT
MEMBER_ID,
COUNT_TRANSACTIONS_IN_QUEUE as trx_behind,
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE as applying
FROM performance_schema.replication_group_member_stats;
Read Replica Routing (Node.js)
const { Pool } = require('pg');
const primaryPool = new Pool({
host: process.env.DB_PRIMARY_HOST,
database: 'app'
});
const replicaPool = new Pool({
host: process.env.DB_REPLICA_HOST,
database: 'app',
poolMode: 'read-only'
});
async function query(sql, params, options = {}) {
const pool = options.readOnly ? replicaPool : primaryPool;
const client = await pool.connect();
try {
return await client.query(sql, params);
} finally {
client.release();
}
}
// Lecturas van a réplica
const users = await query('SELECT * FROM users', [], { readOnly: true });
// Escrituras van a primaria
await query('UPDATE users SET last_login = NOW() WHERE id = $1', [userId]);
Explicación
Modos de replicación:
| Modo | Consistencia | Caso de Uso |
|---|---|---|
| Asíncrono | Eventual | Escalado de lecturas; lag aceptable |
| Síncrono | Fuerte | Datos financieros; zero data loss |
| Semi-síncrono | Balanceado | La mayoría de escenarios HA |
Causas de lag de replicación:
- Transacciones grandes bloquean el stream de replicación
- El hardware de réplica es más lento que la primaria
- Latencia de red entre primaria y réplica
- Réplica bajo carga de lectura pesada compitiendo con el proceso de apply
Estrategias de failover:
- Promoción manual: DBA ejecuta
pg_promote()oCHANGE MASTER TO - Patroni/etcd: Failover automatizado con elección de líder
- AWS RDS: Automático con detección de ~60-120 segundos
- Capa de proxy: PgBouncer o ProxySQL rutean a la nueva primaria
Variantes
| Base de Datos | Método | Feature |
|---|---|---|
| PostgreSQL | Streaming WAL | Hot standby; réplicas en cascada |
| MySQL | Binlog | Row-based o statement-based |
| MongoDB | Oplog | Replica sets; failover automático |
| Redis | Replication | Async; Sentinel para HA |
| CockroachDB | Multi-raft | Síncrono por default |
Lo que funciona
- Monitorea lag de replicación: Alerta cuando el lag excede la tolerancia de la aplicación (usualmente 1-5 segundos)
- Usa connection pooling: PgBouncer o ProxySQL manejan el ruteo primaria/réplica
- Testea failover trimestralmente: El failover automatizado aún necesita validación humana
- Mantén réplicas en AZs diferentes: No solo diferentes instancias — diferentes dominios de falla
- No escribas en réplicas: Incluso si está soportado, crea conflictos y escenarios de split-brain
Errores Comunes
- Asumir que las réplicas son real-time: El lag asíncrono puede ser segundos o minutos; diseña para consistencia eventual. Aprende más en CAP theorem.
- Sin testing de failover: La primera vez que haces failover no debería ser durante un outage
- Ignorar bloat de replication slots: Los slots de replicación de PostgreSQL previenen cleanup de WAL; monitorea uso de disco
- Único path de red: Réplicas en la misma AZ que la primaria comparten el mismo dominio de falla
- Leyendo de réplicas con lag: Mostrar datos stale a usuarios que acaban de escribir causa confusión
Buenas prácticas adicionales
-
Usa replication slots en PostgreSQL. Los replication slots previenen que el WAL se recicle antes de que la réplica lo consuma. Monitorea el uso de disco de los slots para prevenir bloat.
-
Configura
max_replication_slotsymax_wal_sendersapropiadamente. Cada réplica necesita un slot y un WAL sender. Configura 2-3 más que tu conteo de réplicas para expansión futura. -
Usa
synchronous_commit = remote_applypara datos críticos. Esto espera hasta que la réplica aplica la transacción antes de confirmar el commit:
ALTER SYSTEM SET synchronous_commit = remote_apply;
-
Mantén réplicas en diferentes availability zones. Una falla de una sola AZ no debería tumbar tanto la primaria como la réplica.
-
Automatiza el testing de failover. Ejecuta drills de failover mensualmente. Documenta el runbook. Las herramientas de failover automatizado (Patroni, Stolon) aún necesitan validación humana.
Tips de Rendimiento
- Ajusta
wal_sender_timeoutywal_receiver_timeout. Configura 30-60 segundos para detectar fallos de red rápidamente:
ALTER SYSTEM SET wal_sender_timeout = '30s';
ALTER SYSTEM SET wal_receiver_timeout = '30s';
- Usa
wal_compression = onpara replicación WAN. Comprime el WAL antes de enviarlo, reduciendo ancho de banda para réplicas cross-region:
ALTER SYSTEM SET wal_compression = on;
- Batchea escrituras grandes para reducir volumen de WAL. Transacciones grandes individuales generan menos WAL que muchas pequeñas:
-- Mejor: una transacción grande
BEGIN;
INSERT INTO logs SELECT * FROM staging_logs;
COMMIT;
-- Peor: muchas transacciones pequeñas
- Monitorea
pg_stat_wal_receiverpara salud de conexión. Esta vista muestra el estado del proceso WAL receiver en una réplica:
SELECT status, sender_host, sender_port, received_lsn, latest_end_lsn
FROM pg_stat_wal_receiver;
- Usa
hot_standby_feedback = onpara prevenir conflictos de queries. Esto envía feedback de queries de la réplica a la primaria, previniendo que vacuum elimine filas aún necesitadas por queries de la réplica:
ALTER SYSTEM SET hot_standby_feedback = on; Preguntas frecuentes
¿Cuánto lag de replicación es aceptable?
Para analytics: minutos. Para lecturas user-facing: <1 segundo. Para datos financieros: usa replicación síncrona.
¿Puedo usar réplicas para backups?
Sí. pg_basebackup desde una réplica descarga la primaria. Asegúrate de que la réplica esté al día primero. Consulta nuestra plantilla de disaster recovery.
¿Cuál es la diferencia entre replicación lógica y física?
La física copia byte-por-byte (rápida; base de datos completa). La lógica replica cambios de fila (tablas selectivas; compatible entre versiones).
Recursos Relacionados
Generacion de UUID: v4, v7 y Comparacion con ULID
Compara UUID v4, v7, ULID y nanoid para generar identificadores unicos con diferentes tradeoffs en aleatoriedad, ordenamiento, rendimiento y localidad de indices de base de datos
RecipePool de Conexiones a Base de Datos
Configura y ajusta pools de conexiones para maximizar throughput y prevenir el agotamiento de conexiones.
RecipeOptimizacion de Queries e Indexing en PostgreSQL
Analiza y optimiza queries lentas en PostgreSQL usando EXPLAIN, indexing apropiado, partial indexes y reescritura de queries para reducir tiempo de ejecucion
GuideOptimización de Rendimiento SQL
Una guía práctica para optimizar consultas SQL: estrategias de indexación, reescritura de queries, análisis de EXPLAIN plans y anti-patrones comunes a evitar.
RecipePaginación por Cursor en PostgreSQL (Keyset vs OFFSET)
Implementa paginación eficiente por cursor para datasets grandes en PostgreSQL, evitando la degradación de rendimiento de OFFSET con paginación keyset indexada y ordenamiento estable
RecipeClasificar filas y calcular totales acumulados con
Usa funciones de ventana SQL para clasificar filas, calcular totales acumulados y comparar valores dentro de particiones sin self-joins.