CMD Guide
HomeSystem DesignSystem Design Building Blocks

PACELC Theorem

PACELC works because replication forces a standing decision on every write: the coordinator either blocks until enough remote replicas acknowledge — paying latency so that a later read is guaranteed to see the value — or returns the instant one local copy is durable, winning latency but leaving a staleness window until asynchronous propagation catches up. That knob exists whether or not the network is currently partitioned, which is exactly the case CAP is silent about.

The CAP recap, stated correctly

CAP says that during a network partition (P) a replicated system must give up either consistency (C) or availability (A). Traditional ACID relational stores (MySQL, PostgreSQL, Oracle) lean CP: a node that cannot confirm it holds the latest committed state refuses to answer. The genuinely AP, quorum-based, eventually-consistent stores are the Dynamo lineage — Cassandra, Amazon DynamoDB, Riak — which answer from whatever local copy they have and reconcile later.

One clarification the source material usually botches: Redis is not an AP eventually-consistent store. Standalone and Cluster Redis are single-primary with asynchronous replication to replicas. It is not a quorum store that returns divergent-but-mergeable values; instead a failover can silently drop writes the old primary had already acknowledged. Grouping Redis under "BASE/AP, answers without checking peers" conflates two very different models — a single-primary latency-first store versus a multi-master eventually-consistent one. Keep them separate.

CAP's blind spot: what governs the trade-off when there is no partition? A partition is rare; the system spends 99.9% of its life in the non-partitioned state, and it is still making a consistency choice there. That is the gap PACELC fills.

The theorem

For a system that replicates data:

The classification tag reads P?/E? — e.g. PA/EL means "favour availability under partition, favour latency otherwise." The crucial nuance: the tag describes a configuration, not a database. Most modern stores expose the L-vs-C knob per operation (Cassandra's consistency level, DynamoDB's strong-vs-eventual read flag, MongoDB's write/read concern), so the same product can be EL for one query and EC for the next.

diagram
diagram

Worked trace: the Else-branch knob in Cassandra

Setup: a keyspace with replication factor RF = 3, one replica per availability zone. The coordinator happens to be replica A (local, ~0.8 ms to persist); replicas B and C are cross-AZ, ~6 ms RTT away. The row user:42 currently holds balance = 90 on all three. A client issues balance = 100. No partition exists — we are purely in the E branch, choosing L vs C.

Path 1 — CL = ONE (the EL choice)

  1. t = 0.0 ms — client1 writes balance = 100 at CL=ONE. Coordinator A persists locally and, because only one ack is required, immediately dispatches async copies to B and C.
  2. t = 0.8 ms — A returns success to client1. Total write latency ≈ 0.8 ms. B and C have not applied the mutation yet.
  3. t = 1.0 ms — client2 reads user:42 at CL=ONE; the coordinator routes it to the nearest replica, C.
  4. C still holds the old value → returns balance = 90. The read was fast (~0.5 ms) but stale.
  5. t ≈ 6 ms — B and C finally apply the write; the cluster converges. Latency won; consistency was sacrificed for a ~5 ms window. That is EL.

Path 2 — CL = QUORUM read and write (the EC choice)

Now write and read both at QUORUM (2 of 3). The write blocks until A and the faster of B/C ack → ≈ 6 ms. A QUORUM read contacts 2 replicas and returns the value with the highest timestamp. Because W + R = 2 + 2 = 4 > RF = 3, the read set and write set are guaranteed to overlap in at least one replica that saw the completed write → client2 reads 100. Consistency won, at the cost of ~5 ms extra latency and no answer if two replicas are down.

ConfigWrite waits forWrite latencyR + W vs RFGuarantee (Else branch)
W=ONE, R=ONE1 replica~0.8 ms2 ≤ 3stale reads possible → EL
W=QUORUM, R=QUORUM2 of 3~6 ms4 > 3last completed write visible → EC
W=ALL, R=ONE3 of 3~6 ms + tail4 > 3strong, but no writes if any replica down
diagram
diagram

Classifying real systems

Pitfalls

When to use PA/EL — and when NOT to

Reach for PA/EL (Cassandra, DynamoDB eventual reads, Riak) when the workload is write-heavy and geo-distributed, "always writable" is a hard requirement, and a few milliseconds-to-seconds of staleness is harmless: activity feeds, view/like counters, telemetry and IoT ingest, shopping carts, session stores. Gain: low tail latency and writes that survive an AZ or region loss. Cost: the application must tolerate or merge stale and concurrent values — you inherit last-write-wins lost updates unless you model data as CRDTs / commutative operations or merge in the app.

Prefer PC/EC (HBase, Bigtable, Spanner, MongoDB w:majority) when a stale or lost write is a correctness bug: financial ledgers, inventory decrement, uniqueness constraints, anything needing read-your-writes or cross-row transactions. Gain: reads reflect the latest committed state; far simpler application logic. Cost: higher and more variable latency (Spanner's commit-wait, single-primary bottlenecks), and reduced availability during partition — the minority side rejects requests.

Choosing against named alternatives

Crisp rule: choose PA/EL when availability and latency outrank freshness and your writes commute; prefer PC/EC when a stale or lost write would be a bug.

Takeaways


Sources: Daniel Abadi, "Consistency Tradeoffs in Modern Distributed Database System Design" (IEEE Computer, 2012) — the paper that coined PACELC; Eric Brewer's CAP conjecture and the Gilbert–Lynch proof; Martin Kleppmann, Designing Data-Intensive Applications (quorums, replication, linearizability); the Cassandra consistency-level docs, Amazon DynamoDB developer guide, MongoDB write-concern/read-concern docs (default w:majority since 5.0), and the Google Spanner / TrueTime paper (OSDI 2012). Re-authored and deepened for this guide — Redis mislabeling corrected, quorum example traced with real values.

🤖 Don't fully get this? Learn it with Claude

Stuck on PACELC Theorem? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **PACELC Theorem** (System Design) and want to truly understand it. Explain PACELC Theorem from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **PACELC Theorem** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **PACELC Theorem** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **PACELC Theorem** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes