πŸ“š Study Notes / Home / HLD / Session 7
Session 07 Β· CAP & Replication

The Storage Layer β€” CAP, PACELC & Replication

So far our system has been mostly one box doing the thinking. But the moment you have more users than one database can handle β€” or you can't afford to ever lose their data β€” you need more than one copy of the data, living on more than one machine. The instant you do that, a whole family of deep, unavoidable questions appears: which copy is "right"? what happens when the copies disagree? Today we'll meet the famous theorems (CAP and PACELC) that explain the trade-offs every distributed database must make, and the two big tools β€” replication and sharding β€” for actually building one. We assume you've studied none of this; every topic starts with a tiny story.

⏱ 39 min readπŸ“– 8 topics

1 Why one database isn't enough


Explain like I'm 5

Imagine the whole class shares one notebook to write down everyone's lunch order. At first that's fine. But then the notebook gets full (too much to write), or a hundred kids want to scribble in it at the same time (a huge line forms), or someone spills juice on it and it's ruined forever. So the teacher says: "Let's keep several notebooks, in different rooms." Now nobody waits in one giant line, and if one notebook is ruined we still have the others. But a brand-new problem appears: if I write "pizza" in the Room A notebook, the Room B notebook still says "salad." Which one is correct? That puzzle is what today is all about.

Everything we've built in earlier sessions β€” the load balancers, the application servers from Session 6 β€” eventually has to read and write data that outlives a single request: user accounts, messages, orders. That permanent home for data is the storage layer, usually a database. For a while, a single powerful database server handles it all. But a single server hits three hard walls.

The big idea: what "distributed" even means

The CAP and PACELC theorems tell us what is possible and what is not possible when we talk about distributed systems. A system is distributed the moment it has more than one server, connected via some network. Everything today only matters once you cross that line.

The three walls of a single database

WallWhat goes wrongIn plain English
CapacityThe dataset grows bigger than one machine's disk or memory.The notebook is full.
ThroughputToo many reads/writes per second for one machine's CPU and disk.Too many kids want to write at once.
Durability & availabilityIf that one machine dies (disk failure, power cut), all your data and service are gone.Juice spilled β€” notebook ruined, and the whole class is stuck.

The fix for all three is the same big move: use more than one machine. We call each machine a node. A database spread across many nodes is a distributed database, and the whole collection working together is a cluster. There are two fundamentally different ways to spread data across nodes, and they solve different walls:

  • Make copies of the same data on several nodes β€” called replication. This mainly helps the durability/availability and read throughput walls (Topic 8).
  • Split the data into pieces, each piece on a different node β€” called sharding (or partitioning). This mainly helps the capacity and write throughput walls (Topic 8).
The big idea

The moment your data lives on more than one node, those nodes must talk over a network β€” and networks are unreliable. Messages get delayed or lost; a cable gets cut. So the copies can temporarily disagree. Every distributed database is, at its core, a set of carefully chosen answers to one question: "When my nodes disagree, what do I do?"

Recap One database hits walls of capacity, throughput, and durability, so we spread data across many nodes in a cluster β€” by copying (replication) or splitting (sharding). Distributed just means more than one server connected via a network. Multiple copies mean copies can disagree over an unreliable network, which is the entire reason CAP and PACELC exist.

2 Consistency & the kinds of consistency


Explain like I'm 5

If there is only one jar of cookies, you always know exactly how many are left β€” you put cookies in and take them out of the same jar. But if you keep two jars and try to keep them matching, one jar can fall behind: you ate a cookie from jar A, but jar B still "thinks" it's there. "Consistency" is just the question of whether the jars agree. With one jar, the question doesn't even make sense β€” there's nothing to disagree with.

When can we even talk about consistency?

Consistency is always about data. A few consequences fall straight out of that:

  • Stateless app servers cannot be consistent or inconsistent β€” they're stateless, they hold no data, so there's nothing to be in or out of sync. Asking "is this app server consistent?" is like asking "at how many km/hr is your door cooking the colour 9?" or the classic IIT ragging question, "what's the colour of an electron?" β€” the answer is simply undefined. The question doesn't apply.
  • Consistency is typically discussed in the context of a database or a cache.
  • There must be multiple copies of the same data (replication / caching). If there's only one copy, it's guaranteed up to date β€” you read and write the same place. The only way data goes stale is having multiple copies (database + cache, or database replicas).
  • There must be a read after a write/update. If the data is static/immutable, there's no way to read stale data β€” it's never updated.
Example: the leaderboard after a contest

After a contest ends, no new submissions arrive, so the leaderboard is always up to date. We don't say "the leaderboard is consistent" β€” we say consistency is no longer relevant, because the data has become immutable.

Two terms: state & stale reads

State = some data we wish to preserve across multiple requests. So state == data. A stale read happens when an old value of data is read after an update. Stale reads can (not always) lead to bad user experience. If a stale read is possible, it means we do not have immediate consistency.

