Skip to content
SparkTime, home
System Design From Zero to Interview-Ready
Lessons
1 · System Design Foundations
2 · APIs and Communication
3 · Capacity Estimation
4 · Core Building Blocks
5 · Databases
6 · Distributed Systems
7 · Reliability and Operations
8 · Architecture and Security
9 · Interview Method and Foundation Case Studies
10 · Real-World Case Studies
11 · Large-Scale Case Studies
12 · Interview Readiness
Lesson 19 of 45

Lesson 19 · Distributed Systems

CAP Theorem and Consistency Models Explained Without the Myths

What "consistent" means when data is replicated, from linearizability through causal and session guarantees to eventual consistency; what the CAP theorem actually says and why "pick two" misleads; PACELC and the everyday latency trade-off; quorum reads and writes; resolving conflicts; and choosing consistency per feature instead of per system.

On this page

Key takeaways

  • Consistency models describe what readers may see while replicas catch up, from linearizable (behaves like one copy) to eventual (copies converge if writes stop).
  • CAP says that during a network partition a replicated system must choose, per operation, between staying linearizable and answering every request; without a partition there is no forced choice.
  • PACELC adds the everyday trade-off: even without partitions, stronger consistency usually costs latency.
  • With N replicas, write quorum W and read quorum R overlap when W + R > N, but quorums alone do not guarantee linearizability.
  • Choose consistency per feature: strong where wrong answers cost money or safety, session guarantees for a user's own data, eventual for counters and feeds.

"CAP theorem: consistency, availability, partition tolerance; pick two." Almost every candidate has heard it, and many repeat it in interviews, then say "so we chose AP" as if that settled the design. It is one of the most misunderstood ideas in the field. The slogan is not exactly wrong, but it hides what the theorem says, when it applies, and the trade-off you actually face every day, which is not about partitions at all.

This article first builds a clear vocabulary for "consistency" when data lives in several places, then states CAP precisely, adds PACELC, works through quorum arithmetic, and ends with the practical skill: choosing a consistency level per feature.

What you will learn

#
  • What consistency means for replicated data (and how it differs from the C in ACID).
  • The main consistency models: linearizable, causal, session guarantees and eventual.
  • What the CAP theorem states, and the common myths around it.
  • PACELC: the latency-versus-consistency trade-off when nothing is broken.
  • Quorums: N, W and R, with a program that checks overlap.
  • Resolving conflicts when replicas accept concurrent writes.
  • How to choose consistency per feature, with worked examples.

Two meanings of "consistency"

#
  • In ACID (article 12), consistency means a transaction keeps the database valid: constraints hold.
  • In distributed systems, consistency describes what reads may return while copies of the data are being updated: will a reader see the latest write, an older value, or values in a strange order?

This article is about the second meaning. When someone says "eventually consistent", they mean that one.

Consistency models, from strongest to weakest

#

A consistency model is a promise about which results reads may return. Jepsen, which tests databases' guarantees, maintains a reference describing many models and how they relate (Consistency models). For system design, five are enough.

Linearizability ("strong consistency")

#

The system behaves as if there were a single copy of the data, and every operation takes effect at one instant between its start and finish. Once a write completes, every read that starts afterwards sees it (or a later value), whichever replica serves it (Linearizability).

  • Example need: "seat C14 is booked" must be seen by everyone the moment the booking succeeds; a username, once taken, must be taken for everyone.
  • Cost: replicas must coordinate on writes (or reads must go to a leader), adding latency, and during a network partition some requests must be refused.

Causal consistency

#

Operations that are causally related are seen by everyone in the same order; operations that are unrelated (concurrent) may be seen in different orders by different readers.

  • Example need: a reply must never appear before the message it replies to; "unfriend X" followed by "post a private photo" must not let X see the photo.
  • Cost: lower than linearizability; the system must track dependencies.

Session guarantees

#

Weaker promises scoped to one client's session, which fix the most visible anomalies cheaply:

  • Read your writes: a user always sees their own changes.
  • Monotonic reads: a user never sees data go backwards in time.
  • Monotonic writes: a user's writes are applied in the order they made them.

