Saltar al contenido

053 — Réplica: líder único, multilíder y sin líder

🗂️ parte 🎚️ nivel ⏱️ duración 📗 clase

Programa · Parte 10 · ← Anterior · Siguiente →

Parte 10 — Distribución, réplica y consistencia · Avanzado · 4 horas estimadas · motores postgresql, mysql, cassandra · laboratorio labs/07-replication · 3 fuentes.

Conceptos centrales: replicación sincrónica · retraso de réplica · quórum · lectura de tu propia escritura

En este caso se comparan 7 motores: 6 lo resuelven (0 con el resultado comprobado por máquina) y 1 no, con el motivo escrito.

De qué trata esta clase

Las tres arquitecturas de réplica y el compromiso que define cada una. La consecuencia visible para el usuario es el retraso de réplica: guardar algo y al recargar no verlo. Introduce las garantías de sesión que lo tapan y el quórum de los sistemas sin líder.

flowchart LR
    C["🗄️ Clase 053"]
    C --> K1["replicación sincrónica"]
    C --> K2["retraso de réplica"]
    C --> K3["quórum"]
    C --> K4["lectura de tu propia escritura"]
    classDef raiz fill:#0b3d2e,stroke:#3fb950,color:#fff
    class C raiz

Antes de empezar

Esta clase supone que ya trabajaste lo siguiente. Si algo de la última columna no te suena, vuelve a esa clase antes de seguir: aquí se usa sin volver a explicarlo.

# Clase previa Lo que se da por sabido
043 ACID: qué garantiza cada letra y quién la implementa atomicidad · consistencia · aislamiento · durabilidad · unidad de recuperación
046 Registro anticipado y recuperación: WAL y ARIES WAL · punto de control · rehacer · deshacer · LSN

Vocabulario de la clase

Los términos que siguen se usan más adelante con este significado exacto. La definición completa, con sus términos relacionados, está en el glosario del programa.

Término Qué significa Procedencia
replicación sincrónica El líder no confirma la escritura hasta que al menos una réplica la ha recibido. Garantiza que no se pierda al caer el líder, a cambio de que la latencia del cliente incluya la de la réplica más lenta y de que una réplica caída pueda detener las escrituras. se introduce aquí
retraso de réplica La distancia temporal entre lo que ya está en el líder y lo que la réplica ha aplicado. Con replicación asíncrona es inevitable, y es la causa directa de que un usuario guarde algo y al recargar no lo vea. se introduce aquí
quórum Regla de los sistemas sin líder: si las escrituras van a W réplicas, las lecturas consultan R, y W + R > N, entonces toda lectura toca al menos una réplica con el último valor. Permite ajustar el compromiso entre latencia y frescura por operación. se introduce aquí
lectura de tu propia escritura Garantía de sesión que asegura que quien acaba de escribir verá su propio cambio, aunque otros aún no. Se implementa dirigiendo al líder las lecturas recientes de ese usuario, o esperando a que la réplica alcance el LSN de su escritura. se introduce aquí

Propósito

Replicar datos entendiendo qué se gana (disponibilidad, lectura escalada, cercanía geográfica) y qué se paga (retraso, conflictos, pérdida potencial en la conmutación).

Resultados de aprendizaje

Al terminar podrás:

  1. Comparar las tres topologías de replicación y su modelo de fallo.
  2. Explicar el retraso de réplica y las anomalías que produce.
  3. Aplicar las garantías de sesión que las corrigen.
  4. Calcular quórums de lectura y escritura sin líder.
  5. Decidir entre replicación síncrona y asíncrona con un criterio de negocio.

Fundamentos

Las tres topologías

Topología Escrituras Conflictos Ejemplos
Líder único Un nodo Imposibles PostgreSQL, MySQL, SQL Server
Multilíder Varios nodos Inevitables, hay que resolverlos Multirregión, CouchDB, CRDT
Sin líder Cualquier nodo, por quórum Se resuelven al leer Dynamo, Cassandra, Riak

Con líder único no hay conflictos de escritura por construcción: todas pasan por el mismo nodo, que las ordena. Es la razón por la que sigue siendo la elección correcta salvo que haya un motivo fuerte para otra cosa.

Síncrona frente a asíncrona

Modo Confirma cuando Se pierde en la conmutación Latencia de escritura
Asíncrona El líder escribió Lo aún no replicado Baja
Síncrona Al menos una réplica confirmó Nada +1 ida y vuelta
Semisíncrona Una réplica de N Nada, si esa sobrevive +1 ida y vuelta

La asíncrona es la configuración por defecto casi siempre, y significa que una conmutación puede perder transacciones ya confirmadas al cliente. No es un fallo: es el compromiso elegido. Debe estar escrito en el objetivo de punto de recuperación (RPO, clase 048).

PostgreSQL permite ajustarlo por transacción:

SET synchronous_commit = 'remote_apply';   -- solo para las operaciones críticas

Patrón útil: asíncrono por defecto, síncrono para pagos.

El retraso y sus anomalías

