DistributedCAPpartitionconsistencyavailabilityquorum

CAP and Distributed Systems

A network partition is not a choice — any timeout is one — so the real decision is what a system does while it lasts: refuse writes to stay consistent, or accept writes on both sides and reconcile later; quorums (W + R > N) define the boundary precisely, and PACELC adds the everyday trade the slogan omits: latency versus consistency when nothing is broken at all.

▶ InteractiveInterview questionDebug it
Progress
What problem does this solve?

Once data lives on more than one machine, the machines will at some point be unable to talk to each other while clients can still reach both; the system must have decided in advance which guarantee it keeps in that moment, because whichever it does not keep is what its users will experience.

Partitions are not optional

The CAP theorem is usually presented as a menu — consistency, availability, partition tolerance, "pick two" — and the menu is misleading, because partition tolerance is not on offer. A partition is any situation in which two nodes that should communicate cannot, for long enough to matter. Cables get cut, but far more often a switch drops packets for 8 seconds, a garbage collection pause stops a node for 20 seconds, a kernel is starved of CPU, or a link is simply slow enough that every request times out. A timeout is a partition: from the caller’s point of view there is no difference between "the network is down" and "the node is too slow to answer within my deadline", and the caller has to decide what to do without knowing which it is. If your system runs on more than one machine, partitions will happen; the only decision available is what the system does *during* one.

The precise statement is this: during a partition, a system with replicated data must either refuse some operations (typically writes, and sometimes reads, on the side that cannot reach a majority) to keep a single, consistent history — or accept operations on both sides and therefore allow the sides to diverge, to be reconciled afterwards. The first is what CAP calls consistent (CP), the second available (AP). Both are legitimate; neither is free; and the choice can be made per operation, not just per system.

Two replicas, a partition, and two clients who can each reach only one
write balance = 80replication stallswrite balance = 50?Client (EU)Client (US)Replica 1 (EU)partition: link timing outReplica 2 (US)
ClientGateway / LBServiceWorkerDatabaseCacheQueue / LogObject storageCDNExternal system

What consistency means here, and what availability costs

The "C" in CAP is linearizability: every operation appears to take effect atomically at some instant between its start and its end, so that once any client has seen a write, every later read anywhere sees it or something newer — the system behaves as if there were one copy. That is a much stronger property than the "C" in ACID, and it is expensive because it requires the replicas to agree before answering. Eventual consistency is the weak end: replicas may return different values for a while, and are guaranteed only to converge once writes stop and communication resumes. Between them sit useful intermediate guarantees — read-your-own-writes, monotonic reads, causal consistency — which Distributed Consistency: CAP, Quorums, Consensus covers in detail; in practice the most common architectures offer linearizability for a few operations (a unique-username check, a balance debit, a leader election) and eventual consistency for the rest.

Choosing availability during a partition is not "free availability". The system that accepts balance = 80 in Europe and balance = 50 in the US must later decide which is right, and there is no general answer: last-writer-wins silently discards one of them, version vectors detect the conflict and hand it to the application, and CRDTs restrict the data types to ones that merge automatically (counters, sets, registers with defined merge rules). Shopping carts merge well — a union of items is acceptable. Bank balances do not, which is why a bank refuses the write instead. The choice is dictated by whether a conflict can be resolved meaningfully after the fact.

Quorums: the boundary made precise

Quorum systems turn the choice into arithmetic. With N replicas, a write is acknowledged after W replicas have it, and a read consults R replicas and takes the newest. If W + R > N, every read set overlaps every write set in at least one replica, so a read is guaranteed to see the latest acknowledged write. With N = 3, W = 2, R = 2, the system tolerates one replica being unreachable for both reads and writes; a side of a partition holding only one replica can serve neither, which is the consistent choice. Set W = 1, R = 1 and both sides keep serving — the available choice — at the cost of stale reads and divergent writes. Sloppy quorums and hinted handoff (Dynamo, Cassandra) let writes land on any W reachable nodes, not the designated ones, and forward them later; this keeps writes available through a partition and weakens the overlap guarantee, so the numbers stop meaning what they appear to mean.

Consensus protocols — Raft in etcd, Consul and CockroachDB, ZAB in ZooKeeper, Paxos in Spanner — are the strict form: a majority must agree on every write in order, and the minority side of a partition cannot make progress at all. That is exactly the property a lock service or a leader election needs: two leaders is worse than no leader.

N = 3 replicas: what each side of a partition can do
                      W=2, R=2 (W+R > N)          W=1, R=1
