Skip to content

10.7.1 — Consistency Models: CAP, PACELC, and the Spectrum

"Consistency" is the most overloaded word in systems engineering: the C in ACID (a transaction preserves invariants) and the C in CAP (all readers see the same value) are different concepts, and conflating them wastes half the industry's design discussions. This page fixes the vocabulary: the spectrum of consistency models from linearizable to eventual, CAP stated precisely (and its common misreading corrected), PACELC (the refinement that matters more in practice), BASE, and how to choose a model per operation rather than per system.

1. The spectrum

Consistency models are promises about what a read may return given concurrent writes. From strongest to weakest, with the cost of each:

  • Linearizability (a.k.a. strong consistency, atomic consistency) — the system behaves as if there is one copy of the data and every operation takes effect at a single instant between its start and end. Consequence: once a write completes, every subsequent read (by anyone) sees it or something newer. This is the model humans naively assume. Cost: coordination on every operation — a consensus round or a leader round trip, so latency and reduced availability during partitions.
  • Sequential consistency — all nodes see operations in the same order, but that order need not match real time. Rarely offered explicitly; useful as a conceptual step.
  • Causal consistency — operations related by happens-before (10.3) are seen in that order by everyone; concurrent operations may be seen in different orders. Strong enough for most user-facing correctness (a reply never appears before its message), cheap enough to remain available during partitions — the "sweet spot" model, and what session guarantees approximate.
  • Session guarantees — the practical family from 10.5: read-your-writes, monotonic reads, monotonic writes, writes-follow-reads. These are per-client promises that make eventual consistency feel correct to the person using the app, and they're what most real systems actually implement.
  • Eventual consistency — if writes stop, replicas converge. Says nothing about when, and nothing about what you read meanwhile. Cheapest, most available, and adequate for a great deal (view counts, feeds, catalogs) — provided the staleness is bounded in practice and the UI doesn't lie.

A separate axis worth naming to prevent the classic confusion: transaction isolation (serializable, snapshot, read-committed — [7.4]) is about concurrent transactions on one database; consistency models are about replicas of the same data. Strict serializability = serializable isolation + linearizability, and is the strongest (and most expensive) combination.

2. CAP, stated precisely

The CAP theorem (Brewer's conjecture, 2000; Gilbert and Lynch's proof, 2002): in the presence of a network partition, a distributed system must choose between consistency (linearizability) and availability (every request to a non-failed node receives a non-error response). CAP theorem and PACELC honestly. [EQ-983b]

The near-universal misreading is "pick two of three." You do not choose partition tolerance — partitions are a fact of networks, not a design option. The theorem's actual content is a conditional: when a partition occurs, you must sacrifice either consistency or availability. So the honest categories are CP (during a partition, refuse requests on the minority side rather than serve stale or divergent data — a consensus store like etcd/ZooKeeper, or a leader-based database when the leader is unreachable) and AP (keep serving on both sides, accept divergence, reconcile later — Cassandra/Dynamo defaults, DNS, most caches).

Two further precisions that separate a careful answer from a slogan: CAP's "consistency" means linearizability specifically (weaker models like causal consistency are achievable while remaining available — which is why the theorem is less confining than folklore suggests); and CAP's "availability" means every node answers — a system that stays up on the majority side and fails the minority is neither fully A nor useless, which is precisely how most real systems behave.

3. PACELC: the part that governs your daily life

Partitions are rare; the trade-off you actually make every day is the other one — which is why PACELC (Abadi, 2012) is the more useful formulation: What is PACELC? [EQ-984b]

If there is a Partition (P), choose Availability (A) or Consistency (C); Else (E) — in normal operation — choose Latency (L) or Consistency (C).

The "else" clause is the design's everyday reality: strong consistency costs a round trip (to a leader or a quorum) on every operation, and that cost is paid 99.99% of the time when nothing is wrong. Classifying familiar systems: a single-leader SQL database with synchronous replication is PC/EC (consistent during partitions, and paying latency for it normally); DynamoDB and Cassandra defaults are PA/EL (available and fast, eventually consistent — with per-request strong reads available at a latency price); MongoDB with majority write concern is PC/EC; a CDN is PA/EL by construction.

Is there a partition?YES → Availability or ConsistencyNO (99.99%) → Latency or ConsistencyPAserve, divergePCrefuse minorityELlocal read, staleECquorum, slowerCassandra/Dynamo: PA/EL · Spanner: PC/EC · MongoDB (majority): PC/EC · CDN: PA/EL
Figure 1 — PACELC. CAP describes the rare partition case; the "else" branch describes normal operation, where every system trades latency against consistency on every single request. Most architectural pain lives on the right-hand side.