El retraso de réplica es el tiempo entre confirmar en el líder y ser visible en la réplica. Con carga normal son milisegundos; durante una carga masiva o un VACUUM pesado, pueden ser minutos.

SELECT client_addr,
       pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS bytes_de_retraso,
       replay_lag
FROM pg_stat_replication;

Tres anomalías, con sus nombres y sus remedios:

Anomalía Qué ve el usuario Garantía que la corrige
Lee su propia escritura y no la ve Publica un comentario y desaparece Lectura de tus escrituras
Ve datos que retroceden Refresca y el comentario vuelve a desaparecer Lectura monótona
Ve un efecto antes que su causa La respuesta antes que la pregunta Consistencia causal (clase 046)

Implementaciones habituales:

Sin líder y quórums

Dynamo introdujo el modelo: se escribe en N réplicas, se espera confirmación de W, se lee de R.

R + W > N  →  los conjuntos de lectura y escritura se solapan
              → alguna réplica leída tiene la última escritura

Con N = 3:

W R Solapa Tolera
2 2 1 nodo caído en ambas operaciones
3 1 0 en escritura, 2 en lectura
1 3 2 en escritura, 0 en lectura
1 1 No Máxima disponibilidad, sin garantía

Advertencia importante: R + W > N no da linealizabilidad. Garantiza que alguna réplica leída tiene el valor más reciente, no que se sepa distinguirlo si hay escrituras concurrentes, ni protege contra reversiones si un nodo se recupera con datos viejos. Bailis et al. desarrollan qué se puede y qué no se puede garantizar sin coordinación.

Mecanismos de reparación: reparación en lectura (al detectar réplicas atrasadas, se corrigen), entrega con pista (un nodo vecino acepta la escritura del caído y se la entrega al volver) y reparación anti-entropía periódica.

flowchart TD
    subgraph L["Líder único"]
        W1["Escritura"] --> LD["Líder"]
        LD -->|"WAL"| R1["Réplica 1"]
        LD -->|"WAL"| R2["Réplica 2"]
        R1 --> RD1["Lectura (con retraso)"]
    end
    subgraph S["Sin líder"]
        W2["Escritura"] --> N1["Nodo 1"]
        W2 --> N2["Nodo 2"]
        W2 --> N3["Nodo 3"]
        RD2["Lectura R=2"] --> N1
        RD2 --> N2
        RD2 --> REP["Reparación en lectura<br/>si divergen"]
    end

Ejemplo trabajado

Sistema: un líder y dos réplicas asíncronas; las lecturas se reparten entre las réplicas.

La anomalía, con traza real:

t0    Cliente escribe la nota  -> líder. COMMIT. Respuesta 200.
t0+5ms Cliente recarga la ficha -> réplica 2 (retraso: 340 ms)
t0+5ms Respuesta: la nota no aparece.
t0+1s  Cliente recarga         -> réplica 1 (retraso: 12 ms)
t0+1s  Respuesta: la nota aparece.
t0+2s  Cliente recarga         -> réplica 2 (aún atrasada)
t0+2s  Respuesta: la nota DESAPARECE otra vez.

Dos anomalías en cinco segundos: no lee su propia escritura y la lectura no es monótona. Para el usuario, el sistema está roto; para el equipo, todo está «en verde».

Corrección 1 — leer del líder tras escribir:

def leer_ficha(ctx, student_id):
    # Tras una escritura propia, leer del líder durante una ventana
    # holgadamente mayor que el retraso p99 observado.
    if ctx.escribio_hace_menos_de(seconds=10):
        return leer(lider, student_id)
    return leer(replica_de(ctx.session_id), student_id)

Corrección 2 — esperar al LSN, más precisa y sin cargar el líder:

def escribir_nota(ctx, ...):
    lsn = lider.execute("...; SELECT pg_current_wal_lsn()")
    ctx.session["lsn_minimo"] = lsn

def leer_ficha(ctx, student_id):
    r = replica_de(ctx.session_id)
    if r.replay_lsn() < ctx.session.get("lsn_minimo", 0):
        return leer(lider, student_id)      # esta réplica aún no alcanza
    return leer(r, student_id)

Corrección 3 — fijar la sesión a una réplica. Resuelve la lectura monótona (nunca retrocede) pero no la lectura de las propias escrituras si esa réplica va atrasada. Se combina con la 1 o la 2.

Cálculo de capacidad de lectura. Con un líder que sostiene 8 000 lecturas/s y dos réplicas iguales:

solo líder:          8 000 lecturas/s
líder + 2 réplicas: 24 000 lecturas/s teóricas
con el 10 % desviado al líder por consistencia: ~21 600 útiles

Y el límite que no se supera: las escrituras no escalan. Todas van al líder. Añadir réplicas no aumenta en nada la capacidad de escritura; eso exige particionar (clase 044).

Comparación

