Vibe Engines
YouTube

Vibe Engines is free, interactive AI engineering & system design — runs in your browser. Pick a learning path

System Design Fundamentals  /  CAP & Consistency
Fundamental 01~12 min readIntermediate
Deep Dive

The CAP theorem,
and the spectrum of consistency.

CAP is the most quoted and least understood idea in distributed systems. It's not "pick two of three" — it's a single forced choice that only matters in one specific moment. Here's what it really says, and the consistency models that live underneath it.

01

What CAP actually says

A distributed system tries to offer three things. Consistency — every read returns the most recent write (or an error). Availability — every request receives a non-error response, even if it isn't the latest. Partition tolerance — the system keeps working when the network drops or delays messages between nodes.

The theorem (Brewer's conjecture, proved by Gilbert & Lynch) says you can't have all three at the same time. But the framing "pick two of three" is misleading. In any real network, partitions will happen — cables fail, switches reboot, packets vanish. So partition tolerance isn't something you choose; it's something reality imposes. The actual decision is what to do during a partition: stay consistent, or stay available.

During a partition — you must pick one
CP

Consistency + Partition

Refuse or block requests that can't be confirmed correct. Some nodes go unavailable, but no one ever reads stale data.

AP

Availability + Partition

Answer every request from whatever replica is reachable, even if it's behind. Reconcile the divergence once the partition heals.

There is no "CA" column. A system that gives up partition tolerance is just a single node.
02

Why "CA" is a myth

People often label a single-node SQL database as "CA". That's only true because a single node can't be partitioned from itself. The moment you replicate that database across two machines to survive failure, you've entered the distributed world, and a partition between them forces the same CP-or-AP choice.

So the honest reading of CAP is: P is mandatory, and you trade C against A only when P strikes. When the network is healthy, a well-built system can deliver both strong consistency and high availability — CAP says nothing about the happy path. Which is exactly the gap PACELC fills.

→ Common interview trap

If you say "I'll build a CA system," a sharp interviewer will ask what happens when two replicas can't reach each other. Always frame your answer as CP or AP, and say which operations need which.

03

What "available" means in the proof

CAP's three words have narrow, formal meanings. Hold real databases to them and most are neither CP nor AP.

Gilbert and Lynch proved the theorem for exact definitions. Consistency means linearizability: the system behaves as if there were one copy of the data, and every read returns the most recent completed write. Availability means every request received by a node that hasn't crashed eventually gets a non-error response. Not most requests, and not only requests on the majority side: every live node, on both sides of the split. Partition tolerance means the network may lose any number of messages between nodes. The theorem then says one precise thing: while the network is split, no system can be linearizable and also answer on every live node.

Real systems rarely fit either label under those definitions:

SetupLinearizable?Every live node answers during a partition?Strict label
Raft cluster, reads checked by the leader (etcd's default)YesNo: nodes on the minority side refuse requestsCP
Leaderless store, quorum reads and writesNo (section 09 shows why)No: a node that can't reach W or R replicas returns an errorNeither
Single leader, reads from async followersNo: followers lag even with no partitionNo: the side without the leader can't writeNeither
Every node keeps a full copy, accepts local writes, merges laterNoYesAP

So use CAP for the one thing it proves, and describe a real system by what it actually guarantees: which consistency model, for which operations, and what a client sees when its node is cut off. CAP is also silent on most of what you design around day to day: latency, crashed nodes, and every consistency model weaker than linearizability. Brewer made the same point in his 2012 retrospective, "CAP Twelve Years Later", and Martin Kleppmann's essay "Please stop calling databases CP or AP" argues it straight from the definitions.

→ Interview phrasing

Instead of "Cassandra is AP", describe the configuration: "At QUORUM it keeps serving a key while a majority of that key's replicas is reachable, and it isn't linearizable." That sentence survives the follow-up questions. The label doesn't.

04

PACELC — the part CAP forgets

PACELC completes the picture: if there is a Partition, trade Availability vs Consistency; Else (normal operation), trade Latency vs Consistency. The insight is that consistency has a cost even with no failures: to guarantee a read sees the latest write, replicas must coordinate, and coordination takes round-trips. Lower latency means accepting weaker guarantees.

SystemOn partitionElse (normal)Classification
Dynamo / CassandraAvailabilityLatencyPA / EL
BigTable / HBaseConsistencyConsistencyPC / EC
MongoDB (as rated in 2012)AvailabilityConsistencyPA / EC
SpannerConsistencyConsistencyPC / EC

These labels describe default configurations, and defaults move. MongoDB 5.0 made majority write concern the default, which changes what a primary cut off from its majority can acknowledge. Treat a PACELC label as a question to ask of a configuration, not a property of a product.

Some stores let you slide the trade-off per request: Cassandra through its consistency level (how many replicas must answer), DynamoDB by choosing an eventually consistent or a strongly consistent read. For leaderless stores that knob is the quorum, worked through below; the replication mechanics behind it are in partitioning and replication.

05

The consistency spectrum

"Consistency" isn't one thing. It's a ladder of guarantees, each weaker and cheaper than the one above.

From strongest (most coordination) to weakest (most available)
StrongestLinearizable — behaves like a single copy; every read sees the latest completed write, in real-time order.
↓Sequential — all nodes see operations in the same order, not necessarily real-time.
↓Causal — operations that depend on each other are seen in order; unrelated ones may differ.
↓Read-your-writes — you always see your own latest change (session guarantee).
↓Monotonic reads — you never see time go backwards across reads.
WeakestEventual — replicas converge if writes stop; reads may be stale meanwhile.

Pick the weakest model that still keeps your product correct. A bank balance needs linearizability. A "likes" counter is fine with eventual consistency. A chat app usually wants causal, so a reply never appears before the message it answers.

→ Mental model

Consistency is chosen per operation, not per system. The same database can require a linearizable write for an account balance and serve an eventually-consistent read for that account's activity feed.

06

Linearizability is not serializability

One is about time, the other about transactions. Swapping them is the most common consistency mistake in interviews.

Linearizability is a recency guarantee for single operations on one object, such as a key or a register. Once a write completes, every read that starts afterwards returns that value or a newer one, and once any read has returned the new value, no later read may return the old one. It says nothing about grouping operations together. Serializability is an isolation guarantee for transactions that touch many objects: the outcome equals running the transactions one at a time in some order. That order need not match real time, so a serializable database may legally answer a read-only transaction from a slightly old snapshot.

LinearizabilitySerializability
Applies toSingle reads and writes of one objectTransactions over many objects
PromiseReal-time recency: no read goes back in timeSame result as some serial order
Rules outStale reads; a value flipping back to an older oneWrite skew, phantoms, lost updates
Needed forLeader election, locks, unique usernames, compare-and-setInvariants across rows: balances, bookings, stock
Typical mechanismConsensus, or a single leader on the read pathTwo-phase locking, serial execution, SSI

Get both and you have strict serializability: transactions appear to run one at a time, in an order consistent with real time. Google's Spanner provides it under the name external consistency, using its TrueTime clock bounds to order commits. Two-phase locking and actual serial execution are typically strictly serializable too. Serializable snapshot isolation (PostgreSQL's SERIALIZABLE level) is not, by design: every read in a transaction comes from the snapshot taken at its first statement, so a write that commits while the transaction runs stays invisible to it. Isolation levels and their anomalies are covered in concurrency and locking.

→ Interview trap

"Is it consistent?" needs two answers. For single operations: is it linearizable? For transactions: what isolation level? A system can say yes to one and no to the other. The C in CAP means linearizability; the C in ACID means something else again, the application invariants that atomicity and isolation help you keep.

07

Tunable consistency & quorums

Leaderless stores let you dial consistency at query time. With N replicas, a write waits for W acknowledgements and a read queries R replicas. If W + R > N, every read set overlaps every write set, so each read reaches at least one replica holding the latest acknowledged write. That overlap is what people usually mean by "strong consistency" here, but it is a weaker promise than linearizability, and section 09 lists where it breaks. Lower the numbers and you trade that freshness for latency and availability.

Quorum trade-off (N = 3)

W=3, R=1  ·  W+R>N

  • Every read overlaps every write
  • Fast reads, slow writes
  • Write fails if any replica is down

W=1, R=1  ·  W+R≤N

  • Eventually consistent
  • Fast and highly available
  • Reads may be stale

This is the bridge between CAP and the physical mechanics of replication — and when you need a single agreed value rather than a tunable one, you've crossed into consensus.

08

The quorum math, played out

Run the failure case by hand. Three replicas hold x = 1. A client writes x = 2 with W = 1: node A acknowledges, the write returns "success," and A now disagrees with B and C. A read with R = 1 lands on node C — it returns x = 1. Stale, and the client has no way to know.

W=1 write → {A: 2, B: 1, C: 1}   then  R=1 read hits C → returns 1 (stale)

Now the same write with W = 2 (A and B ack) and a read with R = 2 (hits B and C). The read set must include B — a node with the new value — because two sets of size 2 drawn from 3 nodes cannot avoid each other. The read compares versions and returns 2. That's the entire theorem behind tunable consistency:

W + R > N  ⇒  every read set overlaps every write set in ≥ 1 node  ⇒  the latest acknowledged write is always among the replies

Every configuration for N = 3, worked out (this table is exhaustively checkable — the runnable proof is below):

WRW+R>3?GuaranteeProfile
11no (2)eventual — stale reads possiblefastest, most available
21no (3)still stale-able — a common misconfigwrite-safe ≠ read-safe
22yes (4)guaranteed overlapbalanced; survives 1 node down
31yes (4)guaranteed overlapfast reads; writes fail if any node down
13yes (4)guaranteed overlapfast writes; reads fail if any node down

Note the trap in row two: W = 2, R = 1 "feels" safe — a majority acked the write! — but 2 + 1 = 3 is not greater than 3, and the single-node read can land on the one replica that missed the write. This is exactly how Cassandra's QUORUM write + ONE read surprises people in production. And the "yes" rows promise overlap, not linearizability; the next section shows what still goes wrong.

09

Where W + R > N stops protecting you

The overlap proof is airtight. The systems running it are not, and each gap below returns stale or lost data with the quorum rule satisfied.

The brute-force proof assumes every write lands on W of the key's own N replicas, writes never race, and a write either reaches W replicas or none. Production breaks all three assumptions:

CaseWhat happensResult
Sloppy quorumThe key's home replicas are unreachable, so other nodes accept the write and hand it back later (hinted handoff)The W acks came from nodes a read never asks, so the read can miss the write until handoff
Concurrent writesTwo clients write one key at once, replicas see the writes in different orders, and last-write-wins keeps the higher timestampOne acknowledged write silently disappears, and with clock skew it can be the later one
Partly failed writeThe write reaches fewer than W replicas and the client is told it failed, but nothing rolls back the replicas that took itLater reads may return a write the client believes never happened
Read during a writeThe write is still spreading when the read arrivesEither value can come back, and two reads in a row can disagree
Stale restoreA replica holding the new value dies and is rebuilt from one holding the old valueFewer than W replicas now hold the write, so overlap no longer covers it

The fourth row is why quorums aren't linearizable even when nothing fails. With N = 3, a writer sends x = 2 with W = 3, and the write reaches replica C first:

t1  C has x=2; A and B still have x=1       (write in flight)
t2  reader 1: R=2, asks B and C  -> 1, 2    -> returns 2
t3  reader 2 starts after reader 1 returned
    R=2, asks A and B            -> 1, 1    -> returns 1

Reader 2 started after reader 1 had seen the new value, and still got the old one. Every quorum rule held, and linearizability forbids exactly this.

Read repair is the partial fix: when a read sees replicas disagree, the coordinator writes the newest version back to the stale ones, and a background anti-entropy process (Dynamo and Cassandra compare Merkle trees) catches the keys nobody reads. If the reader finishes that repair before returning, and every writer first reads the latest version from a quorum, plain reads and writes on one key become linearizable, at a cost in latency. Riak skips the synchronous repair for performance. Cassandra does wait for repair on quorum reads, but still loses linearizability under concurrent writes because it resolves them by last-write-wins. And a linearizable compare-and-set ("create this username only if it's free") can't be built this way at all: it needs consensus. Try the failure cases in the quorum simulator, or size N, W and R in the quorum explorer.

→ Say this instead of "strong consistency"

"With W + R > N on strict quorums, every read reaches a replica holding the latest write acknowledged before it began, as long as writes don't race and replicas don't lose data. It isn't linearizable, so I wouldn't build uniqueness or locks on it."

RUN IT YOURSELF

Prove W + R > N by brute force

Don't take the overlap rule on faith — enumerate it. This checks every possible write set and read set for a given N, W, R and reports whether a stale read is even constructible. Then it replays the failure story from above. Change N to 5 or 7 and the rule keeps holding — that's why it's a theorem, not a heuristic.

CPython · WebAssembly
Frequently asked

Quick answers

What is the CAP theorem?

During a network partition, a distributed system can guarantee either Consistency (every read returns the latest write) or Availability (every request gets a non-error response), but not both. Since partitions are unavoidable, the real choice is CP vs AP.

Why can't a system be CA?

Partition tolerance isn't optional — networks fail. A pure CA system only exists on a single node. Once partitioned, it must drop either availability or consistency, collapsing into CP or AP.

What is PACELC?

If Partition, trade Availability vs Consistency; Else, trade Latency vs Consistency. It captures that stronger consistency costs latency even when nothing has failed.

Strong vs eventual consistency?

Strong (linearizable) consistency means every read reflects the latest write, at the cost of coordination latency. Eventual consistency lets replicas disagree briefly but converge, trading freshness for speed and availability.

Does W + R > N guarantee strong consistency?

No. It guarantees that every read set overlaps every write set, so each read reaches at least one replica holding the latest acknowledged write. That is weaker than linearizability: sloppy quorums, concurrent writes resolved by last-write-wins, writes that fail on some replicas but not others, and replicas restored from stale copies can all return stale or lost data. Linearizable reads and writes need synchronous read repair, and a compare-and-set still needs consensus.

What is the difference between linearizability and serializability?

Linearizability is a recency guarantee for single reads and writes: once a write completes, every later read sees it or something newer. Serializability is an isolation guarantee for transactions over many objects: the result equals some serial order, which need not match real time. Strict serializability, which Spanner calls external consistency, provides both.

▶  Watch it explained

The CAP theorem: why a database can't be both consistent and available

Finished this one? 0 / 208 Handbooks done
NextPartitioning, Sharding & Replication Next on the “Distributed systems, from first principles” ladder · rung 3 of 7

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

More Handbooks