Article 15 showed how to provide read-your-writes with replica routing.

Eventual consistency

#

If writes stop, all replicas eventually converge to the same value. Before then, reads may return stale values, and different replicas may disagree. There is no bound on how long "eventually" takes, though in practice it is usually milliseconds to seconds.

  • Example fit: like counts, view counts, follower counts, feed contents, DNS records, cached product descriptions.
  • Benefit: replicas can accept and serve requests without waiting for each other, which helps latency and availability.

Model

Promise

Typical use

Cost

Linearizable

Acts like one copy, in real-time order

Locks, uniqueness, balances, seat booking, leader election

Coordination latency; unavailable to some clients during partitions

Causal

Cause before effect, everywhere

Comments and replies, social privacy changes

Dependency tracking

Read your writes, monotonic reads

A user sees their own changes, never goes back in time

Profiles, settings, a user's own posts

Routing per session

Eventual

Copies converge if writes stop

Counters, feeds, caches, analytics

Readers can see stale or differing values

The CAP theorem, stated precisely

#

Eric Brewer proposed the idea in 2000; Seth Gilbert and Nancy Lynch proved a formal version in 2002 (Brewer's Conjecture and the Feasibility of Consistent, Available, Partition-Tolerant Web Services). In their terms:

  • C (consistency) means linearizability (they call it atomic consistency): every read sees the most recent completed write.
  • A (availability) means every request received by a non-failing node gets a non-error response, eventually.
  • P (partition tolerance) means the system keeps operating even when the network loses arbitrary messages between nodes.

The theorem: when a network partition occurs, a replicated system cannot guarantee both C and A. A node cut off from the others must either answer (and risk returning stale data or accepting a conflicting write: giving up C) or refuse or wait (giving up A).

A concrete partition

#
Code
   Region West                     Region East   Replica W  ---- link cut ----   Replica E   client: "book seat C14"         client: "book seat C14"
  • Choose consistency (CP behaviour): the side that cannot reach a majority refuses the booking ("please try again"). No double booking, but some users get errors.
  • Choose availability (AP behaviour): both sides accept their booking. Everyone gets an answer, and after the link heals you discover two bookings for one seat, which must be resolved somehow.

The myths

#

Myth

What is accurate

"Pick any two of three."

Partitions are not optional in a distributed system; networks do fail. The real choice is between C and A during a partition. Brewer himself wrote that the "2 of 3" formulation was always misleading because it oversimplified the tensions (CAP Twelve Years Later).

"Our system is CP" or "AP", as a fixed label.

The choice can be made per operation, and per kind of failure. A system can refuse writes that need uniqueness while still serving reads of cached data.

"When there is no partition, we still give something up."

Not according to CAP. Brewer notes that because partitions are rare, there is little reason to forfeit C or A when the system is not partitioned. The trade-off you do face is latency (PACELC, below).

"AP means no consistency."

AP systems usually offer eventual consistency and often session guarantees; they converge after the partition heals.

"Availability in CAP means 99.99% uptime."

CAP's availability is a strong, specific property (every non-failing node answers). Practical availability, measured in nines, depends on much more.

Brewer's article also recommends treating partitions explicitly: detect them, enter a mode that limits risky operations, and recover by reconciling afterwards.

PACELC: the trade-off you face every day

#

Daniel Abadi pointed out that CAP says nothing about normal operation, yet the most important trade-off is present all the time (Consistency Tradeoffs in Modern Distributed Database System Design):

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

Keeping replicas strongly consistent means waiting for other replicas (often in other zones or regions) before answering. That costs latency on every request, not only during rare partitions. Many systems that relax consistency do so to be fast, not because partitions are common.

Examples from earlier articles:

  • Synchronous replication across regions added about 150 ms to every write (article 15): EC, paying latency.
  • Asynchronous read replicas answer fast but may be stale: EL.

Quorums

#

In leaderless or quorum-based replication (article 15), each piece of data lives on N replicas. A write is considered successful when W replicas acknowledge it; a read asks R replicas and takes the newest version among the answers.

If W + R > N, every set of W replicas overlaps every set of R replicas in at least one node, so every read contacts at least one replica that has the latest acknowledged write. The program below checks this by brute force for N = 3, and also shows how many replicas can be down while writes and reads still succeed.

Java
// File: QuorumDemo.javaimport java.util.ArrayList;import java.util.List;public class QuorumDemo {    // Every subset of n replicas with exactly k members, as bit masks.    static List<Integer> subsets(int n, int k) {        List<Integer> out = new ArrayList<>();        for (int mask = 0; mask < (1 << n); mask++) {            if (Integer.bitCount(mask) == k) {                out.add(mask);            }        }        return out;    }    // True if every possible write set shares at least one replica with every possible read set.    static boolean alwaysOverlap(int n, int w, int r) {        for (int writeSet : subsets(n, w)) {            for (int readSet : subsets(n, r)) {                if ((writeSet & readSet) == 0) {                    return false;                }            }        }        return true;    }    public static void main(String[] args) {        int n = 3;        System.out.println("N = " + n + " replicas");        for (int w = 1; w <= n; w++) {            for (int r = 1; r <= n; r++) {                System.out.printf("W=%d R=%d  overlap guaranteed: %-5s  writes survive %d down, reads survive %d down%n",                        w, r, alwaysOverlap(n, w, r), n - w, n - r);            }        }    }}
Code
N = 3 replicasW=1 R=1  overlap guaranteed: false  writes survive 2 down, reads survive 2 downW=1 R=2  overlap guaranteed: false  writes survive 2 down, reads survive 1 downW=1 R=3  overlap guaranteed: true   writes survive 2 down, reads survive 0 downW=2 R=1  overlap guaranteed: false  writes survive 1 down, reads survive 2 downW=2 R=2  overlap guaranteed: true   writes survive 1 down, reads survive 1 downW=2 R=3  overlap guaranteed: true   writes survive 1 down, reads survive 0 downW=3 R=1  overlap guaranteed: true   writes survive 0 down, reads survive 2 downW=3 R=2  overlap guaranteed: true   writes survive 0 down, reads survive 1 downW=3 R=3  overlap guaranteed: true   writes survive 0 down, reads survive 0 down

Read the table as a menu of trade-offs:

  • W=2, R=2 (a common choice for N=3): reads and writes overlap, and both keep working with one replica down.
  • W=1, R=1: fastest and most available, but a read may miss the latest write: eventual consistency.
  • W=3, R=1: fast reads that always overlap, but a single replica failure blocks all writes.
  • W=1, R=3: fast, very available writes, but any replica failure blocks reads that need the overlap.

What quorums do not guarantee

#

Overlap is necessary for reading the latest write, but not sufficient for linearizability. Concurrent writes may be ordered differently on different replicas; a write that reached only some replicas before failing can be seen by some readers and not others; and if conflicts are resolved by "latest timestamp", clock skew (article 18) can choose the wrong winner. Systems add mechanisms such as read repair, versioning and, for linearizable operations, consensus (article 22). Amazon's Dynamo paper also describes sloppy quorums with hinted handoff: when the usual replicas are unreachable, writes go temporarily to other nodes and are handed back later, which favours availability over strict overlap (Dynamo).

Resolving conflicts

#

If replicas accept writes independently (AP behaviour, multi-leader replication, or W=1), two replicas can end up with different versions. Options:

Strategy

How

Risk

Last write wins (LWW)

Keep the version with the latest timestamp

Silently discards concurrent writes; clock skew picks wrong winners

Version vectors plus application merge

Detect concurrent versions; the application merges them

Merge logic per data type; can be complex

Merge-friendly data types (CRDTs)

Counters, sets and other structures that merge automatically and deterministically

Only some data fits; deletions need care

Avoid conflicts by design

Route all writes for an item to one place (a single leader or home region per user)

Less availability for that item during partitions

Amazon's Dynamo paper describes the shopping-cart example: when concurrent versions of a cart appear, they are merged so that added items are never lost, accepting that a deleted item can occasionally reappear (Dynamo). That is a business decision about which mistake is cheaper.

Choosing consistency per feature

#

The practical skill is not "is the system CP or AP?" but "what does each operation need?"

Feature

Model needed

Why

Typical implementation

Account balance before a debit

Linearizable

Overdrafts and double spends cost money

Single primary with transactions (article 14)

Seat booking, coupon redemption, unique usernames

Linearizable for the decision

Two winners is a real-world failure

Conditional writes or unique constraints on one primary

A user's own profile and posts after editing

Read your writes

Users think edits were lost

Primary reads for a short window (article 15)

Chat messages within a conversation

Ordered per conversation (causal within it)

Replies must follow messages

Per-conversation sequence numbers (article 34)

Like and view counts

Eventual

Off by a few for seconds harms no one

Async counters, caches

Feed contents

Eventual

A few seconds' delay is acceptable

Precomputed feeds (article 35)

Search results

Eventual

Index lags writes slightly

Event-fed search engine

Leader election, distributed locks

Linearizable

Two leaders cause corruption

Consensus systems (article 22)

Worked example: Pixly across two regions

#

Suppose Pixly expands to serve users in India and Europe, with a deployment in each region.

  • User accounts and usernames: must be unique globally. Writes go to one home region (a single primary); signups from Europe pay the cross-region latency on that one rare operation. During a partition, signups in the cut-off region fail with a friendly error (CP for this operation).
  • Photos and captions: each photo is owned by its uploader's home region; replicated asynchronously to the other region for fast reads there. Readers abroad may see a new photo a second late (eventual), and uploaders always read their own from their home region (read your writes).
  • Likes: counted in each region and merged as counters (merge-friendly; a CRDT-style counter). Totals converge after a partition (AP for this operation).
  • Feeds: built per region from replicated events; eventual.

Asked "is Pixly CP or AP?", the right answer is: "Different operations make different choices: usernames and anything involving money are CP; likes, feeds and photo replication are AP with session guarantees for users' own data."

Failure modes

#

Failure

What users see

Mitigation

Stale replica read after a write

"My change disappeared"

Read-your-writes routing

Reads bouncing between replicas

Data appears and disappears

Monotonic reads (sticky replica)

LWW with skewed clocks

A newer edit silently lost

Versions and explicit conflict handling

Misconfigured quorum (W + R not > N)

Intermittent stale reads

Review settings per operation

Partition with AP writes on both sides

Conflicting data after healing

Merge strategy, or CP for that operation

Partition with CP behaviour

Errors for users on the minority side

Clear error handling and retries; limit CP to operations that need it

Trade-offs

#

Choice

You gain

You pay

Linearizable

Simple reasoning, no anomalies

Latency; unavailability for some clients during partitions

Eventual

Low latency, high availability

Stale reads, conflicts to resolve

Session guarantees

Users never see their own changes vanish

Routing complexity

Larger W

Durability and overlap

Slower writes; less write availability

Larger R

Fresher reads

Slower reads; less read availability

Common mistakes

#
  • Reciting "pick two" and labelling the whole system CP or AP.
  • Assuming CAP forces a sacrifice when there is no partition.
  • Forgetting the latency cost of strong consistency (PACELC).
  • Believing W + R > N alone gives linearizability.
  • Using last-write-wins for data where losing a write matters.
  • Strong consistency everywhere "to be safe", paying latency for counters and feeds.

In an interview

#
  • Define terms before using them: "by strong consistency I mean linearizable for this operation".
  • Choose per feature, with a reason tied to the cost of a wrong answer.
  • If you use quorums, give N, W and R and what they tolerate.
  • If asked about CAP, state it precisely: during a partition, choose between consistency and availability for each operation; otherwise the trade-off is latency.

Exercises

#

Exercise 1

Choose the model

#

Choose the weakest consistency model that is acceptable, and say why:

  1. Displaying the number of people currently watching a live stream.
  2. Ensuring two people cannot register the same email address.
  3. Showing a user the playlist they just edited.
  4. A group chat where replies must appear after the messages they answer.
  5. A global configuration flag that turns off a buggy feature.

Exercise 2: Quorum choices

#

A key-value store has N = 5 replicas. For each goal, choose W and R and state how many replica failures writes and reads can tolerate:

  1. Reads always overlap the latest write; tolerate 2 failures for both reads and writes.
  2. Very fast, highly available writes; reads should still overlap.
  3. Lowest possible latency for both; staleness is acceptable.

Exercise 3: Critique the statement

#

A candidate says: "We chose MongoDB because it is CP, so our system is strongly consistent and we don't need to think about stale reads." Explain what is wrong or incomplete.

Exercise 4: The partition

#

An inventory service runs in two data centres, each with a replica, and accepts orders in both. The link between them fails for 10 minutes during a sale. Describe what happens under (a) a CP design and (b) an AP design, and propose a design that sells as much as possible without overselling.

Show solutionHide solution
  1. Eventual. An approximate, slightly delayed count is fine.
  2. Linearizable for the uniqueness check (in practice, a unique constraint on one primary). Two accounts with one email is a real failure.
  3. Read your writes. The editor must see their change; others can see it a moment later.
  4. Causal (at least per conversation ordering). Replies must follow their parents; unrelated messages in other chats need no ordering.
  5. Eventual, with fast propagation, is usually acceptable (a few seconds for every server to pick it up), but make sure it does converge quickly and is monitored. If the bug is causing serious harm, prefer a mechanism that pushes the change to all servers promptly and verify that it took effect.

Exercise 2

Show solutionHide solution

Overlap requires W + R > 5, so W + R >= 6.

  1. W = 3, R = 3: overlap (6 > 5); writes and reads each tolerate 5 - 3 = 2 failures.
  2. W = 2, R = 4: writes need only 2 acknowledgements (tolerate 3 failures) and are fast; reads need 4 (tolerate 1 failure) to overlap. Alternatively W = 1, R = 5, which makes reads fragile (no failures tolerated).
  3. W = 1, R = 1: fastest and most available (tolerate 4 failures each), with no overlap guarantee: eventual consistency.

Exercise 3

Show solutionHide solution
  • "CP" is not a property of a product. Behaviour depends on configuration and on each operation: which read preference is used (primary or secondaries), which write concern, which read concern, and what happens during failover.
  • Reads from secondaries can be stale if the application is configured to use them, and even primary reads during a failover can see rollbacks of unreplicated writes, depending on settings.
  • Stale reads are not the only concern: concurrent updates still need conditional writes or transactions (article 14), and data shared across services is not covered by one database's guarantees at all.
  • Thinking is still required: the candidate should state, per operation, what guarantee is needed and which settings provide it.

Exercise 4

Show solutionHide solution

(a) CP: only the side holding the authoritative copy (or a majority) accepts orders; the other side refuses or queues them. No overselling, but users on the cut-off side get errors for 10 minutes during a sale.

(b) AP: both sides keep selling from their own view of the stock. Total sales can exceed stock; after the link heals you must cancel some orders and apologise.

Better: split the stock in advance. Give each data centre an allocation (for example, 60% of units to the busier one, 40% to the other), each enforced locally with atomic decrements. During a partition each side sells its own allocation without coordination and can never oversell in total. When connected, the sides rebalance unsold allocation periodically. Some units may remain unsold on one side while the other sells out, which is a small, bounded cost compared with overselling or refusing everyone. This "escrow" or allocation idea is a common way to turn a global constraint into local ones.

Where to go next

#

Sources & further reading

  1. infoq.com
  2. users.ece.cmu.edu
  3. cs.umd.edu
  4. jepsen.io
  5. jepsen.io
  6. allthingsdistributed.com
  • Guide · Technology

    Start Here: Your Roadmap from Zero to Job-Ready DSA

  • Guide · Technology

    Heaps and Priority Queues

  • Guide · Career

    A LinkedIn Profile That Gets Recruiter Messages