The kinds of consistency (a spectrum)

Immediate consistency (aka "Consistent")

  • It is impossible for stale reads to happen β€” every read is guaranteed to read the latest data.
  • Only possible when all the copies are always kept in sync, all the time (or you use a quorum).
  • Always nice to have, but very hard to achieve β€” typically requires 2-phase commit, which means high latency and low availability. Because it's so costly, we do not always go with immediate consistency.

Eventual consistency (aka "Not Consistent")

  • It is possible for some reads to be stale for some time. But if we wait long enough, eventually we'll be able to read the updated data.
  • In 99% of cases, eventual consistency is good enough.
The subtle wording everyone gets wrong

Eventual consistency does not mean "eventually the data will become consistent (latest)." It means every write will eventually reflect in all copies.

  • "Eventually the data will be consistent" β€” WRONG. That would imply a future point in time after which the data always stays consistent. Not true: new writes keep arriving.
  • "Eventually every write will reflect in all copies" β€” CORRECT. Wait long enough and what you wrote earlier shows up everywhere. The data can still be stale, because newer writes are continuously coming in.

Data loss β€” no consistency whatsoever

  • If it's possible for some data to be permanently lost, then there are updates that will never reflect β€” no matter how long we wait, the data never becomes consistent.
  • Very rare. Only relevant for analytics, where the overall trend matters more than any individual data point.
Q: Are there more forms of consistency?

Yes β€” but they all fall inside the umbrella of eventual consistency. A famous one is read-your-write consistency: if Ashish edits his post, he immediately sees the update, but his friends might not see it right away (they get it eventually). There are still more forms beyond this.

Concrete example: the disagreeing copies

You change your profile photo. The write hits Node A and it says "done." A friend in another region reads from Node B, which hasn't received the update yet, and still sees your old photo β€” a stale read.

  • Under immediate consistency, the system wouldn't have said "done" until Node B (and others) also had the new photo β€” so your friend always sees the new one. (More waiting for you.)
  • Under eventual consistency, your friend sees the old photo for maybe a second, then it catches up. (Faster, but briefly "wrong.")
A related term: replica lag

The short delay before a copy catches up is called replication lag. Usually milliseconds, but it's never exactly zero β€” light and network packets take time to travel. That's the physical reason "immediate consistency everywhere, instantly" is essentially impossible across distant machines.

Recap Consistency is always about data and only meaningful with multiple copies + a read after a write. The spectrum: immediate (no stale reads ever, but costly β€” 2-phase commit), eventual (briefly stale, every write eventually reflects in all copies β€” good enough 99% of the time), and data loss (some updates never reflect β€” only OK for analytics). Read-your-write and friends live under the eventual umbrella.

3 Availability


Explain like I'm 5

Availability is just: "will the shop serve you when you ask?" If a healthy shop with stock turns you away for no good reason, that's bad (low availability). But if you asked for something silly, or the shopkeeper happened to be out for a second and you can just ask again, that doesn't count against the shop.

Availability refers to whether a server can deny a request or not. If a server can deny a request, the system is "not available" / has low availability. If a server always satisfies the request, the system is "available" / has high availability. But the details matter β€” two classic interview questions:

Q1: A bad request comes in and the server denies it β€” low availability?

Think 4xx (bad request) or 3xx (auth) errors. When the user is at fault, the server is allowed to deny the request β€” it must still respond, but with the appropriate error message. No, this is NOT low availability. We still call the system highly available.

Q2: A request comes in but the server crashes and doesn't respond β€” low availability?

Again, NOT low availability. The request times out, the client just retries, and the load balancer routes the next request to a healthy server.

What low availability actually is