BASE — Basically Available, Soft state, Eventual consistency — is the AP-flavored counterpart to ACID's vocabulary: coined as a deliberate contrast, it describes systems that prioritize availability and accept temporary inconsistency, with convergence and application-level reconciliation as the correctness story. It's a stance, not a protocol, and its useful content is the reminder that ACID's guarantees are not free and are not always required.

4. Choosing per operation, not per system

The mature practice — and the strongest answer in a design review: consistency is a per-operation decision. Within one product:

OperationModelWhy
Account balance shown after a transferlinearizable / read-from-leadershowing stale money destroys trust and creates support load
"Was this username taken?" at signuplinearizable (unique constraint)a race here creates a permanent duplicate
Inventory decrement at checkoutlinearizable per SKU (conditional write)oversell is a real-world cost
Feed/timelineeventual + session guaranteesseconds of staleness are invisible; scale demands it
View counts, likeseventual (CRDT counters)approximate is fine; conflicts merge
Product catalogeventual, heavily cachedchanges are rare, staleness bounded by TTL

Two patterns support this: per-request consistency levels exposed by the datastore (Cassandra's ONE/QUORUM/ALL, DynamoDB's ConsistentRead, Mongo's read/write concerns) — so the code states the requirement; and compensating design — accept eventual consistency and add detection and repair (reconciliation jobs, 10.4) rather than paying coordination costs everywhere. The judgment sentence: pay for consistency where the business consequence of staleness exceeds the latency cost — and nowhere else.

5. The expert lens

"Eventually consistent" is not an excuse — it's a contract that needs a number. "Eventually" with no bound is unmanageable: the useful version is a staleness SLO ("replicas within 2 seconds, 99.9% of the time"), monitored and alerted like any other objective (10.10). Systems whose staleness is measured behave predictably; systems whose staleness is assumed produce the mystery bug reports of 10.5.

Most "we need strong consistency" requirements are really "we need read-your-writes." Users care that their own action is reflected, not that a global snapshot exists. That distinction is worth thousands of dollars and milliseconds: session guarantees are cheap (10.5's routing tricks) while linearizability is expensive, and the conversation that separates them ("who exactly must see this, and by when?") is one a senior engineer starts and a junior one skips.

The trade is bought with round trips, and you can locate them. Every strong-consistency guarantee corresponds to a physical message exchange — a leader hop, a quorum round, a lock acquisition. If someone claims strong consistency with no added latency, the guarantee is either weaker than claimed or purchased elsewhere (Spanner buys it with atomic clocks and a commit-wait — 10.3). Asking "which round trip pays for this?" turns marketing claims into architecture in one question.

Next: 10.7.2 — how strong consistency is actually built: 2PC's blocking problem, Raft step by step, leader election, and distributed locks done safely.

Recall

  • Spectrum: linearizability (one-copy illusion; every read sees the latest completed write — costs a round trip per op) → sequential → causal (happens-before respected; concurrent ops may differ — cheap and usually sufficient) → session guarantees (read-your-writes, monotonic reads/writes, writes-follow-reads — what real systems ship) → eventual (converges eventually; says nothing about when). Distinct axis: transaction isolation ([7.4]) is about concurrent transactions, not replicas.
  • CAP is a conditional, not a menu: partition tolerance isn't optional, so during a partition choose CP (refuse on the minority side) or AP (serve and diverge, reconcile later). Its "C" means linearizability specifically — weaker models stay available.
  • PACELC governs daily life: partition → A or C; else → Latency or Consistency. Classify systems as PA/EL (Cassandra, DynamoDB defaults, CDNs) or PC/EC (Spanner, majority-write Mongo, sync-replicated SQL). BASE is the AP-side stance opposite ACID.
  • Choose per operation: linearizable for balances after transfer, username uniqueness, inventory decrement; eventual + session guarantees for feeds, counts, catalogs. Use per-request consistency levels so the requirement is in the code, and pair eventual consistency with reconciliation (10.4).
  • Lens: "eventually consistent" needs a staleness SLO with monitoring; most "strong consistency" asks are really read-your-writes; every strong guarantee is paid for by an identifiable round trip — ask which one.

Self-test: Distinguish ACID's C from CAP's C. State CAP as a conditional and name what CP and AP do during a partition. Write PACELC in one sentence and classify three systems. Give three operations that need linearizability and three that don't. What number turns "eventual" from an excuse into a contract?

Quiz Bank

FoundationalDefine linearizability, causal consistency, and eventual consistency — and say what each costs.

Linearizability: the system behaves as though there is a single copy of the data and each operation takes effect atomically at some instant between its invocation and response — so once a write returns, every later read by anyone observes it or something newer. It's the model users intuitively assume ("I saved it, so it's saved"). Cost: coordination on every operation — a leader hop or quorum round — meaning added latency always and unavailability on the minority side of a partition.

Causal consistency: operations related by happens-before (10.3) appear in that order everywhere; genuinely concurrent operations may be observed in different orders by different nodes. It preserves the properties users actually notice (a reply never precedes its message, a delete never un-deletes) while remaining available during partitions — the strongest model achievable without sacrificing availability.

Eventual consistency: if writes stop, replicas converge; no promise about when or about intermediate reads. Cheapest and most available; adequate for feeds, counters, catalogs — but only manageable when paired with a bounded staleness objective and, usually, session guarantees (read-your-writes, monotonic reads) so individual users perceive coherence even though the global picture is loose.

FoundationalState the CAP theorem correctly and correct its usual misreading.

Correct statement: in the presence of a network partition, a distributed system cannot provide both linearizable consistency and availability (every request to a non-failed node returns a non-error response) — it must sacrifice one. The misreading: "pick two of C, A, P." Partition tolerance is not a choice — networks partition, and a system that isn't partition-tolerant is simply a system that breaks when they happen. The theorem is a conditional about behavior during partitions, yielding two real categories: CP (during a partition, the minority side refuses requests rather than serve potentially stale or divergent data — etcd, ZooKeeper, leader-based databases when the leader is unreachable) and AP (all sides keep serving, divergence is accepted and reconciled later — Dynamo-style stores, DNS, caches).

Two refinements that mark a careful answer: CAP's "consistency" is linearizability specifically, so weaker-but-useful models (causal, session guarantees) remain achievable while available — the theorem constrains less than folklore claims; and CAP's "availability" requires every non-failed node to answer, so the common real-world design (majority side serves, minority refuses) is a nuanced point on the spectrum rather than a clean letter.

AppliedWhat is PACELC, and why is it more useful day to day than CAP?

PACELC: if Partition → choose Availability or Consistency; Else → choose Latency or Consistency. It's more useful because partitions are rare while the else branch is every request you serve: strong consistency requires contacting a leader or assembling a quorum, so it costs a round trip all the time, when nothing is wrong — which is where most user-visible latency and most architectural regret actually come from. Classifications: Cassandra/DynamoDB defaults are PA/EL (stay up during partitions, serve local/fast reads normally, converge eventually — with per-request strong reads available at a latency price); Spanner and majority-write MongoDB are PC/EC (refuse rather than diverge, and pay coordination latency in normal operation); CDNs are PA/EL by construction. The practical payoff of the framing: it forces the design conversation past "are we CP or AP?" (a question that only matters during incidents) to "what latency are we paying for consistency on this operation, and is it worth it?" — a question with a different answer per endpoint, which is exactly how consistency should be chosen (section 4).

InterviewGive three operations in a typical product that need linearizability and three that don't, with reasons.

Need it: (1) Username/email uniqueness at signup — two concurrent registrations must not both succeed; the guarantee comes from a linearizable operation (a unique constraint in a single-leader store or a consensus-backed check), because the failure is permanent duplicate identity. (2)

Inventory decrement at checkout — the last unit must be sold once; implemented as a conditional atomic write on that SKU's row (9.5.4), which is linearizable per key — note that you rarely need global linearizability, only per-entity. (3)

Balance display immediately after a transfer — a stale balance after moving money produces support tickets and mistrust; strictly this is read-your-writes plus a linearizable write, which is the cheaper honest requirement. Don't need it: (1) Timeline/feed — seconds of staleness are unnoticeable, volume makes coordination prohibitive, and session guarantees make it feel correct. (2)

View counts and likes — approximate is acceptable and CRDT counters merge concurrent increments without coordination. (3) Product catalog / marketing pages — changes are rare, so a CDN with a TTL is both faster and more available than any consistent read (10.2). The pattern in the answer: consistency requirements track the business cost of being wrong, they're usually per-entity rather than global, and several apparent "strong consistency" needs are actually read-your-writes.

StaffA team proposes moving the entire product onto a strongly consistent global database 'so we never have consistency bugs.' Evaluate the proposal.

What's right about it: consistency bugs are genuinely expensive and hard to reason about, and a system where every read is linearizable removes a large class of subtle defects — plus modern options (Spanner, CockroachDB, Yugabyte) make it far more practical than a decade ago.

What's wrong with it as a blanket move: (1) You pay the PACELC "else" cost on every request forever — a global strongly consistent write requires cross-region coordination (a quorum round, or Spanner's commit-wait — 10.3), which is tens to hundreds of milliseconds; for feed reads and catalog pages, that's a large latency regression bought for a guarantee those endpoints don't need (section 4). (2)

It doesn't eliminate distributed-systems concerns — duplicate delivery, ordering across services, cache staleness, and the read-your-writes problems of any caching layer all survive (10.4); the team may believe they've bought more than they have. (3)

Availability profile changes — strongly consistent systems are CP: a partition or a quorum loss makes writes fail rather than degrade, which may be strictly worse for a consumer product than serving slightly stale data. (4) Cost and lock-in — these databases are expensive and their operational model is specialized.

Counter-proposal: keep a strongly consistent store for the operations whose staleness has real business cost (identity, money, inventory, entitlements — the section 4 list), and serve the read-heavy, staleness-tolerant surface from replicas/caches with session guarantees and a monitored staleness SLO. Make consistency an explicit per-operation parameter in the data layer so the requirement is visible in code review rather than implied by infrastructure choice.

Frame for the decision meeting: the goal isn't to eliminate consistency decisions — it's to make them explicit, per operation, and cheap to audit; a global strong database converts a design skill into a latency bill, and pays it on every request including the 95% that never needed it.

Flashcards

FlashConsistency spectrum

Linearizable (one-copy illusion, round trip per op) → causal (happens-before honored, stays available) → session guarantees (what real systems ship) → eventual (converges, unbounded unless you set an SLO).

FlashCAP, correctly

Conditional, not a menu: partitions aren't optional. During a partition: CP (refuse on minority) or AP (serve, diverge, reconcile). CAP's C = linearizability only.

FlashPACELC

Partition → A or C; Else → Latency or Consistency. The else branch is 99.99% of requests. PA/EL: Cassandra, DynamoDB, CDNs. PC/EC: Spanner, majority Mongo.

FlashACID's C vs CAP's C

ACID C = a transaction preserves invariants (a database property). CAP C = all readers see the latest write (a replication property). Different concepts, same letter.

FlashPer-operation consistency

Linearizable: uniqueness, inventory, balances-after-write. Eventual: feeds, counts, catalogs. Expose per-request levels so the requirement lives in code.

FlashTwo senior questions

"Who exactly must see this, and by when?" (usually read-your-writes, not linearizability) and "which round trip pays for this guarantee?"

Scenario Drill

DrillDesign the consistency model for a ride-hailing app: driver locations update every 4 seconds, riders see nearby drivers, a ride request must be assigned to exactly one driver, fares are computed at trip end, and ratings are eventually visible. Assign a model per operation with justification, and identify the one operation where getting it wrong is unrecoverable.

Per-operation assignments. Driver location updateseventual, deliberately lossy: locations are a firehose (every driver, every 4 seconds) whose value decays in seconds; write to a fast in-memory geospatial store with no durability guarantee, and treat a lost update as irrelevant because the next one arrives in 4 seconds. Coordination here would be absurd — this is the clearest EL choice in the system.

Riders seeing nearby driverseventual with bounded staleness (a few seconds), served from replicas/caches near the rider (10.2): a driver shown a block away from their true position is invisible to the user, while the latency of a consistent read would be very visible.

Ride assignmentlinearizable, per driver and per request: this is the unrecoverable one (below). Fare computation at trip endstrongly consistent write, eventually consistent read: the fare record must be written atomically once (idempotent on trip id — 10.4) because it becomes a financial record, but displaying it a second later from a replica is fine.

Ratingseventual, mergeable: aggregate counters/averages converge; a rating visible 30 seconds later harms nothing, and CRDT-style counters avoid conflicts entirely. The unrecoverable operation: ride assignment. Two riders assigned the same driver, or one request assigned to two drivers, produces a physical world inconsistency that no reconciliation job can fix — a driver cannot un-arrive, and a rider left waiting is a churned customer. So assignment requires a linearizable claim on the driver: a conditional atomic write (UPDATE drivers SET assigned_trip = ? WHERE id = ? AND assigned_trip IS NULL) — 9.5.4's claim protocol, at the exact point where the digital and physical worlds meet — plus per-driver serialization so the dispatcher's decisions for one driver are ordered (10.3's per-key ordering). The matching design consequence: the matching computation (which driver is best) may run on stale location data — that's fine, it's a heuristic — but the claim must be strongly consistent, and a lost claim simply means re-running the match with the next-best driver.

The general principle the drill teaches: consistency requirements are set by the cost of being wrong, and the highest cost is where software commits the physical world — everything upstream of the commit (locations, matching, ETAs) can be approximate and fast, while the commit itself is the one place to spend a coordination round trip.