side with 2 replicas  reads ✓  writes ✓           reads ✓  writes ✓
side with 1 replica   reads ✗  writes ✗           reads ✓ (stale?)  writes ✓ (diverge)
after healing         one history                  conflict → LWW / vector clocks / CRDT merge

PACELC, and concrete systems

CAP describes the partition, which is rare. PACELC adds the everyday case: if there is a Partition, trade Availability against Consistency; Else, trade Latency against Consistency. A system that stays linearizable in normal operation pays a round trip to a quorum on every write, and often on every read; one that answers from the nearest replica is faster and can be stale. Cross-region synchronous replication is the sharpest example — 80 ms per commit between Frankfurt and Virginia, for every write, forever, in exchange for never losing an acknowledged write in a regional failure. That latency is the price of consistency when *nothing is wrong*, and it is paid far more often than the partition-time price.

What a system actually does during a partition is a matter of its configuration, not its marketing, and most systems can be tuned to either side.

Behaviour during a partition and in normal operation (PACELC)
SystemDuring a partitionNormal operation: latency vs consistencyNotes
PostgreSQL, synchronous replicationPrimary blocks commits until a sync standby acknowledges; the minority side (a lone standby) is read-onlyPays one replica round trip per commit for zero-loss failoverAsync mode flips it: commits proceed, failover can lose the tail; see Replication and Read Scaling
etcd / ZooKeeper / Consul (Raft, ZAB)Majority side serves reads and writes; minority side refuses writes and, by default, linearizable readsEvery write is a majority round trip; reads can be served locally if staleness is allowedDesigned for locks, leader election and configuration, where two truths are unacceptable
Cassandra / DynamoDB-style ringsTunable: QUORUM refuses on the minority side; ONE keeps both sides writing with hinted handoffConsistency level per query trades latency for freshnessConflicts resolved by last-writer-wins (timestamp) unless the application uses versioned reads
MongoDB replica setMajority side elects a primary and continues; minority primary steps down within an election timeout and becomes read-onlyw: majority waits for replication; w: 1 is faster and can roll back on failoverRead preference secondary adds stale reads even with no partition
Kafka (acks=all, min.insync.replicas=2)A partition whose in-sync set falls below 2 refuses produces; consumers keep reading committed offsetsacks=all costs a replica round trip per batch; acks=1 is faster and can lose the tail on leader failureUnclean leader election, if enabled, chooses availability and loses data; see Kafka-Style Logs: Topics, Partitions, Offsets
Redis Sentinel / ClusterA minority master keeps accepting writes until min-replicas-to-write or cluster-node timeouts stop it; those writes are lost on failoverAsync replication: fast, and a failover can discard acknowledged writesFine for caches and ephemeral state; wrong as the only store for money
DNSEvery resolver keeps serving cached answers until the TTL expires; fully available, arbitrarily staleAnswers from the nearest cache; propagation takes minutes to hoursThe purest AP system in daily use

Designing for the partition you will have

Because partitions include timeouts, every system that makes a remote call has already made a CAP decision, usually by accident. A payment service that times out on the database and returns an error chose consistency. One that times out and returns "probably succeeded" chose availability and must now reconcile — which is where the idempotency key from the async module and the compensation in Saga Pattern come from; Distributed Transactions is the same problem stated for multi-step writes. Make the decision explicit, per operation: the operations that cannot tolerate divergence (debits, unique names, leader election, inventory reservation) go through a quorum or a single leader and are unavailable on the minority side; everything else (view counts, presence, carts, feeds) accepts writes anywhere and merges.

Then rehearse it. Inject latency and drop links between availability zones in staging and watch what each store does; the failure that surprises you in production is the one you assumed was a theory. Leases should have expiry so a partitioned leader stops leading before a new one is elected (fencing tokens make the old leader’s late writes rejectable). And the minority side should *know* it is the minority: a node that cannot reach a majority should say so, not guess.

  • Every remote timeout is a partition; the code path after the timeout is your CAP policy whether or not you wrote it as one.
  • Choose per operation, not per system: quorum for the few things that cannot diverge, availability with merge rules for the rest.
  • PACELC is the daily bill: synchronous cross-region consistency costs a round trip on every write, all year, not only during outages.
  • A partitioned leader must step down on lease expiry, and stale writes must be fenced; otherwise "consistent" is a configuration, not a fact.

