¿Qué Es la Replicación de Base de Datos?
La replicación de base de datos es el proceso de copiar y mantener objetos de base de datos a través de múltiples servidores. La replicación proporciona redundancia, mejora el rendimiento de lectura y asegura alta disponibilidad.
¿Por Qué Replicar?
- Alta Disponibilidad: Si un nodo falla, otros pueden continuar sirviendo solicitudes.
- Escalabilidad de Lectura: Distribuir consultas de lectura entre múltiples réplicas.
- Distribución Geográfica: Colocar datos más cerca de los usuarios en diferentes regiones.
- Recuperación ante Desastres: Mantener copias en diferentes centros de datos.
- Aislamiento de Analíticas: Ejecutar consultas analíticas pesadas en réplicas sin impactar producción.
Replicación Maestro-Esclavo (Primary-Replica)
La topología de replicación más común. Un nodo se designa como maestro (primario) y maneja todas las operaciones de escritura. Uno o más nodos esclavos (réplicas) reciben copias de los datos y sirven consultas de lectura.
Cómo Funciona
- Todas las escrituras van al nodo maestro
- El maestro escribe cambios en un log de replicación (binlog en MySQL, WAL en PostgreSQL)
- Las réplicas consumen el log y aplican cambios a sus copias locales
- Las consultas de lectura pueden ser servidas por cualquier réplica o el maestro
// Master-Slave routing logic
interface DatabasePool {
master: DatabaseConnection;
replicas: DatabaseConnection[];
}
class ReplicaRouter {
private pool: DatabasePool;
private currentReplica = 0;
constructor(pool: DatabasePool) {
this.pool = pool;
}
// All writes go to master
async write(query: string, params: any[]): Promise<any> {
return this.pool.master.execute(query, params);
}
// Reads are distributed across replicas (round-robin)
async read(query: string, params: any[]): Promise<any> {
const replica = this.pool.replicas[this.currentReplica];
this.currentReplica = (this.currentReplica + 1) % this.pool.replicas.length;
return replica.execute(query, params);
}
// For reads that must see latest writes (read-after-write consistency)
async readFromMaster(query: string, params: any[]): Promise<any> {
return this.pool.master.execute(query, params);
}
}
Limitaciones de Maestro-Esclavo
- Cuello de Botella de Escritura Única: Todas las escrituras deben pasar por un nodo, limitando el rendimiento de escritura
- Retraso de Replicación: Las réplicas pueden servir datos obsoletos durante cargas de escritura altas
- Complejidad de Failover: Promover una réplica a maestro requiere coordinación y puede causar breve tiempo de inactividad
Replicación Multi-Maestro
En la replicación multi-maestro, dos o más nodos aceptan operaciones de escritura. Cada maestro replica sus cambios a los otros maestros. Esto elimina el cuello de botella de escritura única pero introduce el desafío de conflictos de escritura.
Cuándo Usar Multi-Maestro
- Despliegues multi-región: Cada región tiene un maestro local para minimizar la latencia de escritura
- Alto rendimiento de escritura: Cuando un solo maestro no puede manejar el volumen de escritura
- Configuraciones activo-activo: Ambos centros de datos sirven tráfico activamente de forma simultánea
Comparación de Topologías de Replicación
| Aspecto | Maestro-Esclavo | Multi-Maestro |
|---|---|---|
| Nodos de Escritura | Único | Múltiples |
| Escalabilidad de Escritura | Limitada por un nodo | Escala horizontalmente |
| Manejo de Conflictos | Sin conflictos (escritor único) | Debe manejar conflictos |
| Consistencia | Más fácil de mantener | Eventualmente consistente por defecto |
| Failover | Requiere promoción | Automático (otros maestros disponibles) |
| Complejidad | Más simple | Significativamente más compleja |
Replicación Síncrona vs Asíncrona
El momento de cuándo se replican los datos a nodos secundarios es una decisión de diseño crítica que afecta tanto la consistencia como el rendimiento.
Replicación Síncrona
El maestro espera a que al menos una réplica confirme que ha escrito los datos antes de confirmar la escritura al cliente. Esto garantiza que los datos existen en múltiples nodos pero agrega latencia a cada operación de escritura.
Replicación Asíncrona
El maestro confirma la escritura inmediatamente después de escribir localmente y replica a los seguidores en segundo plano. Esto proporciona menor latencia de escritura pero arriesga pérdida de datos si el maestro falla antes de que se complete la replicación.
Replicación Semi-Síncrona
Un punto medio práctico: el maestro espera a que al menos una réplica confirme, pero no todas las réplicas. MySQL soporta esto nativamente con rpl_semi_sync_master_wait_for_slave_count.
// Illustrating sync vs async replication behavior
// Synchronous: write is only confirmed after replica acknowledges
async function syncWrite(master: DB, replicas: DB[], data: Record<string, any>): Promise<void> {
// Write to master
await master.insert(data);
// Wait for at least one replica to confirm
await Promise.any(
replicas.map((replica) => replica.applyReplicationEvent(data))
);
// Only now confirm to the client
return; // Write confirmed
}
// Asynchronous: write is confirmed immediately, replication is background
async function asyncWrite(master: DB, replicas: DB[], data: Record<string, any>): Promise<void> {
// Write to master
await master.insert(data);
// Confirm to client immediately
// Replication happens in background
Promise.allSettled(
replicas.map((replica) => replica.applyReplicationEvent(data))
).catch((err) => console.error("Replication failed:", err));
return; // Write confirmed before replication
}
Retraso de Replicación y Consistencia Eventual
El retraso de replicación es el tiempo entre una escritura en el maestro y cuándo esa escritura se vuelve visible en las réplicas. En replicación asíncrona, el retraso puede variar de milisegundos a segundos (o incluso minutos bajo carga pesada). Esto significa que las réplicas sirven datos eventualmente consistentes.
Problemas Comunes Causados por el Retraso de Replicación
- Inconsistencia de lectura después de escritura: Un usuario escribe datos e inmediatamente los lee de una réplica que aún no ha recibido la actualización
- Violaciones de lectura monótona: Un usuario ve un valor más nuevo, luego en la siguiente solicitud llega a una réplica diferente más retrasada y ve un valor más antiguo
- Violaciones de causalidad: Una respuesta a un comentario aparece antes del comentario original en una réplica retrasada
Mitigando el Retraso de Replicación
class ConsistentReader {
private pool: DatabasePool;
// Strategy 1: Read-after-write consistency
// After a write, read from master for a short window
async readAfterWrite(
userId: string,
query: string,
params: any[],
lastWriteTimestamp: number
): Promise<any> {
const lagWindow = 5000; // 5 seconds
const timeSinceWrite = Date.now() - lastWriteTimestamp;
if (timeSinceWrite < lagWindow) {
// Recent write, read from master
return this.pool.master.execute(query, params);
}
// Safe to read from replica
return this.readFromReplica(query, params);
}
// Strategy 2: Monotonic reads
// Always route a user to the same replica within a session
async monotonicRead(
sessionId: string,
query: string,
params: any[]
): Promise<any> {
const replicaIndex = this.hashToReplica(sessionId);
return this.pool.replicas[replicaIndex].execute(query, params);
}
private hashToReplica(key: string): number {
let hash = 0;
for (let i = 0; i < key.length; i++) {
hash = (hash * 31 + key.charCodeAt(i)) % this.pool.replicas.length;
}
return hash;
}
}
Estrategias de Resolución de Conflictos
En la replicación multi-maestro, dos nodos pueden modificar la misma fila simultáneamente, creando un conflicto de escritura. Hay varias estrategias para resolver conflictos.
- Último en Escribir Gana (LWW): La escritura con el timestamp más reciente gana. Simple pero puede perder datos. Usado por Cassandra.
- Resolución a Nivel de Aplicación: La aplicación define lógica de fusión personalizada. Por ejemplo, un carrito de compras podría tomar la unión de elementos de ambas versiones.
- CRDTs (Tipos de Datos Replicados Libres de Conflictos): Estructuras de datos diseñadas para fusionarse automáticamente sin conflictos. Usados en herramientas de edición colaborativa.
- Vectores de Versión: Rastrean el historial causal de cada actualización para detectar y resolver modificaciones concurrentes. Usado por DynamoDB y Riak.
// Last Write Wins conflict resolution
interface VersionedRecord {
data: Record<string, any>;
timestamp: number;
nodeId: string;
}
function resolveConflictLWW(a: VersionedRecord, b: VersionedRecord): VersionedRecord {
if (a.timestamp > b.timestamp) return a;
if (b.timestamp > a.timestamp) return b;
// Tiebreaker: higher node ID wins
return a.nodeId > b.nodeId ? a : b;
}
// Application-level merge for a shopping cart
interface CartItem { productId: string; quantity: number; }
function mergeCart(cartA: CartItem[], cartB: CartItem[]): CartItem[] {
const merged = new Map<string, number>();
for (const item of [...cartA, ...cartB]) {
const current = merged.get(item.productId) || 0;
merged.set(item.productId, Math.max(current, item.quantity));
}
return Array.from(merged.entries()).map(([productId, quantity]) => ({
productId,
quantity,
}));
}
Herramientas de Replicación y Ejemplos del Mundo Real
| Base de Datos | Método de Replicación | Notas |
|---|---|---|
| PostgreSQL | Replicación de streaming (WAL) | Soporta sync, async y replicación lógica |
| MySQL | Replicación binlog | Basada en fila, en sentencia o mixta; soporta Group Replication para multi-maestro |
| MongoDB | Replica sets | Failover automático con elecciones; replicación basada en oplog |
| Cassandra | Peer-to-peer (sin maestro) | Todos los nodos son iguales; consistencia ajustable con lecturas/escrituras de quórum |
| CockroachDB | Consenso Raft | SQL distribuido fuertemente consistente con replicación automática |
Consejos para Entrevistas
- Por defecto usa maestro-esclavo para la mayoría de problemas de entrevista a menos que escalar escrituras sea un requisito declarado
- Siempre menciona el retraso de replicación y cómo tu diseño maneja la consistencia de lectura después de escritura
- Conoce las implicaciones del teorema CAP: la replicación te obliga a elegir entre consistencia y disponibilidad durante particiones
- Discute el failover: ¿qué pasa cuando el maestro cae? Promoción manual vs automática