Low availability is when a healthy request comes to a healthy server, but the server still refuses to provide the service for some internal reason β€” most often because it can't sync up with other replicas. Examples:

  • Internal server error (bad code, or unable to access a critical resource).
  • Some specific reason the server wants to deny service.
  • The request times out because the server is busy (not because it's down).
The numbers: "five nines"

At 99.999% availability, a service can have a maximum downtime of about 5.26 minutes per year.

Recap Availability = "does a server deny requests?" A 4xx/3xx on a bad request is not low availability (the user was at fault, but the server still responded). A crash is not low availability (retry + LB handles it). True low availability = a healthy server denies a healthy request, usually because it can't sync with replicas. 99.999% ("five nines") allows ~5.26 min downtime/year.

4 Partition tolerance & the bank (A vs P)


Explain like I'm 5

Imagine two friends who normally text to keep their notes matching. One day their phones can't reach each other β€” that's a partition. A system is "partition tolerant" if it keeps working at least partially even while they can't talk, instead of the whole thing shutting down.

What is partition tolerance?

A system is partition tolerant if it can continue functioning seamlessly in the face of network partitions. When a partition happens, if the system continues working at least partially (some availability might be lost, some consistency might be lost, but the entire system doesn't go down), it's partition tolerant. If any loss of communication between nodes brings the whole system down, it's not partition tolerant. Partition tolerance is very highly desired.

What is a network partition?

In a network of servers (a distributed system), if some subset of servers cannot communicate with the other subset, we have a network partition.

A slow network is a broken network

The connection doesn't have to physically break for a partition to happen. A slow / congested network behaves like a broken one, because requests time out.

Q: How likely is a network partition? β€” 100%

In large-scale distributed systems (Google has 10 million+ servers), network partitions are not just likely, they ALWAYS exist. Some subset is always disconnected β€” some node or link is always down, creating a small partition somewhere. 100% probability. There is always a partition somewhere.

Availability vs Partition tolerance β€” the bank/ATM story

Tarun wants to withdraw money from his bank account via the ATM. In the backend, the bank replicates the account information β€” we don't want to lose account data if a server/hard disk crashes. When Tarun withdraws, the bank must update both copies to reflect the new balance. Now imagine a network partition happens and the two bank database servers can't communicate. Two cases arise:

Case AP β€” highly available, low consistency (partition tolerant)

The bank returns success without updating both servers β€” it updates the balance in just one server and gives Tarun his money. This gives eventual consistency (stale reads possible, but once the network is back the DB servers sync up) and high availability. The data was inconsistent, but the system stayed available through the partition.

Case CP β€” consistent without availability (partition tolerant)

The bank database detects it can't reach its replica and denies service. This is low availability (a healthy request to a healthy server got denied!), but we got immediate consistency β€” no stale read was possible.

Note: the withdraw money functionality is down, but check balance is still up. So the system as a whole did not crash β€” it is still partition tolerant. There was low availability for "money withdrawal," but the system didn't crash.

When is a system NOT partition tolerant?

When any network partition brings down the entire system. This is very, very rare β€” about 99.99% of backend systems are designed to be partition tolerant.

The exception: stock exchanges

Stock exchanges (NSE / BSE / SSE / NYSE) are A+C systems β€” they do not have partition tolerance. If two servers inside the exchange can't communicate, the entire exchange shuts down until it's resolved. So they do a lot of engineering to minimise the chance of a partition: each pair of servers is connected by multiple redundant fiber connections.

Why real banks are actually A+P (and earn from it)

In reality the ATM system and most banks follow A+P (eventual consistency), because banks have found a way to "earn" from their own mistakes. If, due to a partition, Tarun redeems more money than he has, eventually the partition resolves, both DBs reconcile, and an automatic audit realises he withdrew twice. Tarun's balance is now negative β€” the bank charges him an overdraft fee plus interest on the β‚Ή100 he effectively borrowed.

This is also why refunds take 5–7 business days even though payment happens immediately. (Typically the refund actually happens immediately β€” but in the worst case it can take a long time, because of eventual consistency.)

Recap A system is partition tolerant if it keeps working at least partially during a network partition (a subset of nodes can't talk β€” and a slow network counts). In big systems a partition always exists (100%). During the bank partition you must choose AP (give the money, sync later β€” eventual consistency) or CP (deny the withdrawal, stay correct β€” low availability, but check-balance still works so it's still partition tolerant). Non-partition-tolerant systems (stock exchanges, A+C) are rare and avoid partitions by brute-force redundant fiber.

5 The CAP theorem


Explain like I'm 5

You and your sibling each have a copy of the family shopping list, and you keep them the same by texting each other. One day the phone network goes down between you β€” you literally can't text. Now your sibling walks into the store and asks: "Should I add milk?" You have only two choices. (1) Say "wait!" until the phones work again, so you don't both buy milk β€” that's safe but you got stuck waiting. Or (2) just decide on your own and sort out any double-buy later β€” that's you keep going, but your lists might disagree for a bit. When the connection is broken, you simply cannot have both "always agree" AND "never wait." CAP is the grown-up name for that exact dilemma.

When do the theorems even apply?

CAP / PACELC apply only when you have replication β€” multiple copies of the same data, distributed across multiple servers, connected by a network. No replication, no theorem.

The CAP theorem (proposed by Eric Brewer in 2000, later proven) is the most famous rule about distributed data stores. It gives you a fundamental limit of what you can achieve with distributed systems: a system can offer at most two of these three guarantees at the same time:

LetterNamePromise it makes
CConsistencyEvery read sees the most recent write (or an error). All nodes agree on the data β€” as if there were one single copy.
AAvailabilityEvery request gets a (non-error) response, even if it might not be the very latest data. The system always answers.
PPartition toleranceThe system keeps working even when the network between nodes drops or delays messages (a network partition).
Does Google Spanner break CAP?

Google Spanner seems to violate CAP β€” they claim to provide all three. They don't actually violate it (and don't claim to). They do some black magic with timestamps (TrueTime) to practically achieve all three.

The three categories of system (with real percentages)

A+P systems β€” high availability + eventual consistency (~99%)

Even during a partial failure (network partition), the system keeps serving users' requests. AP systems give up on consistency β€” they're eventually consistent. 99% of all systems are AP, because mostly we do not care about immediate consistency. Example: social media (Twitter / Facebook / Instagram). If a user keeps seeing an old post, or a new post doesn't appear in a friend's feed immediately, it's not the end of the world β€” as long as it updates eventually.

C+P systems β€” immediate consistency + low availability (~0.9%)

Only if there's no partition can the system serve users. The moment a partition happens, it may deny requests (lose availability). Rare β€” only 0.9%, used when data is critical. Candidate examples: financial transactions & banks (though these are often actually eventually consistent), stock brokers (Zerodha), ticket booking (BookMyShow) / product purchase (don't oversell inventory).

