The CAP theorem and consistency models

Your reel shows 1,024 likes while your cousin sees 1,021, yet your bank makes you wait rather than risk a wrong balance. Both are distributed systems facing the same choice. In this lesson you learn what the CAP theorem really says (and the popular myth it isn't), compare CP and AP behaviour during a network split, merge a shopping cart correctly, and see why consistency costs latency even on good days (PACELC).

Module 3 · Distributed Systems Concepts⏱ 30 minBeginner → AdvancedRuns in your browser (Python)3 real-time scenariosPartition simulator on your PC9 practice problems
1 The story

Why can likes disagree, but my bank balance can’t?

Riya posts a reel. On her phone it shows 1,024 likes; at the same moment her cousin Meera in Delhi sees 1,021 on the same reel. Neither of them cares. Five minutes later Riya pays ₹500 by UPI, and the app says “Payment pending, please don’t retry” for ten long seconds.

Riya’s phone♥ 1,024likes on her reelMeera, Delhi♥ 1,021same reel, same timedifferent numbers: nobody mindsUPI · Riya₹ 2,350balanceUPI · bank₹ 2,350must always matchdifferent numbers: unacceptablevs myphatshala.in
Riya

Sir, why can Instagram show two different numbers for my likes, but my bank won’t even let me pay until it is sure?

Arjun Sir

Because both are distributed systems, with copies of data in many places, and both face the same unavoidable choice. When the network between copies breaks, a system can either stay available and risk different answers, or stay consistent and refuse some requests.

Kabir

That’s the CAP theorem! Consistency, Availability, Partition tolerance: pick two?

Arjun Sir

That’s the popular slogan, Kabir, and it’s slightly misleading. Networks will break sometimes, so partition tolerance isn’t optional. The real choice is: when a partition happens, do you give up consistency or availability? Likes choose availability. Money chooses consistency.

Riya

And when the network is fine?

Arjun Sir

Then there is a quieter trade-off between speed and consistency, called PACELC. Today you’ll see both, merge a shopping cart after a split, and learn the ladder of consistency models from “eventual” to “strong”.

2 Definition

The CAP theorem and consistency models

Formal definition (write this in exams)

The CAP theorem (conjectured by Eric Brewer in 2000 and proved by Seth Gilbert and Nancy Lynch in 2002) states that a distributed data store cannot simultaneously guarantee Consistency (every read receives the most recent write, i.e. linearizability), Availability (every request to a non-failing node receives a response) and Partition tolerance (the system continues to operate despite lost messages between nodes). Since network partitions cannot be ruled out, a system must choose, during a partition, between consistency (CP) and availability (AP). Consistency models describe the guarantees a system gives about the order and visibility of reads and writes, from strong (linearizable) to eventual consistency.

In simple words

When copies of data are on different machines and the network between them breaks, a system has two choices: keep answering (and possibly give different answers on each side), or refuse some requests until it can be sure every answer is correct. It can’t do both. Banks refuse; social media keeps answering.

Words you’ll meet in this lesson

Network partitionA failure where some nodes can’t communicate with others, though each may still be running.
LinearizabilityThe strongest consistency: the system behaves as if there were one copy, and reads see the latest completed write.
Eventual consistencyIf no new writes happen, all copies eventually become the same.
CP systemStays consistent during a partition by refusing requests on the minority side.
AP systemStays available during a partition, allowing copies to differ for a while.
PACELCExtension of CAP: without partitions, there is still a latency vs consistency trade-off.
Causal consistencyEffects are never seen before their causes.
CRDTConflict-free replicated data type: a structure that merges concurrent updates automatically.

Where common systems sit (default settings)

CP-leaningZooKeeper, etcd, HBase, Google Spanner, MongoDB (majority read/write concern), relational databases with synchronous replicas
AP-leaningCassandra and ScyllaDB (consistency level ONE), Amazon Dynamo-style stores, Riak, CouchDB, DNS, CDN caches
Tunable per requestCassandra (ONE, QUORUM, ALL), DynamoDB (eventually or strongly consistent reads), MongoDB (read and write concerns)

CAP and consistency at three levels

Pick your level. New to this? Start at Beginner and climb.

Beginner Two bank branches and a broken phone line

Imagine one bank account managed by two branches that phone each other after every transaction. One day the phone line breaks.

  • Choose consistency: both branches refuse withdrawals until the line is fixed. No mistakes, but customers are turned away (not available).
  • Choose availability: both branches keep serving customers. Nobody is turned away, but the two branches may now disagree about the balance (not consistent), and someone could withdraw the same money twice.

Banks choose consistency for balances. Social apps choose availability for likes and views. Both are correct for their data.

Intermediate CP and AP systems, and common myths

  • C (consistency) in CAP means linearizability: every read sees the latest successful write, as if there were one copy. A (availability) means every request to a working node gets a non-error response. P (partition tolerance) means the system keeps operating when messages between nodes are lost.
  • CP examples: ZooKeeper, etcd, HBase, MongoDB with majority reads and writes, most relational databases with synchronous replication. In a partition, the minority side refuses requests.
  • AP examples: Cassandra and DynamoDB-style stores at low consistency levels, DNS, many caches. In a partition, every side answers, and copies reconcile later (eventual consistency).
  • Myth 1: “pick any two”. A distributed system can’t give up P, so “CA” really means “not distributed” (or “stops working during a partition”).
  • Myth 2: the choice is fixed for a whole system. Many databases let you choose per query (Cassandra consistency levels, DynamoDB strongly consistent reads).

Advanced PACELC, the consistency ladder and conflict resolution

  • PACELC (Daniel Abadi): if there is a Partition, choose A or C; Else, choose Latency or Consistency. Strong consistency needs coordination even on good days, which costs round trips, especially across regions.
  • Consistency ladder (strongest to weakest): linearizable (real-time order, one copy illusion) → sequential (one agreed order) → causal (cause before effect, e.g. a reply never appears before its comment) → session guarantees (read-your-writes, monotonic reads) → eventual (copies converge if writes stop).
  • Conflict resolution in AP systems: last-write-wins (simple, but silently drops concurrent updates and depends on clocks), version vectors (detect concurrent versions and keep both), and CRDTs (data types like counters and sets designed to merge automatically and correctly).
  • Global strong consistency: Google Spanner uses tightly synchronised clocks (TrueTime) and consensus to offer linearizable transactions across regions, at the cost of commit latency.
  • Design rule: decide consistency per piece of data: balances, inventory counts and seat bookings need strong guarantees; likes, views, recommendations and analytics can be eventual.

Exam tip: State the CAP theorem with all three properties defined, explain why P is unavoidable so the real choice is C or A during a partition, and give one CP and one AP example with a reason (bank balance vs social media likes). Mention eventual consistency and, for extra marks, PACELC.

3 Types and ways to use it

CP, AP and the consistency ladder

CP: consistent under partition

The side without a majority stops serving. Answers are always correct, but some users see errors. Payments, inventory, leader election, config stores.

Correct or nothing

AP: available under partition

Every side keeps serving and copies reconcile later. Users always get an answer, but it may be stale or conflict. Feeds, likes, carts, DNS.

Answer always

Tunable

The client chooses per request: fast, eventually consistent reads for a feed; strongly consistent reads for checkout.

Per query

The consistency ladder

ModelGuaranteeExample where it mattersCost
Linearizable (strong)Reads see the latest completed write, in real-time orderBank balance, seat booking, unique usernamesHighest (coordination on every operation)
SequentialEveryone sees operations in one agreed orderReplicated logsHigh
CausalCauses are seen before effectsComment threads, chat repliesMedium
Read-your-writes / monotonicYou see your own changes; reads never go backwardsProfile edits, order statusLow
EventualCopies converge when writes stopLike counts, view counts, recommendationsLowest

Don’t ask “is our system CP or AP?”; ask “for this data, what is worse during a network fault: showing an error or showing a possibly wrong answer?” The answer is usually different for balances, carts and like counts in the same app.

4 Step by step

A partition, handled two ways

  1. Three copies, then the network splits

    replicas = {"A": 100, "B": 100, "C": 100}
    groups = [{"A"}, {"B", "C"}]           # the network splits
    majority = len(replicas) // 2 + 1
    for g in groups:
        print(sorted(g), "has majority" if len(g) >= majority else "minority")
    ['A'] minority ['B', 'C'] has majority
    A network fault separates A from B and C. Every node is still running; they just can’t talk. This is a partition, and in a big cluster it is a matter of when, not if.
  2. CP: the minority refuses

    def cp_write(group, value, replicas, majority=2):
        if len(group) < majority:
            return "error: try again later"
        for n in group:
            replicas[n] = value
        return "ok"
    r = {"A": 100, "B": 100, "C": 100}
    print("via A:", cp_write({"A"}, 40, r), "| via B:", cp_write({"B", "C"}, 70, r), "|", r)
    via A: error: try again later | via B: ok | {'A': 100, 'B': 70, 'C': 70}
    Only the side with a majority may accept writes (and serve strongly consistent reads). Clients talking to A get errors, but no one ever sees two different balances.
  3. AP: both sides answer

    r = {"A": 100, "B": 100, "C": 100}
    r["A"] = 40                      # AP: A accepts a write on its side
    r["B"] = r["C"] = 70             # B accepts a different write on the other side
    print("A answers", r["A"], "| B answers", r["B"], "-> both available, inconsistent")
    A answers 40 | B answers 70 -> both available, inconsistent
    Every request succeeds, but the two sides now disagree. When the network heals, the system must reconcile the two values, and some updates may need special merging.
  4. Quorums: consistency you can tune

    N, W, R = 3, 2, 2
    print("R + W > N:", R + W > N, "-> every read overlaps the latest write")
    print("survives 1 node down for reads and writes:", N - W >= 1 and N - R >= 1)
    R + W > N: True -> every read overlaps the latest write survives 1 node down for reads and writes: True
    In leaderless stores like Cassandra, choosing W and R per query moves you along the scale: W = R = 1 is fast and AP-like; R + W > N gives strongly consistent reads while still tolerating one failed node.
  5. When the network is fine: latency vs consistency

    Even without failures, a strongly consistent write must wait for a majority to confirm. If replicas are in Mumbai, Singapore and Frankfurt, that wait is one long network round trip.

    This is the “ELC” in PACELC: else, choose latency or consistency. Many systems keep strongly consistent data in one region and replicate asynchronously elsewhere.
  6. Decide per piece of data

    In one food-delivery app: wallet balance → strong; restaurant stock of a limited dish → strong; cart → eventual with merge; ratings and view counts → eventual.

    Good designs mix models. The skill is matching each kind of data to the weakest guarantee that is still correct for the business.
5 See it happen

Likes and a payment: what Riya sees, and what the copies do

Step through the six frames. Left: Riya’s reel likes and a UPI payment. Right: copies in three regions, eventually consistent for likes and strongly consistent for money.

What Riya sees, and what the copies do 6 steps
What you see Riya’s reel♥ 1,024she taps like: instantMeera · Delhi♥ 1,021a few likes behindEveryone♥ 1,025same number for allUPIPay ₹500 toKirana StorePAYUPIPayment pendingplease don’t retryUPIPaid ₹500balance ₹1,850, correct myphatshala.in
Behind the screen Likes: AP, eventually consistentMumbai♥ 1,024Delhi♥ 1,021Chennai♥ 1,021The like is written locally and replicated later.Delhi is a few likes behindMumbai♥ 1,024Delhi♥ 1,021Chennai♥ 1,021Stale by a second or two. No harm done.Copies convergeMumbai♥ 1,025Delhi♥ 1,025Chennai♥ 1,025When updates settle, every copy agrees: eventual consistency.Balance: CP, strongly consistentMumbai₹2,350Delhi₹2,350Chennai₹2,350A debit must be agreed by a majority before it counts.Link to Mumbai breaks mid-paymentMumbai₹2,350Delhi₹2,350Chennai₹2,350Mumbai (minority) refuses to confirm alone: “pending”.Majority confirms the debit onceMumbai₹1,850Delhi₹1,850Chennai₹1,850Exactly one debit, the same balance everywhere. myphatshala.in
6 Real-world use

Real-time scenarios: choosing consistency

Three live scenarios: the same network split handled by a CP and an AP design (real numbers), a shopping cart merged after a split, and an advanced look at the latency cost of consistency across regions.

Real-time scenario 1

One network split, two designs

A three-node cluster loses its network link to node A. Watch a CP bank balance and an AP like counter react to exactly the same failure. (These are the numbers from the program in “Run it on your PC”.)

CP vs AP during a partition 5 steps
Animated example Node ARs 100Node BRs 100Node CRs 100Network splits: {A} | {B, C}Same failure, two designs. First: a CP bank balance.Node ArefusesNode BRs 70Node CRs 70CP: A has no majority → refusesB and C (2 of 3) accept a debit to Rs 70.Users routed to A get an error. Nobody sees a wrong balance.Node A♥ 1,003Node B♥ 1,005Node C♥ 1,005AP like counter: both sides accept3 likes arrive at A, 5 at B. Everyone gets a response,but A says 1,003 and B says 1,005.Node A♥ 1,003Node B♥ 1,005Node C♥ 1,005Network heals: how to merge?Last-write-wins would keep 1,005: A’s 3 likes vanish.Silent data loss.Node A♥ 1,008Node B♥ 1,008Node C♥ 1,008CRDT counter: add both sides’ increments1,000 + 3 + 5 = 1,008. Every like kept.AP done right needs data types that merge safely. myphatshala.in
Real-time scenario 2

Merging a shopping cart after a split

Shopping carts are a classic AP example: it is better to always accept “add to cart” than to show an error during a sale. Watch what merging two diverged carts really involves.

AP merge done right 5 steps
Animated example Replica 1• thaliReplica 2• thaliRiya’s cart, copied on two replicasCarts are AP: adding an item must never fail.Replica 1• thali• lassiReplica 2• thali• gulab jamunPartition: phone and laptop hit different replicasShe adds lassi on her phone and gulab jamun on her laptop.Both writes succeed on different replicas.Merged cart• thali• lassi• gulab jamunHealed: merge = union of both cartsUnion keeps every addition. Nothing she added is lost.Merged cart• thali• lassi• gulab jamunBut: she had removed lassi on one sideA plain union brings deleted items back (“zombie” items).Amazon’s Dynamo paper describes exactly this.Merged cart• thali• gulab jamunFix: track adds and removes separatelyAn OR-Set CRDT records each add and remove with an id,so a remove beats the add it saw. The cart merges correctly. myphatshala.in
Real-time scenario 3 · advanced

PACELC: consistency costs time even on good days

CAP talks only about partitions. But most of the time the network is fine, and there is still a trade-off: every strongly consistent write must wait for other replicas. Watch the latency of one write with replicas in three regions.

Latency vs consistency 5 steps
Animated example MumbaiSingaporeFrankfurtThree replicas in three regionsround trip Mumbai–Singapore ≈ 60 ms · Mumbai–Frankfurt ≈ 120 msNo partition today. Every link works.What does consistency cost?write latency (illustrative)async (local only)≈ 2 msAsync: confirm after the local write.Fastest, but other regions may lag (and lose data in a crash).write latency (illustrative)async (local only)≈ 2 msmajority (2 of 3)≈ 60 msStrong: wait for a majority. Mumbai + Singaporemust agree: one long round trip on every write.write latency (illustrative)async (local only)≈ 2 msmajority (2 of 3)≈ 60 msall 3 replicas≈ 120 msWaiting for all three adds Frankfurt’s distanceand fails if any one region is down.write latency (illustrative)wallet: majority≈ 60 mslikes: async≈ 2 mscart: local + merge≈ 2 msPACELC choice per data: pay latency only wherecorrectness truly needs it. myphatshala.in

Consistency choices in real products

₹ ledger

1. Payments and wallets: strong consistency

UPI and wallet systems treat balances as strongly consistent: a debit is confirmed only once, and during uncertainty the payment stays “pending” and is later settled or reversed rather than guessed.

Debit request→Majority / transaction→One true balance
♥1.2k

2. Social counters and feeds: eventual

Likes, views and follower counts are counted on many servers and merged in the background. Showing 1,021 instead of 1,024 for a second is a fine trade for never failing a tap.

Tap ♥→Local write, async merge→Converges
seat 14B

3. Ticket and seat booking: strong for the seat

Train, flight and cinema booking must never sell one seat twice, so the final seat assignment is strongly consistent, even though seat-availability views shown while browsing may be slightly stale.

Browse (stale OK)→Lock / confirm seat→One owner
etcd

4. Cluster coordination: CP stores

Kubernetes stores cluster state in etcd and Kafka uses KRaft (formerly ZooKeeper): small CP stores based on consensus, where being correct about “who is leader” matters more than answering during a split.

Leader election→Raft consensus→Exactly one leader
7 Run the code

A network partition, handled CP and AP

Three replicas are split into {A} and {B, C}. In CP mode only the majority side accepts writes; in AP mode both sides accept and the values diverge. Run it, then try the challenges: quorum checks, read-your-writes, last-write-wins vs a CRDT counter, a cart merge and a PACELC latency estimate.

replicas = ["A", "B", "C"]
sides = [{"A"}, {"B", "C"}]
majority = len(replicas) // 2 + 1

def side_of(node):
    return next(s for s in sides if node in s)

def write(mode, node, value, store):
    side = side_of(node)
    if mode == "CP" and len(side) < majority:
        return "refused (minority side)"
    for n in side:
        store[n] = value
    return "accepted"

for mode in ["CP", "AP"]:
    store = {n: 100 for n in replicas}
    r1 = write(mode, "A", 40, store)
    r2 = write(mode, "B", 70, store)
    print(f"{mode}: via A {r1:24} via B {r2:9} -> {store}")
CP: via A refused (minority side) via B accepted -> {'A': 100, 'B': 70, 'C': 70} AP: via A accepted via B accepted -> {'A': 40, 'B': 70, 'C': 70}
  • majority = len(replicas) // 2 + 1With 3 replicas a majority is 2. Only a side with at least 2 nodes may make decisions in CP mode.
  • if mode == "CP" and len(side) < majority:CP gives up availability on the minority side: it refuses rather than risk a conflicting value.
  • for n in side:In AP mode each side updates its own copies, so after both writes the copies disagree.

Run it on your PC: CP, AP and merging after a split

This program splits three replicas into {A} and {B, C}. In CP mode it refuses writes on the minority side; in AP mode it lets both sides count likes, then merges them two ways: last-write-wins, which loses likes, and a CRDT counter, which keeps them all. Save it as cap_sim.py and run it.

CAP choices and conflict resolution

"""Three replicas, then a network partition splits them {A} | {B, C}.
CP mode: only the side with a majority accepts writes.
AP mode: both sides accept writes, then merge when the network heals.
We merge a like-counter two ways: last-write-wins (loses likes) and a CRDT counter (keeps all)."""

REPLICAS = ["A", "B", "C"]
partition = [{"A"}, {"B", "C"}]


def side_of(node):
    return next(s for s in partition if node in s)


def cp_write(node, value, store):
    side = side_of(node)
    if len(side) > len(REPLICAS) // 2:
        for n in side:
            store[n] = value
        return "accepted"
    return "REFUSED (no majority on this side)"


print("CP mode (choose consistency):")
store = {n: 100 for n in REPLICAS}          # balance Rs 100 everywhere
print("  write via A:", cp_write("A", 40, store))
print("  write via B:", cp_write("B", 70, store))
print("  majority side (B, C) now holds:", store["B"], "| A must refuse reads and writes until the network heals")

print("\nAP mode (choose availability): a like counter")
likes = {"A": 1000, "B": 1000, "C": 1000}
# during the partition: 3 likes arrive at A, 5 likes at B
likes["A"] += 3
likes["B"] += 5
likes["C"] = likes["B"]                      # C is on B's side and syncs with it
print("  during partition:", likes, "-> different answers, but every request succeeded")

# merge 1: last-write-wins (keep the value written last, say B's)
lww = likes["B"]
print("  last-write-wins after healing:", lww, "(A's 3 likes are lost)")

# merge 2: a G-counter CRDT keeps a separate count per replica and adds them
increments = {"A": 3, "B": 5}
crdt = 1000 + sum(increments.values())
print("  CRDT counter after healing   :", crdt, "(every like kept)")

# In a terminal:  python cap_sim.py
CP mode (choose consistency): write via A: REFUSED (no majority on this side) write via B: accepted majority side (B, C) now holds: 70 | A must refuse reads and writes until the network heals AP mode (choose availability): a like counter during partition: {'A': 1003, 'B': 1005, 'C': 1005} -> different answers, but every request succeeded last-write-wins after healing: 1005 (A's 3 likes are lost) CRDT counter after healing : 1008 (every like kept)

Recorded from a real run with Python 3.13; the simulation is deterministic. These are the numbers used in scenario 1. Try moving node C to A's side of the partition: which side can accept writes in CP mode now?

8 Line by line

Merging a G-counter, one line at a time

A G-counter (a CRDT) keeps one count per replica. Two replicas counted likes independently; merging takes the maximum for each replica's slot, then the total is the sum. Watch nothing get lost.

Worked examples: real problems, solved and traced in memory

Four consistency problems, from classifying data to merging concurrent updates. Each runs live and is traced.

Example 1BeginnerSystem design · classification

CP or AP for each kind of data?

Problem statement

Decide CP or AP for each piece of data using one question: during a network fault, is a wrong answer worse than an error?

Input
wallet balance, like count, seat booking, product reviews, leader election
Expected output
wallet balance   -> CP (refuse when unsure)
like count       -> AP (answer, reconcile later)
seat booking     -> CP (refuse when unsure)
product reviews  -> AP (answer, reconcile later)
leader election  -> CP (refuse when unsure)

Approach

  1. For each item, record whether a wrong answer is worse than an error.
  2. Wrong answer worse → CP. Error worse → AP.
  3. Print the decisions.

Solution: run it live

What happens in memory, step by step

Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.

Example 2IntermediateDistributed DB · quorums

Check consistency levels for a Cassandra cluster

Problem statement

A table has replication factor 3. For each (write level, read level) pair, decide whether reads always see the latest write and how many replica failures each operation tolerates.

Input
levels ONE = 1, QUORUM = 2, ALL = 3
Expected output
write ONE    read ONE   : consistent=False, write tolerates 2, read tolerates 2
write QUORUM read QUORUM: consistent=True, write tolerates 1, read tolerates 1
write ALL    read ONE   : consistent=True, write tolerates 0, read tolerates 2
write ONE    read QUORUM: consistent=False, write tolerates 2, read tolerates 1

Approach

  1. Map level names to numbers of replicas.
  2. Consistent if R + W > N.
  3. An operation tolerates N − level failed replicas.

Solution: run it live

What happens in memory, step by step

Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.

Example 3IntermediateConflicts · last-write-wins

How last-write-wins loses updates

Problem statement

Two replicas accept updates to the same field during a partition, each with a timestamp. Merge with last-write-wins and list the updates that were silently discarded.

Input
A: address=Baner at 10:05 · B: address=Wakad at 10:03, phone=98xx at 10:04
Expected output
merged: {'address': 'Baner', 'phone': '98xx'}
lost  : [('B', 'address', 'Wakad', '10:03')]

Approach

  1. Collect every update with its key and timestamp.
  2. For each key keep only the update with the latest timestamp.
  3. Updates not kept were lost.

Solution: run it live

What happens in memory, step by step

Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.

Example 4AdvancedCRDTs · counters

A PN-counter: likes and unlikes that merge correctly

Problem statement

Users can like and unlike. Each replica keeps separate increment (P) and decrement (N) counts per replica. Merge two diverged replicas and compute the true like count.

Input
replica A: +4 −1 · replica B: +6 −2 · both start from the same state
Expected output
merged: {'P': {'A': 4, 'B': 6}, 'N': {'A': 1, 'B': 2}}
likes: 7

Approach

  1. Keep P and N dictionaries with one slot per replica.
  2. Merge by taking the maximum of each slot from both copies.
  3. Value = sum(P) − sum(N).

Solution: run it live

What happens in memory, step by step

Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.

9 Quiz and revision

Check yourself

Quick revision

Lesson 3.4 in one screen

  • CAP: with a network partition, choose consistency (refuse some requests) or availability (answer, maybe stale). P is unavoidable.
  • CP examples: ZooKeeper, etcd, HBase, Spanner, majority-configured MongoDB. AP examples: Cassandra/Dynamo at low levels, DNS, caches.
  • “Pick any two” is a myth; many databases are tunable per query (R + W > N for strong reads).
  • PACELC: else (no partition) choose latency or consistency.
  • Ladder: linearizable → sequential → causal → read-your-writes/monotonic → eventual.
  • AP conflicts: last-write-wins (loses data), version vectors, CRDTs (counters, OR-Sets merge safely).
  • Choose per data: balances, seats and stock strong; likes, views and carts eventual.

Interview and viva questions

State and explain the CAP theorem.

The CAP theorem states that a distributed data store cannot simultaneously provide consistency (every read sees the most recent write), availability (every request to a non-failing node gets a response) and partition tolerance (the system keeps working when network messages between nodes are lost). Because partitions cannot be prevented in a distributed system, the practical meaning is that during a partition the system must sacrifice either consistency (CP: refuse some requests) or availability (AP: answer but possibly return stale or conflicting data).

Give examples of CP and AP systems.

CP: ZooKeeper, etcd and Consul (consensus-based coordination), HBase, Google Spanner, MongoDB with majority read and write concerns, relational databases with synchronous replication. AP: Cassandra and ScyllaDB at low consistency levels, Dynamo-style key-value stores, Riak, CouchDB, DNS and CDN caches. Many systems are tunable, so the classification depends on configuration.

What is eventual consistency?

A consistency model in which, if no new updates are made, all replicas eventually converge to the same value. Reads may temporarily return stale data. It allows high availability and low latency and suits data like likes, views and recommendations, but needs rules for resolving concurrent updates.

What is PACELC?

An extension of CAP by Daniel Abadi: if there is a Partition (P), a system trades Availability (A) against Consistency (C); Else (E), when the network is healthy, it trades Latency (L) against Consistency (C). It highlights that strong consistency has a latency cost even without failures, especially with replicas far apart.

What are CRDTs?

Conflict-free replicated data types are data structures (such as grow-only counters, PN-counters, grow-only sets and observed-remove sets) designed so that replicas can be updated independently and merged in any order, any number of times, always converging to the same correct result without coordination. They make AP designs safe for counters, sets and collaborative editing.

Practice problems

Consistency and quorum exercises. The last two are business tasks.

P1Easy

Majority side

Three replicas split into sides of size 1 and 2. Print which side may accept writes in a CP system.

Input
sides [1, 2]
Expected output
['right']
Show solution and explanation
sides = {"left": 1, "right": 2}
majority = 3 // 2 + 1
print([s for s, n in sides.items() if n >= majority])
['right']

How it works: Only a side with a majority of all replicas may decide.

P2Easy

Consistent read?

N = 3, W = 1, R = 2. Print whether reads always see the latest write.

Input
3, 1, 2
Expected output
False
Show solution and explanation
N, W, R = 3, 1, 2
print(R + W > N)
False

How it works: 1 + 2 = 3 is not greater than 3, so a read could miss the write.

P3Easy

Classify data

Print “strong” for money and seats, “eventual” for everything else.

Input
balance, likes, seat, views
Expected output
balance -> strong
likes -> eventual
seat -> strong
views -> eventual
Show solution and explanation
for item in ["balance", "likes", "seat", "views"]:
    print(item, "->", "strong" if item in ("balance", "seat") else "eventual")
balance -> strong likes -> eventual seat -> strong views -> eventual

How it works: Consistency is chosen per kind of data.

P4Medium

Converged?

Given replica values after updates stop, print whether the system has converged.

Input
{A: 1008, B: 1008, C: 1005}
Expected output
not yet
Show solution and explanation
values = {"A": 1008, "B": 1008, "C": 1005}
print("converged" if len(set(values.values())) == 1 else "not yet")
not yet

How it works: Eventual consistency promises convergence only after updates stop and replication catches up.

P5Medium

G-counter merge

Merge two G-counters by taking the maximum per slot and print the total.

Input
a {A:5, B:2}, b {A:3, B:7}
Expected output
{'A': 5, 'B': 7} 12
Show solution and explanation
a, b = {"A": 5, "B": 2}, {"A": 3, "B": 7}
merged = {k: max(a[k], b[k]) for k in a}
print(merged, sum(merged.values()))
{'A': 5, 'B': 7} 12

How it works: Each slot only grows, so the maximum is always the most recent count for that replica.

P6Advanced

Monotonic reads

A user's successive reads return these versions. Print whether any read went backwards.

Input
[12, 14, 13, 15]
Expected output
went backwards at: [(14, 13)]
Show solution and explanation
versions = [12, 14, 13, 15]
backwards = [(a, b) for a, b in zip(versions, versions[1:]) if b < a]
print("went backwards at:", backwards if backwards else "never")
went backwards at: [(14, 13)]

How it works: Monotonic-read consistency forbids this; pinning a user to one replica (or tracking versions) prevents it.

P7Advanced

Latency of a quorum write

Replica round-trip times from the coordinator are given. Print the latency of writes with W = 1, 2 and 3 (the time until W replicas have confirmed).

Input
[2, 45, 110] ms
Expected output
W=1: 2 ms
W=2: 45 ms
W=3: 110 ms
Show solution and explanation
rtts = sorted([2, 45, 110])
for W in [1, 2, 3]:
    print(f"W={W}: {rtts[W - 1]} ms")
W=1: 2 ms W=2: 45 ms W=3: 110 ms

How it works: The write waits for the W-th fastest replica: stronger guarantees cost latency (PACELC).

P8Business problem

Cost of eventual vs strong

A strongly consistent write takes 60 ms, an eventual one 3 ms. A feature makes 2 lakh writes per minute and each request holds a thread for the write time. Print the average busy threads for each (Little's law).

Input
2 lakh/min, 60 ms vs 3 ms
Expected output
strong  : about 200 busy threads
eventual: about 10 busy threads
Show solution and explanation
rate_per_s = 2_00_000 / 60
for name, ms in [("strong", 60), ("eventual", 3)]:
    print(f"{name:8}: about {rate_per_s * ms / 1000:.0f} busy threads")
strong : about 200 busy threads eventual: about 10 busy threads

How it works: Consistency choices change capacity needs too: 20 times more concurrency for the strong version here.

P9Business problem

Oversell risk

A flash sale of 500 phones uses an eventually consistent stock counter with 2 seconds of lag at 300 orders per second. Roughly how many phones could be oversold?

Input
500 stock, 2 s lag, 300/s
Expected output
orders that could see stale stock near the end: 600
so up to ~ 600 phones could be oversold -> use strong consistency at checkout
Show solution and explanation
lag, rate = 2, 300
print("orders that could see stale stock near the end:", lag * rate)
print("so up to ~", lag * rate, "phones could be oversold -> use strong consistency at checkout")
orders that could see stale stock near the end: 600 so up to ~ 600 phones could be oversold -> use strong consistency at checkout

How it works: For limited stock, a stale view is fine for browsing, but the final reservation must be strongly consistent.

Real-world scenario questions (asked in company interviews)

Consistency questions from interviews and real designs. Decide your answer first, then open the model answer.

System design · consistencyFresher

Which parts of a food app need strong consistency?

For a food-delivery app, decide the consistency level for: wallet balance, cart, restaurant ratings, “only 5 left” limited-dish stock, and order status shown to the customer.

The interviewer is checking: can you choose consistency per piece of data with reasons?

Show a strong answer
  • Wallet: strong (never double-spend).
  • Limited stock: strong at checkout (never oversell); browsing can show a slightly stale count.
  • Cart: eventual/available, with a correct merge.
  • Ratings: eventual.
  • Order status: read-your-writes and monotonic reads per user (status never goes backwards), not necessarily global linearizability.

Avoid: labelling the whole app “CP” or “AP”.

Distributed DB · Cassandra1–3 years

Users sometimes see old profile data

A Cassandra cluster with replication factor 3 uses consistency level ONE for reads and writes. Users occasionally see their old profile after updating it.

The interviewer is checking: do you understand tunable consistency and its trade-offs?

Show a strong answer

With W = 1 and R = 1, R + W = 2 is not greater than N = 3, so a read can hit a replica that hasn’t received the write. Use QUORUM for both (2 + 2 > 3) on profile reads and writes, accepting slightly higher latency, or LOCAL_QUORUM in multi-datacentre setups. Keep ONE for data where staleness is harmless. Make sure clocks are synchronised, since Cassandra resolves conflicts by timestamp (last-write-wins).

Avoid: switching everything to ALL, which fails whenever any replica is down.

Architecture · multi-region3+ years

Go active-active in two regions?

Leadership wants the app to accept writes in both Mumbai and Hyderabad at the same time, so a regional outage causes no downtime.

The interviewer is checking: do you see the consistency consequences of multi-leader designs?

Show a strong answer

Active-active means concurrent writes to the same data in both regions, so conflicts are certain during network issues. For each entity decide: can it be partitioned by region (each user’s data has a home region), can it merge automatically (counters, sets via CRDTs), or must it be strongly consistent (wallet, inventory), which then needs a single leader or consensus with cross-region latency on every write. Often the answer is active-active for most data plus a single-region leader for money, with fast failover.

Avoid: promising zero downtime and strong consistency everywhere without discussing the latency or conflicts.

Fundamentals · interviewFresher

“Explain the CAP theorem”

The classic question. Many candidates answer “pick any two of three”.

The interviewer is checking: can you explain it precisely and correct the myth?

Show a strong answer

In a distributed system, when a network partition happens, you must choose between consistency (every read returns the latest write) and availability (every request gets a non-error response). Partitions can’t be prevented, so partition tolerance is required, and “CA” only applies to non-distributed systems. Example: a bank ledger chooses consistency and refuses some requests during a partition; a like counter chooses availability and reconciles later. Without partitions, PACELC adds a latency vs consistency trade-off, and many databases let you tune consistency per query.

Avoid: saying “Cassandra is AP, MongoDB is CP, done” without explaining what is traded and when.