TechLead
Leccion 6 de 30
7 min de lectura
Diseño de Sistemas

Teorema CAP Explicado

Entiende el teorema CAP con ejemplos del mundo real, aprende las compensaciones de sistemas CP vs AP, la extensión PACELC y cómo elegir el modelo de consistencia correcto

¿Qué Es el Teorema CAP?

El teorema CAP, propuesto por el científico informático Eric Brewer en 2000 y posteriormente demostrado por Seth Gilbert y Nancy Lynch en 2002, establece que un almacén de datos distribuido puede proporcionar como máximo dos de tres de las siguientes garantías simultáneamente:

  • Consistencia (C): Cada lectura recibe la escritura más reciente o un error. Todos los nodos ven los mismos datos al mismo tiempo.
  • Disponibilidad (A): Cada solicitud recibe una respuesta sin error, sin la garantía de que contenga la escritura más reciente. El sistema siempre está operativo.
  • Tolerancia a Particiones (P): El sistema continúa operando a pesar de particiones de red (fallos de comunicación entre nodos). Los mensajes entre nodos pueden perderse o retrasarse.

¿Por Qué No Las Tres?

Imagina que tienes dos nodos de base de datos, Nodo A y Nodo B, que replican datos entre sí. Ocurre una partición de red y los nodos ya no pueden comunicarse. Ahora un cliente escribe datos en el Nodo A. Cuando otro cliente lee del Nodo B, tienes una elección:

  • Retornar los datos antiguos (Elegir A sobre C): El Nodo B responde con datos desactualizados. El sistema está disponible pero inconsistente.
  • Retornar un error (Elegir C sobre A): El Nodo B se rehúsa a servir la lectura hasta que pueda confirmar que tiene los datos más recientes del Nodo A. El sistema es consistente pero no disponible.

No puedes tener ambos: no puedes retornar los datos más recientes del Nodo B si el Nodo B no los ha recibido del Nodo A debido a la partición. Esta es la compensación fundamental.

Por Qué la Tolerancia a Particiones No Es Negociable

En cualquier sistema distribuido desplegado a través de una red, las particiones de red van a ocurrir. Los cables se cortan, los routers fallan, las zonas de disponibilidad de la nube se vuelven inalcanzables. Como la tolerancia a particiones es una realidad más que una elección, la elección práctica es entre CP (consistencia + tolerancia a particiones) y AP (disponibilidad + tolerancia a particiones).

Un sistema que no tolera particiones — un sistema CA — sería esencialmente un sistema no distribuido ejecutándose en un solo nodo sin replicación. Aunque técnicamente es consistente y disponible, derrota el propósito de los sistemas distribuidos, que es sobrevivir a los fallos.

Sistemas CP: Consistencia + Tolerancia a Particiones

Un sistema CP prioriza la consistencia sobre la disponibilidad. Durante una partición de red, rechazará servir solicitudes en lugar de arriesgarse a retornar datos obsoletos. Cuando la partición se sana, todos los nodos tendrán datos consistentes.

Ejemplos de Sistemas CP

  • MongoDB (configuración predeterminada): En un replica set, las escrituras van al nodo primario. Si el primario es inalcanzable debido a una partición, el sistema elige un nuevo primario. Durante la elección, las escrituras son rechazadas (sacrificando disponibilidad por consistencia).
  • HBase: Construido sobre HDFS con garantías de consistencia fuerte. Usa ZooKeeper para coordinación.
  • Redis Cluster: Con la configuración predeterminada, Redis Cluster prefiere consistencia. Si un master falla y sus réplicas no pueden ser promovidas, el cluster rechaza escrituras a esos slots.
  • etcd / ZooKeeper: Estos servicios de coordinación usan protocolos de consenso (Raft y ZAB respectivamente) que garantizan consistencia fuerte.
// CP behavior illustrated in pseudocode
class CPDatabase {
  private nodes: DatabaseNode[];
  private quorumSize: number;

  async write(key: string, value: string): Promise<boolean> {
    // Must get acknowledgment from a majority of nodes (quorum)
    let acks = 0;
    const promises = this.nodes.map(async (node) => {
      try {
        await node.write(key, value);
        acks++;
      } catch (e) {
        // Node unreachable (partition)
      }
    });

    await Promise.allSettled(promises);

    if (acks >= this.quorumSize) {
      return true; // Write committed - consistency guaranteed
    }

    // Cannot reach quorum - reject the write (sacrifice availability)
    throw new Error('Write failed: cannot reach quorum');
  }