Even IRCTC makes ticket booking eventually consistent β€” they offer RAC tickets that get resolved later ("eventually"). CP is rare because in most cases we're OK with eventual consistency; immediate consistency is always nice but rarely strictly needed.

A+C systems β€” immediate consistency + high availability, but no partition tolerance (~0.1%)

Never denies a request and always stays consistent β€” as long as there's no partition. The moment a partition happens, the entire system crashes. Extremely rare β€” only 0.1%. Example: stock exchanges (NSE, NYSE, SSE, BSE). A+C systems are typically not geographically distributed because they can't afford partitions: very powerful servers, all in the same building, connected with high-speed fiber, multiple redundant connections. The chance of a partition is close to 0 (by design, extremely expensive). Still, if one happens, the whole system must shut down.

CAP β€” two ways to state it

1️⃣
Definition 1
Pick any 2 of C, A, P
β†’
2️⃣
Definition 2
When there's a partition, choose A or C β€” you can't have both

1st definition: pick any 2. 2nd definition (the better one): when there's a network partition, you must choose between Availability or Consistency β€” you cannot have both. As long as there's no partition, you don't have to worry. The moment one happens, you choose C or A, not both.

The most misunderstood part of CAP

People say "pick 2 of 3" as if you freely choose any pair. But because in large systems there's always a partition somewhere, you definitely want partition tolerance. So effectively your real choice is between A+P and C+P β€” "during a Partition, choose Consistency or Availability."

🟒
Normal
A & B sync; C, A and P all fine
β†’
βœ‚οΈ
Partition!
Network between A & B breaks
β†’
πŸ›‘οΈ
CP choice
Refuse/wait β†’ stay correct, lose availability
β†’
⚑
AP choice
Keep answering β†’ stay up, allow stale data

Why you can't have all three during a partition

Picture two nodes, A and B, that normally sync. The network breaks β€” the partition. A write arrives at A. Node A faces an impossible choice:

  • Accept the write (stay Available) β†’ but B doesn't know about it, so a read from B is stale β†’ you gave up Consistency.
  • Refuse the write / make it wait until it can reach B (stay Consistent) β†’ but now A isn't answering β†’ you gave up Availability.

There's no third option while the cable is cut. That's the theorem in one breath.

Worked example: a bank vs a social feed

Bank (wants CP). The network between two data centres glitches. You try to withdraw $100. A CP system would rather fail your request ("please try again") than risk letting you and your partner both withdraw the last $100 from two sides of the partition and end up overdrawn. Correctness beats uptime.

Twitter/X-style feed (wants AP). The same glitch happens; you post a tweet. An AP system accepts it immediately. A friend on the other side might not see it for a few seconds. That's fine β€” a slightly late tweet beats a site that says "down."

CP/AP and modern databases

By how they behave during a partition: CP examples include MongoDB (default config), HBase, Zookeeper, etcd, traditional RDBMS clusters; AP examples include Apache Cassandra, Amazon DynamoDB, Riak, CouchDB. The textbook "CA" category really just describes a single non-distributed node β€” once you have multiple nodes over a network, partitions are inevitable, so the meaningful choice is CP vs AP.

Key takeaway

CAP isn't a menu where you tick two boxes for fun. Partitions are a fact of nature, so the engineering decision is: when the network splits, would my product rather be correct (CP) or online (AP)? The answer comes from the business, not from the database.

Recap CAP applies only with replication. It says keep at most 2 of C/A/P β€” or, better stated, during a partition choose A or C. Since partitions always exist, the real choice is A+P (~99%, e.g. social media, eventual consistency) vs C+P (~0.9%, e.g. Zerodha/BookMyShow, immediate consistency, low availability); A+C (~0.1%, e.g. stock exchanges) drops partition tolerance entirely. Google Spanner "fakes" all three with TrueTime timestamps.

6 The PACELC theorem


Explain like I'm 5

CAP only talks about what happens when the phones are broken. But here's the thing: most days, the phones work just fine β€” and you still have a choice to make! Every time your sibling wants to add something to the list, do you (1) wait to text everyone and make sure all the copies match before saying "ok" β€” safe but slow? Or (2) just write it down right away and text the others a moment later β€” fast but the lists briefly differ? PACELC is the smarter rule that says: "Tell me your choice when the phones are broken, AND ALSO your choice on a normal day when they work."