Necesidad Topología
Escalar lecturas Líder único + réplicas
Alta disponibilidad regional Líder único con conmutación automática
Escritura en varias regiones Multilíder, con resolución de conflictos
Tolerar la caída de varios nodos Sin líder con quórum
Cero pérdida en la conmutación Replicación síncrona
Latencia mínima de escritura Asíncrona, con RPO declarado

Errores frecuentes

  1. Conmutación automática con réplica asíncrona sin declarar el RPO. Se pierden transacciones confirmadas.
  2. Repartir lecturas sin garantías de sesión. Aparecen las tres anomalías.
  3. Suponer que las réplicas escalan la escritura. No lo hacen.
  4. Cerebro dividido en multilíder. Dos líderes aceptando escrituras que después no se pueden reconciliar.
  5. R + W > N interpretado como linealizabilidad. No lo es.
  6. No vigilar el retraso. Una réplica atrasada sirve datos viejos sin ningún error visible.

De la clase a la operación

El retraso de réplica es la métrica que más incidencias explica y la que menos se mira. Una alerta sobre el retraso p99 —y la lógica que desvía al líder cuando se supera— evita la clase entera de incidencias «me desaparecen los datos».

Reto de transferencia

  1. Levanta un líder y una réplica y mide el retraso bajo carga de escritura.
  2. Reproduce las tres anomalías con un cliente que lea de la réplica.
  3. Implementa la corrección por LSN y demuestra que desaparecen.
  4. Calcula el RPO real de tu configuración actual, en segundos y en transacciones.

Preguntas de evaluación

  1. ¿Cuántas transacciones se pierden en una conmutación asíncrona con 340 ms de retraso y 2 000 escrituras/s?
  2. Explica por qué fijar la sesión a una réplica no resuelve la lectura de tus escrituras.
  3. Con N = 5, enumera las combinaciones R/W que solapan y su tolerancia a fallos.
  4. Da una operación de tu sistema que justifique replicación síncrona y otra que no.

🌐 El mismo problema en cada motor

Caso: Quién puede aceptar una escritura, y qué pasa cuando ese nodo cae

Solo hay tres topologías de réplica y cada una responde distinto a la misma pregunta: ¿quién puede aceptar una escritura?

Con líder único, uno solo; los demás copian. Es simple y no hay conflictos de escritura, pero el líder es un punto de fallo y su conmutación es la operación más delicada del sistema. Con multilíder, varios; hay conflictos y hay que resolverlos. Sin líder, cualquiera: el cliente escribe en varias réplicas y lee de varias, y la coherencia se arregla por quórum y reparación.

Esta comparación no tiene salida que verificar: lo que se compara es qué ofrece cada motor y, sobre todo, qué se pierde exactamente cuando el nodo que manda deja de contestar.

Esta comparación es conceptual: la decisión no se reduce a una consulta con resultado, así que aquí no hay sello de máquina. Lo que se compara es lo que cada motor ofrece y a qué precio, con la página oficial al lado de cada afirmación.

Motor ¿Resuelve el caso? Nivel de prueba Código Fuente
PostgreSQL conceptual doc oficial
MySQL conceptual doc oficial
MongoDB conceptual doc oficial
Apache Cassandra conceptual doc oficial
Redis conceptual doc oficial
CockroachDB conceptual doc oficial
SQLite no doc oficial

Los que resuelven el caso

PostgreSQL

MySQL

MongoDB

Apache Cassandra

Redis

CockroachDB

Los que no resuelven este caso — y qué se hace en su lugar

Descartar un motor con un argumento es tan formativo como usarlo. Ninguna de estas filas dice que el motor sea peor: dice que este problema no es el suyo.

Motor Por qué no Qué se hace en su lugar Fuente
SQLite No tiene réplica: es una biblioteca sobre un archivo. Copiar el archivo mientras se escribe produce una copia corrupta, y no hay mecanismo de difusión de cambios. Proyectos construidos encima —Litestream para réplica continua del WAL a almacenamiento de objetos, o rqlite y dqlite, que ponen Raft alrededor de SQLite— resuelven casos concretos sin cambiar de motor. doc

Laboratorio

python scripts/validate_repository.py
python labs/07-replication/run_replication_lab.py

Guarda como evidencia la salida completa, la versión del motor y la semilla o los parámetros usados. Una captura sin comando no es evidencia: no se puede repetir.

Evaluación

Criterio Peso Qué se comprueba
Comprensión conceptual 25 % Explica el mecanismo, no solo el resultado
Ejecución reproducible 25 % Otra persona obtiene lo mismo con las instrucciones dadas
Interpretación basada en evidencia 25 % Cada conclusión se apoya en una salida o una medición
Límites y riesgos declarados 25 % Dice qué no demuestra el ejercicio y qué faltaría en producción

La clase se da por superada cuando la respuesta explica el mecanismo, muestra la salida que la respalda y declara al menos un límite del ejercicio.

Fuentes de esta clase

Todo lo afirmado arriba procede de estas obras. Los identificadores viven en catalog/sources.json y el estado de los enlaces se comprueba con python scripts/check_external_links.py.


Programa · Parte 10 · ← Anterior · Siguiente →