  async read(key: string): Promise<string> {
    // Must read from a majority to ensure we get the latest value
    const responses: string[] = [];
    for (const node of this.nodes) {
      try {
        const value = await node.read(key);
        responses.push(value);
      } catch (e) {
        // Node unreachable
      }
    }

    if (responses.length >= this.quorumSize) {
      // Return the value with the highest version/timestamp
      return this.getLatestValue(responses);
    }

    throw new Error('Read failed: cannot reach quorum');
  }
}

Sistemas AP: Disponibilidad + Tolerancia a Particiones

Un sistema AP prioriza la disponibilidad sobre la consistencia. Durante una partición de red, todos los nodos continúan aceptando lecturas y escrituras. Cuando la partición se sana, el sistema reconcilia escrituras conflictivas usando técnicas como last-write-wins, relojes vectoriales o CRDTs.

Ejemplos de Sistemas AP

  • Cassandra: Diseñada para disponibilidad. Cada nodo puede aceptar lecturas y escrituras. Usa niveles de consistencia ajustables — puedes configurar cuántas réplicas deben responder antes de que una lectura o escritura se considere exitosa.
  • DynamoDB: La base de datos NoSQL gestionada de Amazon favorece la disponibilidad. En su configuración predeterminada, las lecturas pueden retornar datos obsoletos (lecturas eventualmente consistentes), pero puedes optar por lecturas fuertemente consistentes a costa de mayor latencia.
  • CouchDB: Usa un modelo de replicación multi-master donde todos los nodos pueden aceptar escrituras. Los conflictos se detectan y almacenan, y la aplicación debe resolverlos.
  • DNS: El Sistema de Nombres de Dominio es un sistema AP clásico. Los servidores DNS pueden servir registros obsoletos durante particiones, priorizando disponibilidad sobre consistencia.

Comparación de Sistemas CP vs AP

Aspecto Sistemas CP Sistemas AP
Durante particiónPuede rechazar solicitudesSiempre responde
Frescura de datosSiempre actualizadoPuede estar desactualizado
Conflictos de escrituraPrevenidosDeben resolverse
LatenciaMayor (espera quórum)Menor (respuesta local)
Caso de usoSistemas financieros, inventarioRedes sociales, carritos de compra
EjemplosMongoDB, HBase, etcdCassandra, DynamoDB, CouchDB

Teorema PACELC

El teorema CAP solo describe el comportamiento durante una partición de red. Pero ¿qué pasa cuando la red funciona normalmente? El teorema PACELC extiende CAP para abordar esto:

Si hay una Partición (P), elige entre Disponibilidad (A) y Consistencia (C). En caso contrario (E), cuando el sistema opera normalmente, elige entre Latencia (L) y Consistencia (C).

Esto es importante porque incluso sin particiones, existe una compensación entre consistencia y latencia. Un sistema que requiere que una escritura se replique a todos los nodos antes de confirmarla (consistencia fuerte) tendrá mayor latencia que uno que confirma inmediatamente y replica en segundo plano (consistencia eventual).

Clasificaciones PACELC

Sistema Durante Partición (PAC) Operación Normal (ELC)
CassandraPA (Disponible)EL (Baja latencia)
DynamoDBPA (Disponible)EL (Baja latencia)
MongoDBPC (Consistente)EC (Consistente)
PostgreSQLPC (Consistente)EC (Consistente)
Cosmos DBPA/PC (Ajustable)EL/EC (Ajustable)

Cómo Elegir para Tu Sistema

La elección correcta depende completamente de los requisitos de tu aplicación. Aquí hay un marco de decisión:

Marco de Decisión

  • Elige CP cuando la corrección es crítica: Transacciones financieras (transferencias bancarias), gestión de inventario (vender de más es costoso), elección de líder, bloqueos distribuidos y cualquier sistema donde datos obsoletos podrían causar daño.
  • Elige AP cuando la disponibilidad es primordial: Feeds de redes sociales (mostrar una publicación ligeramente desactualizada está bien), carritos de compra (resolver conflictos después), analíticas y logging (alguna pérdida de datos es aceptable) y cualquier sistema donde el tiempo de inactividad impacta directamente los ingresos.
  • Usa consistencia ajustable cuando sea posible: Muchas bases de datos modernas (Cassandra, DynamoDB, Cosmos DB) te permiten elegir consistencia por consulta. Usa consistencia fuerte para operaciones críticas y consistencia eventual para todo lo demás.

Concepto Erróneo Común

El teorema CAP no significa que debas sacrificar consistencia o disponibilidad todo el tiempo. Sacrificas uno solo durante particiones de red, que son (esperemos) eventos raros. Durante la operación normal, puedes tener tanto consistencia fuerte como alta disponibilidad. El teorema PACELC hace esta distinción explícita: durante la operación normal, la compensación es entre latencia y consistencia, no disponibilidad y consistencia.

Continuar Aprendiendo