CAP has a blind spot: it only describes behaviour during a partition β€” a rare event. But a distributed database makes a consistency-vs-speed trade-off on every single request, all the time, even when the network is perfectly healthy. The PACELC theorem (Daniel Abadi, 2010) is an extension to CAP that fills that gap. Read it as a sentence:

The PACELC sentence

When there's a Partition, choose between Availability (serve potentially stale data) OR Consistency (service down, but data stays consistent). Else (even with no partition) there's a trade-off between Latency (low latency because sync-up happens later) OR Consistency (sync up right away, but higher latency).

In symbols: if (P) then (A or C) else (L or C).

The deeper point: consistency is expensive

Just like in DSA we trade Time Complexity vs Space Complexity, in HLD we trade Consistency vs Availability and Consistency vs Latency. Basically: if you choose immediate consistency, you give up on both Availability and Latency. An always-consistent system will be slow (high latency) and might deny requests (low availability). So immediate consistency comes at a huge cost.

The first half (P β†’ A/C) is just CAP. The new, important half is the "ELC": latency (how long a request takes) is traded against consistency even when everything is healthy. To be strongly consistent, a node must wait to confirm the other copies agree before answering β€” and waiting is latency.

Why PACELC is "more complete" than CAP

CAP describes the exceptional moment (a partition). PACELC also describes the normal 99.9% of the time. Since latency directly drives user experience and cost every day, the "Else" branch often matters more in practice than the rare partition branch. PACELC = CAP + the everyday trade-off CAP forgot.

The four PACELC personalities

Each system gets a two-part label: its partition choice (PA or PC) and its normal-time choice (EL or EC).

LabelDuring partitionNormal timeExample systems
PA/ELStay available (allow stale)Favour low latency (allow stale)Cassandra, DynamoDB, Riak β€” "fast and always up; consistency is best-effort."
PC/ECStay consistent (may reject)Favour consistency (accept higher latency)HBase, BigTable, VoltDB β€” "always correct, even if slower or briefly down."
PC/ELStay consistent during partitionBut favour latency when healthyMongoDB (typical config), PNUTS β€” "strict when it matters most, fast on a normal day."
PA/ECStay available during partitionBut favour consistency when healthyRarer; some tunable configs. Up during outages, careful when calm.
Worked example: Cassandra (PA/EL) vs a strict store (PC/EC)

Two requests arrive on a perfectly healthy network (no partition β€” the "Else" branch).

Cassandra (PA/EL). You write a value. By default it can reply "ok" as soon as one (or a quorum of) replica acknowledges, without waiting for all copies. Response is super fast (low Latency), but a read a millisecond later from a not-yet-updated replica might be stale. It chose L over C.

A PC/EC store like HBase. The same write waits until the system can guarantee subsequent reads see it. The reply comes back a little slower, but any later read is correct. It chose C over L.

Notice: no partition was involved. CAP can't even describe this difference β€” but PACELC's "ELC" half captures it precisely.

Tunable consistency β€” the modern reality

Many systems (Cassandra, DynamoDB) let you pick the trade-off per request using a quorum: roughly, "how many of the N copies must reply before I answer." Wait for more copies = more consistent but slower; wait for fewer = faster but riskier. So a single database can behave like different PACELC labels depending on the knob β€” which is why these theorems are guides, not rigid boxes.

Recap PACELC = if (P) then (A or C) else (L or C) β€” an extension of CAP. The first half restates CAP (partition β†’ A vs C); the second, new half says that even on a healthy network you trade latency against consistency on every request. Immediate consistency therefore costs you both availability and latency (like Time vs Space in DSA). Labels like Cassandra's PA/EL vs HBase's PC/EC capture both branches.

7 Proof by story β€” Aditi's Reminder Service


Explain like I'm 5

Two people answer phone calls and write reminders in their own diaries. Everything you learned today β€” scaling, consistency, availability, partitions, CAP, PACELC β€” shows up naturally as their little business grows. Watch what choices they're forced to make.

Scaling up, then out

  • Vertical scaling (scaling up): at first Aditi runs the reminder service alongside her day job; as requests grow, she quits and does it full time.
  • Horizontal scaling (scaling out): she can't handle all the calls alone, so she hires Sanjana.
Q: One shared diary, or two independent diaries?

Single diary β†’ Aditi & Sanjana must be in the same room (colocated, not distributed), and they'll fight over the diary β€” it becomes a bottleneck. Two diaries β†’ they can be far apart (Sanjana works from home) and the diary isn't a bottleneck. So they go with two diaries; a single diary would render the scaling useless.

The angry customer (a consistency issue)

Customer: "Yesterday I called to remind me of my 11am flight. Then I called at 8am to ask my flight time and you said you don't remember. You lost my data and I missed my flight." Why? The write went to Sanjana, but the read came to Aditi, and Aditi's data was not in sync with Sanjana's. A consistency issue.