Key points

  • Partition tolerance is not a choice; any timeout is a partition. The only decision is what the system does during one.
  • During a partition: refuse operations on the minority side (consistent), or accept on both sides and reconcile later (available). Choose per operation.
  • CAP’s consistency is linearizability — one apparent copy — and it costs a quorum round trip; eventual consistency guarantees only convergence.
  • W + R > N gives read/write overlap and tolerates N − max(W, R) unreachable replicas; sloppy quorums and hinted handoff trade that guarantee for availability.
  • PACELC: with no partition, the trade is latency versus consistency, and that cost is paid on every write, every day.

A partition: choose consistency or availability

A partition: choose consistency or availability
Three replicas of x. Cut the network between {1,2} and {3}, then write and read on each side under a CP or an AP policy.
Policy
On conflict
W + R = 4 > 3: reads overlap the latest write
replica 1 (left)
x=0 v0
replica 2 (left)
x=0 v0
replica 3 (right)
x=0 v0
writes accepted
0
writes / reads refused
0
stale reads
0
conflicts on heal
0
startx=0 on all three replicas
No partition and W + R > N: every read overlaps the latest write's replicas, so reads are consistent — at the price of waiting for 2 acks per write and 2 replies per read. That is PACELC's E-L-C: even without a partition you trade latency for consistency. A partition is not exotic: a 5 s timeout to replica 3 is indistinguishable from a cut cable. Timeouts are partitions.
strongly consistent   every read returns the latest acknowledged write (linearizable: as if one copy)
eventually consistent  replicas converge once writes stop flowing; reads in between may be stale
quorum rule            W + R > N  ⇒  the read set intersects the last write set
PACELC                 if Partition: Availability or Consistency; Else: Latency or Consistency

How data moves through it

One request or event, hop by hop.

  1. 1Client (EU) → Replica 1: write balance = 80; Replica 1 forwards to Replica 2 and 3 and waits for W acknowledgements.
  2. 2Replica 1 → Replica 2: replication times out — a partition, whatever the cause. With W = 2 and Replica 3 reachable, the write commits; with only Replica 1 reachable, it is refused.
  3. 3Client (US) → Replica 2: read balance; with R = 2 and no majority reachable, Replica 2 refuses (consistent) or answers with its last value flagged as possibly stale (available).
  4. 4Link heals → Replicas: missing writes are streamed; if both sides accepted writes, the conflict is resolved by the configured rule or handed to the application.
  5. 5Leader lease expires → Minority leader: steps down; the majority elects a new leader; writes carrying the old leader’s fencing token are rejected.

When to use — and when not

Use it when
  • Every time data is replicated across machines, zones or regions: decide, per operation, which side of a partition may proceed.
  • Choosing a store: read its partition behaviour (leader election, quorum settings, conflict resolution) before its feature list.
  • Designing timeouts and error paths in any service that calls another: the post-timeout branch is the CAP policy.
Avoid it when
  • As a slogan to justify a choice ("we picked AP") without stating what happens to conflicting writes.
  • On a single-node system: there is no replication, so there is no partition to reason about — it is simply up or down.
  • To reason about latency in normal operation: that is PACELC’s second half, and it usually matters more than the partition case.

Tradeoffs

Complexity
low → high
Ops cost
low → high
Latency
low → high
Consistency
weak → strong
Scalability
poor → strong

The rating depends entirely on the side chosen: a quorum system has high consistency and pays latency; an available system has low latency and shifts the complexity into conflict resolution.

How it fails

  • Split brain: both sides of a partition elect a leader and accept writes; after healing, two histories exist and one is discarded.
  • A "consistent" store configured for availability: Redis with async replication or Kafka with unclean leader election loses acknowledged writes on failover.
  • Last-writer-wins with skewed clocks: the "newest" write is the one from the node whose clock is ahead, not the one that happened last.
  • Timeout treated as failure for a write that actually committed: the client retries without an idempotency key and the operation happens twice.
  • A minority node that keeps serving reads confidently: users see data that the majority has since changed, with no indication it is stale.

How it scales

  • Quorum cost grows with replica count and distance; keep N small (3 or 5) and place replicas in zones close enough that the round trip is acceptable.
  • Scale out by partitioning the keyspace so each partition has its own small quorum (Consistent Hashing), rather than one large consensus group.
  • Multi-region active-active requires conflict resolution by design (CRDTs, per-region ownership of keys); multi-region active-passive keeps one writer and pays failover time instead.

How it interacts with databases, queues, caches, APIs and external systems