Tier 2 · Distributed Core

CAP, Properly — and PACELC

Why "we chose AP" is not an answer, and what the theorem actually forbids

⏱ 17 min distributedconsistencytradeoffs 📕 Ch 6 — Design a Key-Value Store

What the theorem actually says

Three properties, with the definitions that make the proof work:

The theorem: you cannot have all three simultaneously.

The proof is a paragraph. Partition the network into two halves. A client writes to one half, another client reads from the other. If both must respond (availability), the reader cannot know about the write (no messages cross), so it returns stale data — consistency lost. If it refuses to answer to avoid staleness, availability is lost.

The misreading that ruins it

"Pick two of three" implies all three are on the menu. They aren't.

You do not choose P. Partitions are a property of networks, not an architectural option. Cables get cut, switches misconfigure, a GC pause makes a node indistinguishable from an unreachable one. If you're running on more than one machine, you must tolerate partitions or you simply lose the data when one happens.

So the real statement is much narrower:

That last part is why CAP is a poor design tool on its own. It describes a rare emergency, and most of your engineering effort goes into the other 99.9% of the time.

What CP and AP look like in practice

Choice during partition Concretely
CP Minority side stops serving ZooKeeper/etcd: without a quorum, nodes reject requests. HBase: the region is unavailable until reassigned.
AP Every side keeps answering Cassandra/Dynamo with low quorums: all replicas answer, divergence repaired later. DNS: famously stale, famously up.

Two honest caveats, both worth saying out loud:

PACELC: the part you'll actually use

Daniel Abadi's extension is the more useful formulation, because it covers the normal case:

If there is a Partition, choose Availability or Consistency; Else, choose Latency or Consistency.

The "else" branch is the real design decision. Even with a perfectly healthy network, keeping replicas consistent means waiting for them — and that wait is measured in the round-trip times you can't argue with. A cross-region linearizable read costs the speed of light whether or not anything is broken.

System PACELC Reading
Cassandra (default) PA/EL Stays up during partition; favours latency normally
DynamoDB PA/EL Same, with per-request ConsistentRead to opt into C
Spanner PC/EC Refuses rather than diverge; pays coordination cost always
MongoDB (default) PC/EC Primary-only writes; consistency preferred both branches
PostgreSQL + async replica PC/EL Single primary is consistent; follower reads trade C for L

It's a dial, not a switch

The framing that actually survives contact with a real design: consistency is chosen per operation, not per system.

In one product you might have:

Cassandra exposes this as tunable consistency per query (ONE, QUORUM, ALL); DynamoDB as a per-read flag. Saying "CAP is chosen per operation, and here's the one operation in this design where I'd pay for linearizability" is a genuinely senior answer.

Walking a partition, concretely

A cluster of 5 nodes across two datacenters — 3 in Zurich, 2 in Frankfurt. The link between them dies. Both sides are healthy internally.

CP choice (quorum = 3): Zurich has 3 nodes, forms a quorum, keeps serving reads and writes. Frankfurt has 2, cannot reach quorum, and rejects everything — including reads, because it cannot know whether Zurich has newer data. Frankfurt users see errors. When the link heals, Frankfurt catches up from the log. No data was lost, no conflicting writes exist.

AP choice: Both sides serve. A Zurich user and a Frankfurt user update the same record. Both succeed. When the link heals, you have two versions of one record and no ordering between them — you now need last-write-wins (silent data loss), version vectors plus application merge, or a CRDT.

Neither is correct in the abstract. Which is right depends entirely on whether a wrong answer is worse than no answer — and that's a product question, not an engineering one. The interview answer that lands is: "For the ledger, CP — I'd rather show an error than double-spend. For the feed, AP — stale posts are fine, an error page is not."

What to take away

Check yourself

  1. In the CAP theorem, what does the C stand for precisely?

  2. Why is 'pick two of three' a misleading way to describe CAP?

  3. What does the 'EL' in a PACELC classification of PA/EL mean?

  4. Which requirement cannot be satisfied by an AP design, no matter the conflict-resolution strategy?