Protocol 1 β€” sync eventually (at night)

They copy each other's data each night before closing, so in the morning both have the same copy.

PROTOCOL 1 β€” Sync eventually (at night)

on WRITE(data):
    write data to MY diary only
    return SUCCESS                # fast: write in one place

every NIGHT (before closing):
    copy MY diary  -> OTHER diary
    copy OTHER diary -> MY diary  # both diaries now match

Q: Can there still be stale reads / angry calls? Yes β€” until the nightly sync, any read before the sync can be stale. But wait long enough and the data syncs (eventual consistency). Data can be stale (low consistency), but a write only touches one place (low latency).

Protocol 1 = Low Consistency + Low Latency

Protocol 2 β€” sync immediately

Whenever one gets a call, they write to their own diary, put the customer on hold, call the other person, get them to write it too, and only return success when the other confirms. If the other returns an error, roll back (delete from own diary) and return error.

PROTOCOL 2 β€” Sync immediately (synchronous replication)

on WRITE(data):
    write data to MY diary
    put customer ON HOLD
    call OTHER person, ask them to write data
    if OTHER responds SUCCESS:
        return SUCCESS
    else:                         # OTHER returned error
        delete data from MY diary  # ROLLBACK
        return ERROR

on READ(query):
    answer from MY diary directly   # no waiting β€” both have all data

This gives immediate consistency β€” data is always in sync because every write goes to both diaries. But latency is higher (the client waits on hold while Aditi calls Sanjana), and throughput suffers β€” every call is now effectively made twice (to both Aditi and Sanjana), which undercuts the horizontal scaling we did.

Q: Does Protocol 2 apply to reads too? No β€” only writes. On a read, Aditi and Sanjana each respond independently from their own diary (both have all the data). So no waiting on reads (low latency for reads).

Protocol 2 = High Consistency + High Latency
Q: How does Google Docs handle this?

It gives eventual consistency β€” you can make changes even while offline, and they sync up once your network is restored β€” by performing conflict resolution later. The powerful (but complex) general technique is Conflict-Free Replicated Data Types (CRDTs). Google Docs doesn't actually use CRDTs; it uses a custom protocol that is slightly weaker than (but similar to) CRDTs.

Vacation time (a server is down β€” but no partition)

Sanjana goes on vacation. No availability issue β€” calls just route to Aditi. No network partition β€” Sanjana is simply on leave. When she returns, she syncs with Aditi's diary before taking calls β€” no consistency issue. This holds for both protocols: since Sanjana is absent, Aditi keeps writing to her own diary (even in Protocol 2), and Sanjana syncs up on return. So no availability and no consistency issue β€” because there's no partition; it's just that a server (Sanjana) is down.

The big fight (a real network partition)

Aditi & Sanjana have a big fight and refuse to talk β€” a network partition.

Protocol 1 during the fight

No worries β€” both keep taking calls and writing in their own diaries. Eventually the fight resolves (network heals) and they sync. Data stays stale until then, but the service stays available.

Partition β‡’ High Availability + Eventual Consistency (AP).

Protocol 2 during the fight

The protocol requires writing to both places, but Aditi isn't talking to Sanjana. So on a write call she must deny. She can still serve read requests from her own diary, but writes are denied until the fight resolves.

Partition β‡’ Immediate Consistency + Low Availability (CP). Note only writes are unavailable β€” reads continue β€” but overall we say the system has low availability.

Recap The diary story reproduces the whole theory: two diaries = horizontal scaling; out-of-sync diaries = consistency issues. Protocol 1 (sync at night) = low consistency + low latency, and under partition gives AP (high availability + eventual consistency). Protocol 2 (sync immediately) = high consistency + high latency (and lower throughput), and under partition gives CP (immediate consistency + low availability). A server merely being down (vacation) is not a partition. Google Docs picks eventual consistency via conflict resolution (CRDT-like).

8 Replication vs Sharding


Explain like I'm 5

Two different ways to handle "too much for one notebook." Replication is like photocopying the same notebook so every room has an identical copy β€” if one is ruined you still have the data, and lots of kids can read at the same time from different copies. Sharding is like tearing the address book by letter: names A–H in one notebook, I–P in the next, Q–Z in the last β€” now no single notebook is full, and three kids can write at once because they're using different books. Copies = safety and fast reading. Splitting = more room and fast writing. Real systems do both.

Replication means explicitly, by choice, having multiple copies of the same data, stored on different servers. These are the two foundational techniques for scaling the storage layer, and they are not the same thing β€” confusing them is a classic beginner trap.

Isn't replication bad? (the normalization angle)

In RDBMS we study normalization, which says redundancy (duplicate data) is bad because it leads to anomalies (read / write / delete). Consider an un-normalized table:

