Zurück zum Blog
Apr. 2026·4 Min. LesezeitKI-generiert
Sprache:DeutschEnglishFrançaisÖsterreichischKlingonisch Originalfassung: English

Das CAP-Theorem, erklärt mit echten Beispielen

#distributed-systems#databases#architecture

Jeder Hersteller verteilter Datenbanken behauptet, schnell, konsistent und immer verfügbar zu sein. Das CAP-Theorem ist der Grund, warum man bei diesem Versprechen misstrauisch sein sollte: Bei einer Netzwerkpartition kann man nur zwei von Consistency (Konsistenz), Availability (Verfügbarkeit) und Partition Tolerance (Partitionstoleranz) behalten, und Partitionstoleranz ist nicht wirklich optional – die eigentliche Wahl liegt also zwischen Konsistenz und Verfügbarkeit.

Was die drei Buchstaben tatsächlich bedeuten

  • Consistency (C): Jeder Lesezugriff erhält den jüngsten Schreibvorgang oder einen Fehler. Alle Knoten sehen zur selben Zeit dieselben Daten.
  • Availability (A): Jede Anfrage erhält eine (nicht fehlerhafte) Antwort, ohne Garantie, dass sie den jüngsten Schreibvorgang enthält.
  • Partition Tolerance (P): Das System arbeitet weiter, obwohl eine beliebige Anzahl von Nachrichten zwischen Knoten verworfen oder verzögert wird.

Netzwerkpartitionen passieren – ein Switch fällt aus, eine Rechenzentrumsverbindung wird gesättigt, die Netzwerkkarte eines Knotens spinnt. Da man nicht aussteigen kann, dass das Netzwerk unzuverlässig ist, ist P keine echte Designentscheidung, sondern eine Tatsache verteilter Systeme. Bleibt die Wahl zwischen C und A während einer Partition. Außerhalb einer Partition kann ein gut gebautes System beides bieten.

Warum „wähle zwei" irreführend ist

Die klassische Formulierung „wähle zwei von drei" suggeriert, CA sei eine gültige Option, als ließe sich Partitionstoleranz abschalten. Das geht nicht, außer das System läuft auf einer einzigen Maschine ganz ohne Netzwerkaufrufe. In der Praxis reduziert sich das Theorem also auf eine Frage: Bleibt dein System bei einer Partition verfügbar, auf Kosten der Konsistenz, oder bleibt es konsistent, auf Kosten der Verfügbarkeit?

CP in der Praxis: ein Leader-basierter Konfigurationsspeicher

Betrachte einen Konfigurationsdienst auf Basis eines Raft-basierten Speichers (etcd, Consul, ZooKeeper). Schreibvorgänge laufen über einen Leader, der auf eine Mehrheit der Knoten replizieren muss, bevor er bestätigt.

Client -> Leader -> [replicate to majority] -> ack -> Client

Teilt eine Netzwerkpartition den Cluster in zwei Gruppen, kann nur die Gruppe mit der Mehrheit der Knoten einen Leader wählen und Schreibvorgänge annehmen. Die Minderheitsseite nimmt gar keine Schreibvorgänge mehr an – sie gibt Fehler zurück, statt zu riskieren, veraltete oder widersprüchliche Daten auszuliefern.

# Simplified: a node in the minority partition rejects writes
def handle_write(request):
    if not self.has_quorum():
        raise Unavailable("no quorum: refusing to risk inconsistent write")
    return self.replicate_and_commit(request)

Das ist CP: Konsistenz bleibt erhalten, indem auf der Minderheitsseite die Verfügbarkeit geopfert wird. Genau das will man bei Konfigurationsdaten, Leader-Wahl oder verteilten Sperren – einen veralteten Sperren-Besitzer auszuliefern ist schlimmer als ein vorübergehender Ausfall.

AP in der Praxis: ein Warenkorb-Dienst

Betrachte nun einen Warenkorb, gespeichert in einer Dynamo-artigen Datenbank (Cassandra, DynamoDB) mit mehreren Replikaten über Regionen hinweg. Während einer Partition nimmt jedes Replikat weiterhin unabhängig Schreibvorgänge an.

# Simplified: every reachable replica accepts writes during a partition
def handle_write(request):
    self.local_store.put(request.key, request.value, timestamp=now())
    return Ack()  # never blocks on other replicas

Zwei Regionen können nun auseinanderlaufende Versionen desselben Warenkorbs haben. Heilt die Partition, braucht das System eine Abgleichsstrategie – Last-write-wins nach Zeitstempel, Vector Clocks oder ein Merge auf Anwendungsebene (die Artikel vereinen, statt eine Seite zu wählen).

# A simple merge strategy: union cart items instead of picking a winner
def merge_carts(cart_a, cart_b):
    return {**cart_a, **cart_b}  # naive union; real systems need care around removals

Das ist AP: Der Warenkorb-Dienst bleibt auf beiden Seiten der Partition verfügbar, und die Korrektheit wird nachträglich wiederhergestellt, statt während des Schreibens erzwungen. Für einen Warenkorb schlägt ein verfügbares, aber letztlich konsistentes System ein konsistentes, aber ausgefallenes – niemand will zwischen Stöbern und Kasse ein „Dienst nicht verfügbar".

Es ist keine einzelne systemweite Entscheidung

Die nützliche Erkenntnis ist, dass CAP pro Operation gilt, nicht für ein Datenbankprodukt als Ganzes. Viele reale Systeme mischen beides: DynamoDB bietet auf derselben Tabelle sowohl letztlich konsistente als auch stark konsistente Lesezugriffe. PostgreSQL mit synchroner Replikation ist für die Schreibvorgänge des Primärknotens CP, kann aber mit asynchronen Standbys konfiguriert werden, die veraltete (AP-lastige) Lesezugriffe bedienen.

-- PostgreSQL: synchronous_commit controls where you sit between C and A
SET synchronous_commit = 'on';   -- wait for replica ack: favors consistency
SET synchronous_commit = 'off';  -- don't wait: favors availability/latency

Entwirf auf der Ebene einzelner Operationen: Braucht dieser Schreibvorgang linearisierbare Konsistenz, oder kann dieser Lesezugriff ein paar Sekunden veraltet sein? Pro Operation statt pro Datenbank zu antworten ist, wo CAP als Entwurfswerkzeug seinen Wert beweist.

PACELC: die unterschätzte Fortsetzung des Theorems

CAP beschreibt nur das Verhalten während einer Partition. Daniel Abadis PACELC-Erweiterung ergänzt den häufigeren Fall: Auch ohne Partition tauscht man Latenz gegen Konsistenz. If Partitioned, wähle Availability oder Consistency; Else (Normalbetrieb), wähle Latency oder Consistency.

Ein System, das synchron in eine entfernte Region repliziert, bekommt starke Konsistenz, zahlt aber bei jedem Schreibvorgang einen regionsübergreifenden Roundtrip. Ein System, das asynchron repliziert, bekommt niedrige Latenz, aber Leser sehen womöglich veraltete Daten, selbst wenn das Netzwerk völlig gesund ist. Dieser Kompromiss besteht bei jeder einzelnen Anfrage, nicht nur bei seltenen Partitionsereignissen – weshalb er für das tägliche Systemdesign wichtiger ist als der Partitionsfall.

Anwenden, wenn man tatsächlich etwas entwirft

  • Identifiziere, welche Operationen im Stil von Sperren/Leader-Wahl/Bestandsverringerung sind (brauchen CP) und welche im Stil von Warenkorb/Profil/Analytics (vertragen AP).
  • Wähle keine Datenbank wegen des Marketingversprechens „immer konsistent und immer verfügbar" – diese Kombination übersteht keine echte Partition. Frage konkret, was sie tut, wenn Knoten einander nicht erreichen.
  • Prüfe, ob der Konsistenz-Regler pro Cluster oder pro Anfrage gilt. Systeme wie DynamoDB und Cassandra lassen die Wahl pro Lesezugriff zu, was meist die richtige Granularität ist.
  • Denk an PACELC: Deine Konsistenzentscheidung hat Latenzkosten auf dem Normalpfad, nicht nur Risikokosten bei Ausfällen.

Das CAP-Theorem ist kein Grund, sich vor verteilten Systemen zu fürchten – es ist eine Checklisten-Frage, die man jeder Datenbank stellen sollte, bevor man darauf baut: Was genau passiert mit meinen Anfragen, wenn eine Partition zuschlägt, und auf welcher Seite dieses Kompromisses müssen meine Daten tatsächlich stehen?

NeuerEin einfaches Pub/Sub-System in Node.js bauenÄlterEin praktischer Leitfaden zur JWT-Authentifizierung