CourseStudent
HLDTarun
HLDSanjana
LLDHarini
DBMSSanjana
  • Update anomaly: rename HLD β†’ "High Level Design" but miss a row β†’ the two rows now disagree, effectively creating an extra course.
  • Delete anomaly: delete Sanjana and you accidentally delete the course DBMS (she was its only entry).

The normalized design removes these anomalies by splitting into separate tables:

Course IDCourse Name
1HLD
2LLD
3DBMS
Student IDStudent Name
1Sanjana
2Tarun
3Harini
Student IDCourse ID
11
13
21
32
So why deliberately replicate?

Normalization fights accidental redundancy within one DB. Replication is deliberate, useful redundancy across servers β€” a completely different goal: protecting against data loss.

Why do we need replication? Durability β‰  replication

Replication is the ONLY protection against data loss

The "D" in ACID stands for durability: any committed transaction is persisted to disk, so after a power failure and restart it's still there. But ACID durability is only about persistent vs volatile memory β€” it does NOT protect you from HDD failures. The only way to prevent data loss when a hard disk dies is replication: multiple copies of the same data across multiple disks.

Replicate across servers, not within one

There's no point replicating data within the same server (useless redundancy) β€” you waste disk space and still lose everything if the server crashes. Always replicate across multiple servers (useful redundancy).

Replication vs Sharding β€” the core distinction

AspectReplicationSharding
What it doesMultiple copies of the same data across servers.Partition data horizontally across servers.
One wordCopyingSplitting
Servers holdDifferent servers (replicas) hold the same data.Different servers (shards) hold different data.
Each node holdsThe whole dataset.One slice of the dataset.
If a node diesFine β€” another copy has the data.That slice is unavailable (unless that shard is also replicated).
AnalogyPhotocopying the whole notebook.Tearing the address book A–H, I–P, Q–Z.

Pros & cons

ReplicationSharding
Pros Minimises chance of data loss (resilience). Only read throughput improves β€” you can read from any copy, spreading read load across replicas. Store more data than one server's capacity (scaling out). Both read & write throughput increase β€” load is distributed across shards.
Cons Increases data size β†’ capacity decreases (3Γ— replication β‡’ ~3Γ— less effective storage). Worsens write throughput (extra writes, even if done in the background). Must keep replicas in sync (consistency troubles). Complex. Requires consistent hashing for routing. Risk of fan-out queries (joins/transactions across shards).
Q: Which should we use? β€” Both, together!

You have more data than one server can handle, and you don't want to lose data. So large systems run sharding and replication at the same time: shard the data for capacity & write throughput, then replicate each shard for durability & read throughput. E.g. 4 shards, each with 3 copies β†’ 12 nodes total.

πŸ—„οΈ
Shard 1
Leader + 2 followers
+
πŸ—„οΈ
Shard 2
Leader + 2 followers
+
πŸ—„οΈ
Shard 3
Leader + 2 followers
=
πŸ›οΈ
Cluster
Scales reads, writes, capacity & survives failures

How replication works (leader–follower)

The most common pattern is leader–follower (master–slave / primary–replica): one leader accepts all writes and streams changes to several read-only followers. We go deep on this β€” sync vs async, failover, lag β€” in Session 8.

✍️
Write
Goes to the leader
β†’
πŸ‘‘
Leader
Stores it, streams changes out
β†’
πŸ“„
Followers
Copy 1, Copy 2, Copy 3 β€” identical data
β†’
πŸ‘€
Reads
Spread across all the copies

How sharding works (the shard key)

The rule that decides which row goes to which shard is the shard key (partition key). Range-based splits by key ranges (A–H, I–P, Q–Z) β€” easy range scans but risks hot spots. Hash-based hashes the key β€” even load, but range scans become hard.

Worked example: sharding users by ID with a hash

Say we have 4 shards (nodes 0–3) and route each user by hashing their ID:

# pick which shard a user lives on
def shard_for(user_id, num_shards=4):
    return hash(user_id) % num_shards   # 0, 1, 2, or 3

shard_for("alice")   # -> 2  (alice's row lives on node 2)
shard_for("bob")     # -> 0  (bob's row lives on node 0)
shard_for("carol")   # -> 1

A write for "alice" goes only to node 2; a write for "bob" only to node 0 β€” they happen at the same time on different machines. That parallelism is how sharding scales writes. The trade-off: "list all users alphabetically" must now visit every shard and merge β€” a fan-out query.

The hidden cost of % num_shards

Plain hash(key) % N looks neat, but if you ever add a shard (N: 4 β†’ 5), almost every key remaps to a different node β€” a massive reshuffle. Real systems use consistent hashing, which moves only a small fraction of keys when a node is added/removed.

What about caching? Caching is kind-of like replication

In caching, your data lives in 2 places: the database and the cache. So it resembles replication β€” but it's not pure replication.

Cache vs replication
  • Does NOT save you from data loss β€” caches are volatile (store data in RAM).
  • Improves read throughput (good).
  • Worsens write latency & throughput (bad) β€” every write must also touch the cache.
Key takeaway

Replication = copying (same data, many copies β†’ safety + read scale). Sharding = splitting (different data, many pieces β†’ capacity + read & write scale). They're orthogonal β€” use both. And the moment you replicate, the consistency questions from CAP and PACELC come right back, because now you have copies that can disagree.

Recap Replication = copying same data across servers (read-throughput + resilience, but worse write throughput and 3Γ— the storage); sharding = splitting data horizontally (capacity + read & write throughput, but needs consistent hashing and risks fan-out queries). Normalization fights accidental redundancy; replication is deliberate redundancy and the only defence against HDD-failure data loss (ACID durability only covers volatile vs persistent memory). Always replicate across servers; use sharding + replication together. Caching is replication-like but volatile (no data-loss protection). Session 8 dives into leader–follower replication.

β˜… Putting it all together


Today we left the comfort of a single machine and entered the world of distributed storage. Here's the one-paragraph story tying all the topics together:

A single database eventually hits walls of capacity, throughput, and durability, so we spread data across many nodes. The instant we have multiple copies talking over an unreliable network, those copies can disagree β€” consistency (always about data) ranges from immediate (no stale reads, but needs 2-phase commit) to eventual (every write reflects eventually β€” good 99% of the time) to data loss. Meanwhile availability is about a healthy server denying a healthy request (a 4xx or a crash doesn't count), and a network partition (a slow network counts!) always exists somewhere in big systems. The CAP theorem: during a partition you keep only two of C/A/P, so you really choose CP (~0.9%, stay correct β€” Zerodha, BookMyShow) or AP (~99%, stay online β€” social media), while A+C (~0.1%, stock exchanges) abandons partition tolerance. PACELC completes it: Else (no partition) you still trade latency vs consistency on every request β€” immediate consistency costs you both availability and latency. Aditi & Sanjana's diaries make it concrete (Protocol 1 = AP/low-latency, Protocol 2 = CP/high-latency). The build tools are replication (copies β†’ safety + read scale, the only defence against HDD data loss) and sharding (splits β†’ capacity + write scale), usually combined. Replication is exactly where these trade-offs bite, which is why Session 8 zooms into master–slave replication.

Quick self-check

Why can't a stateless app server be "consistent" or "inconsistent"?

Consistency is always about data, and stateless servers hold no data β€” there's nothing to be in or out of sync. The question is undefined, like asking the colour of an electron.

"Eventually the data will be consistent" β€” right or wrong?

Wrong. That implies a future point after which data stays consistent forever. The correct statement is "every write will eventually reflect in all copies" β€” data can still be stale because new writes keep arriving.

A server returns a 4xx on a bad request. Is that low availability?

No. The user was at fault and the server still responded (with an error). Low availability is when a healthy server denies a healthy request β€” usually because it can't sync with its replicas.

How likely is a network partition in a system with millions of servers?

100% β€” there is always some subset disconnected somewhere. That's why partition tolerance is effectively mandatory and the real choice is AP vs CP.

In CAP, why is "partition tolerance" not really optional for a real distributed system?

Because networks genuinely fail (and a slow/congested network behaves like a broken one). You can't choose to never have a partition, so P is effectively mandatory; the real decision is whether, during a partition, you sacrifice C (become CP) or A (become AP).

A bank's core ledger should lean toward CP or AP, and why?

CP for correctness β€” better to reject/delay than allow a double-withdrawal. In practice many real banks actually run A+P and reconcile later via auditing (overdraft fee + interest), which is also why refunds can take 5–7 business days.

What does PACELC add that CAP misses?

The "ELC" half: even with no partition (normal operation), the system still trades latency against consistency on every request. Immediate consistency costs both availability and latency.

In Aditi's story, which protocol gives AP and which gives CP during a partition?

Protocol 1 (sync at night) β†’ AP: both keep serving, data is eventually consistent. Protocol 2 (sync immediately) β†’ CP: writes are denied during the fight (low availability) but data stays immediately consistent.

Cassandra is often labelled PA/EL. Decode that label.

During a Partition it favours Availability (stays up, allows stale data); Else, on a healthy network, it favours low Latency (answers fast, again allowing some staleness).

You're running out of disk space because the dataset is too big for one machine. Replication or sharding?

Sharding. Replication copies the whole dataset onto each node, so it doesn't help capacity. Sharding splits the data so 10 nodes hold ~10Γ— the data.

ACID durability protects you from a hard-disk failure. True or false?

False. Durability only guarantees committed data survives in persistent (vs volatile) memory across restarts. The only protection against HDD failure is replication across multiple servers/disks.

Why doesn't a single leader–follower replication setup scale write throughput?

All writes funnel through the one leader; followers are read-only. To scale writes you need sharding, so different nodes accept writes for different slices in parallel.

πŸ“š References & Further Reading


Class material

Papers, docs & deep dives