1 Masterβslave (leaderβfollower) replication
Imagine one teacher with the master notebook. Whenever something new happens, only the teacher is allowed to write it in. But thirty kids each have their own copy of the notebook, and the teacher keeps reading the new lines aloud so every kid can copy them down. If you just want to read something, you ask any nearby kid β fast, no queue. But if you want to add something new, you must go to the one teacher. One writer, many readers.
That teacher is the master (modern docs say leader or primary). The kids are the slaves (modern term: followers, replicas, or secondaries). We'll use "master/slave" because that's still the most common interview phrasing, but know the kinder, clearer words too β they mean the same thing.
The words "master" and "slave" carry a lot of historical baggage, and many communities deliberately avoid them. You'll see the exact same relationship described as LeaderβFollower, ActiveβPassive, or PrimaryβSecondary. They are all the same pattern: one node that owns writes, others that mirror it.
In masterβslave replication there is exactly one node that accepts writes (the master), and one or more read-only copies (the slaves) that constantly try to mirror it. All changes flow in one direction: master β slaves. This single rule is what makes the whole thing simple to reason about.
Why copy data at all? (recall Session 7)
In Session 7 we said replication buys us three things. Masterβslave gives all three:
- Read scaling β the headline benefit today. Most apps read far more than they write (think: 100 page-views per 1 comment posted). Spread reads across many slaves and you serve more traffic.
- High availability β if the master dies, a slave can be promoted to take over (Topic 3).
- Geography & backups β keep a slave in another data centre for disaster recovery, or one nearby your users for low-latency reads.
How a write propagates
When the master accepts a write, it doesn't just change its own data and forget about it. It records the change in an ordered log and ships that log to every slave. The log has different names in different systems but the same job:
| System | Name of the replication log |
|---|---|
| MySQL | binary log (binlog) |
| PostgreSQL | Write-Ahead Log (WAL) |
| MongoDB | oplog (operations log) |
The key word is ordered: every slave applies the changes in the same sequence the master did. Apply them out of order and the copies would disagree. So a slave is really just a machine replaying the master's diary, line by line, forever.
There are two flavours of what the log actually contains. Statement-based ships the SQL
command itself (UPDATE accounts SET balance = balance - 10 ...). It's compact but
dangerous: a command like NOW() or RAND() would produce
different results on each replica! Row-based ships the actual changed rows ("row 42's
balance is now 90"), which is bigger but deterministic. Most modern systems prefer row-based for safety.
The topology, drawn out
Your app talks to the cluster through a layer that decides where each query goes. Writes go to the one master; reads fan out to the slaves:
Read/write splitting β how reads actually scale
The trick that scales reads is read/write splitting: the application (or a proxy
in front of the database) sends every INSERT/UPDATE/DELETE
to the master, and load-balances every SELECT across the pool of slaves.
A tiny router that routes by query type. The reads round-robin across three replicas; writes always hit the master:
# db_router.py β toy read/write splitter master = connect("db-master:5432") replicas = [connect("db-replica-1:5432"), connect("db-replica-2:5432"), connect("db-replica-3:5432")] def run(sql): if sql.strip().upper().startswith(("INSERT", "UPDATE", "DELETE")): return master.execute(sql) # writes β the one master else: replica = random.choice(replicas) # reads β spread across slaves return replica.execute(sql)
Now imagine the master can handle 5,000 reads/sec on its own. Add three equally-powered replicas and your read capacity jumps to roughly 20,000/sec (master + 3 slaves), while writes stay capped at the single master's 5,000/sec. That asymmetry is the whole point: reads scale horizontally, writes do not.
The slaves are always slightly behind the master β they're replaying a log that arrives a beat late. So a read from a slave might return data that's a few milliseconds (or, on a bad day, seconds) out of date. That gap is called replication lag, and it's the headache we tackle next.
Masterβslave works brilliantly for read-heavy workloads. It does nothing for write-heavy ones β there's still only one master taking writes. When writes themselves become the bottleneck, you need sharding (splitting data across many masters), which is the headline topic of Session 9.
2 Basic setup & the replication factor
How many copies of the class notebook should exist? If there's only one, and it gets lost, the notes are gone forever β useless. So you keep a few copies. And you usually keep an odd number of kids (plus the teacher) in the room, because when they have to vote on something β like "who's the new teacher?" β an odd number means there's never a tie. There's always a clear winner.
The replication factor, written X, is the
number of total copies of the same data:
X = 1 master + (Xβ1) slaves. So X = 3 means 1 master + 2 slaves; X = 5 means 1 master + 4 slaves; X = 2 means 1 master + 1 slave. Typical values are X = 3 or X = 5.
X is the number of copies, not the number of machines in your whole database. If the database is
sharded, you have shards and replicas. A database can have
S = 100 shards, each shard keeping X = 3 copies, for a
total of N = 300 servers. (Sharding is Session 9 β here we focus on one shard's
copies.)
Why an odd number of servers?
Typically we use an odd number of total servers (the master plus an even number of slaves). This is not mandatory β you can have an even number β but odd gives you a clear majority, which makes tie-breaking trivial when the cluster has to vote (during master election, or during a quorum read/write). With an even number, a split vote can deadlock.
How many copies do you actually need?
- At least X = 2 (1 master + 1 slave). With only 1 copy there's no replication at all, so any disk failure means data loss.
- X = 3 is the typical default (1 master + 2 slaves).
- X = 5 for critical data where you cannot tolerate any data loss. Going above 5 buys almost nothing β it's already astronomically unlikely that 5 servers in the same shard fail at once.
- Very high X (e.g. 100) only when you're using replicas purely to scale read throughput. This is normally done for a cache, not the whole database, and it's usually fine for such a cache to be eventually consistent.
If you had 100 read replicas and demanded immediate consistency, your choices are both bad: write-everywhere means every write must touch all ~100 servers (only acceptable if writes are extremely rare), and quorum means every read must touch ~50 servers (which kills your read performance β the very thing you added the replicas for). So at huge replica counts you settle for eventual consistency: just write to master + 1 slave.
Common operational questions
| Question | Answer |
|---|---|
| What if the master goes down? | A re-election happens; one slave becomes the new master. |
| What if the old master comes back? | It rejoins the cluster as a new slave. |
| What if a slave crashes? | Nobody cares β slaves die all the time. Reads just go to a different slave. |
| How does master election happen? | Usually via a distributed configuration management system (e.g. Zookeeper); other algorithms exist too. |
| How do slaves sync with the master? | Asynchronously, using the Write-Ahead Log. |
| Where do writes happen? | Always at least at the master (some configs also write to a subset of slaves). |
| Where do reads happen? | In a subset of the slaves. |
3 Replication lag & async vs sync replication
Back to the teacher reading new lines aloud. There's always a tiny delay between the teacher writing a line and a kid in the back row finishing copying it. If you ask that kid right away, he might say "I don't have that yet!" β even though the teacher already wrote it. That little delay is replication lag. And the teacher has a choice: wait until everyone finishes copying before moving on (slow but everyone's in sync), or charge ahead and let the kids catch up whenever (fast but some fall behind).
Replication lag is the time gap between a write committing on the master and that same write becoming visible on a given slave. The big design decision is when the master considers a write "done" β and that gives us three replication modes.
Asynchronous replication β fast, possibly lossy
In asynchronous (async) replication, the master writes locally, immediately tells the client "done!", and ships the change to slaves afterwards, in the background. The client never waits for the slaves.
- Pro: very low write latency β the client only waits for the master.
- Con: if the master crashes after step 2 but before step 3 reaches any slave, that write is gone. The client was told "saved" but it never propagated. This is data loss.
Synchronous replication β safe, slow
In synchronous (sync) replication, the master waits for the slave(s) to confirm they've received and stored the change before telling the client "done."
- Pro: no data loss for an acknowledged write β at least one other node has it.
- Con: the client waits for the slowest slave on every write. And if a synchronous slave goes down or gets slow, writes stall β you've coupled the master's availability to the slave's. Pure full-sync (wait for all slaves) is rare for exactly this reason.
Semi-synchronous β the practical middle
Semi-synchronous replication is the popular compromise: the master waits for at least one slave to confirm, then acks the client. The rest catch up asynchronously.
This means at least one backup copy always exists (so a single master crash loses nothing), but you don't
pay the cost of waiting for every replica. MySQL's semi-sync and PostgreSQL's
synchronous_commit with one sync standby both work this way. As you'll see in
Topic 4, "wait for at least K of N" is exactly a quorum β the same idea generalised.
| Mode | Master waits for⦠| Write latency | Data loss on master crash? |
|---|---|---|---|
| Asynchronous | nothing (acks immediately) | Lowest | Possible β unshipped writes lost |
| Semi-synchronous | β₯1 slave to confirm | Medium | No (at least one copy exists) |
| Synchronous (full) | all slaves to confirm | Highest | No, but writes stall if a slave is down |
Suppose your master commits a write at t = 0 ms. With async replication on a
healthy network:
- Network hop to slave: ~2 ms
- Slave applies the log entry: ~3 ms
- Total lag β 5 ms β invisible to humans, almost always fine.
But now the master gets a burst of 50,000 writes/sec and a slave on slow disks
can only apply 40,000/sec. It falls behind by 10,000 writes
every second. Within a minute the lag is minutes deep β a read from that slave shows data
from a minute ago. Lag is usually tiny, but under load it can blow up. Always monitor it
(e.g. MySQL's Seconds_Behind_Master).
The read-your-own-writes problem
Here's the classic bug async replication causes. A user updates their profile photo (write β master), then the page reloads and reads their profile (read β a slave that hasn't caught up yet). They see their old photo and think the save failed. They saved successfully β they just can't see their own write.
The guarantee the user expects is read-your-own-writes consistency (also called read-after-write): "after I write something, I should immediately see it." Async masterβslave breaks it because your write and your follow-up read may hit different machines that disagree for a moment.
Common fixes β you'll be expected to name at least one:
- Read from the master for data the user themselves just changed (e.g. read their own profile from the master for the next 30 seconds after an edit).
- Sticky / monotonic reads β pin a given user's reads to one specific replica so they at least don't bounce backward in time between replicas.
- Wait for the replica to catch up β remember the log position of the user's write, and only let a replica serve them once it has applied up to that position.
Async replication is the everyday face of choosing availability over strict consistency. The slaves are eventually consistent: stop all writes and wait, and every replica will eventually converge to the same data. "Eventually" is doing a lot of work β the lag is exactly the window where the system is inconsistent.
4 Failover & promotion
The one teacher with the master notebook goes home sick. Now nobody can add new lines β the class is stuck. So the kids quickly pick the kid whose copy is most up-to-date and say "you're the teacher now." From this moment, new lines go to that kid. Picking a new teacher when the old one disappears is failover. But there's a scary failure: what if the old teacher comes back and also thinks she's still in charge? Now there are two teachers and two different notebooks.
Because only the master accepts writes, the master is a single point of failure for writes. If it dies, reads can still be served by slaves, but no new writes can happen until a new master exists. Failover is the process of detecting the dead master and promoting a slave to replace it. Promotion is the act of turning a read-only slave into the new writable master.
The failover sequence
1. Detecting the death
The cluster uses heartbeats: nodes ping each other on a timer. If the master misses several heartbeats in a row (say, no reply for 10 seconds), it's presumed dead. Note "presumed" β we can't actually tell a crashed master apart from a master that's merely slow or behind a broken network link. That uncertainty is the root of all the danger below.
2. Electing the new master
You don't pick a slave at random. You want the slave that is most caught up β the one whose replicated log position is furthest along β because any writes it's missing are lost forever once it becomes master. Many systems use a consensus algorithm such as Raft or Paxos to elect a leader safely (we treat these as black boxes here; their whole job is to make sure the cluster agrees on exactly one leader).
3. Promotion
The chosen slave flips from read-only to read-write. The other slaves are told to start replicating from the new master instead of the dead one.
4. Reconfiguration
Clients and the router must learn the new master's address. This is often done with a stable hostname or a virtual IP that gets re-pointed, or via a service-discovery layer, so apps don't need to hard-code which box is master.
Async cluster, master M with two slaves A and B.
- M commits write #105 and acks the client "saved."
- M ships #105 to slave A, but crashes before it reaches slave B. So A has #105, B does not.
- Failover runs. Suppose it accidentally elects B (less caught-up).
- B becomes master at log position #104. Write #105 is now gone, even though the client was told it succeeded β and when A reconnects to B it will be forced to discard #105 to match B.
Lesson: always elect the most up-to-date replica (A), and understand that async failover can still lose the very last unshipped writes. This is the data-loss risk from Topic 2 made concrete.
Split-brain β the nightmare
Split-brain happens when a network partition (recall the "P" in CAP from Session 7) makes part of the cluster think the master is dead and promote a new one β while the old master is actually alive and still taking writes on the other side of the partition. Now you have two masters, each accepting conflicting writes, with no idea the other exists.
When the partition heals, both halves have accepted writes the other never saw β and they may contradict (both masters sold "the last ticket"). There's no clean automatic answer; you're stuck reconciling conflicting data, sometimes by hand. Prevention beats cure.
How systems prevent split-brain:
- Quorum / majority rule β a node may only act as master if it can talk to a majority of nodes. In a partition, only one side can hold the majority, so the minority side refuses writes. (This is why clusters favour an odd number of nodes β 3, 5, 7 β so a majority always exists.)
- Fencing / STONITH ("Shoot The Other Node In The Head") β before promoting a new master, forcibly disable the old one (cut its power or network) so it physically cannot keep serving writes.
- Leases / tokens β a master holds a time-limited lease; if it can't renew it (because it's partitioned away), it must stop accepting writes on its own.
A word on multi-master
So far there's exactly one writer. Multi-master (also multi-leader) replication intentionally allows several nodes to accept writes at once β handy for writing locally in multiple data centres. The price is that the same row can be edited in two places simultaneously, so you must have a conflict-resolution strategy (last-write-wins by timestamp, version vectors, CRDTs, or app-defined merges). Masterβslave sidesteps all of that by having one writer; multi-master trades that simplicity for write availability and locality. Leaderless systems (Dynamo-style) push this even further β which leads us straight to quorums.
5 The four consistency configurations
You can choose how careful to be when you save a new phone number into your address books. Save it into just one book? Super fast, but you might lose it if that book burns. Save into two books? Safer. Save into every book before you tell anyone "done"? Safest, but you have to wait for the slowest friend to finish writing. Each level of carefulness is a different configuration, and each one trades speed for safety in its own way.
Masterβslave is not one fixed thing β by choosing how many places a read touches (R) and
how many places a write touches (W), you pick a point on the consistency spectrum. Below are
the four classic configurations, from least to most consistent. In every one, reads use R = 1
(one random slave, chosen fresh each time via round-robin); what changes is the
writes.
Config A β No consistency (data loss possible)
R = 1, W = 1. Reads go to any 1 random slave; writes go only to the master.
| Operation | Where | Availability | Latency |
|---|---|---|---|
| Reads (R = 1) | Any 1 random slave (round-robin) | Very High β if a slave dies, just use another | Very Low β reading one place |
| Writes (W = 1) | Only at the master | Very High β if master dies, re-elect | Very Low β writing one place |
Writes going only to the master doesn't mean slaves have no data β they sync up periodically, so the master always has the latest data and the slaves usually lag a bit.
- Can there be data loss? Yes. If the master's HDD fails with unsynced changes, those changes are lost forever.
- Can stale reads happen? Yes β slaves sync only periodically. But here we don't even care about stale reads, because data loss is worse and this config already allows it.
Config B β Eventual consistency
R = 1, W = 2. Use this when eventual consistency is good enough. Reads go to any 1 random slave; writes go to the master + 1 random slave, atomically (random slave chosen round-robin).
| Operation | Where | Availability | Latency |
|---|---|---|---|
| Reads (R = 1) | Any 1 random slave | Very High | Very Low |
| Writes (W = 2) | Master + 1 random slave (at least 2 places) | Decent β re-elect master, or pick another slave | Decent β must write 2 places at once (2PC) |
- How do we write to two places at once? Using Two-Phase Commit (2PC): acquire distributed locks so the write to (master + 1 slave) is atomic. If it doesn't succeed in both places, we roll back the partial write and return an error; the client can retry.
- Can there be data loss? No β the data is in at least 2 places. (If both those HDDs fail before any other slave syncs, sure β but that's astronomically rare; HDDs fail maybe once every 2β3 years. Want fewer losses? Write to more places.)
- Can stale reads happen? Yes. The latest write went to Master + Slave A, but a read went to Slave B which hasn't synced yet β stale read.
Config C β Immediate consistency: Write-Everywhere
R = 1, W = X. Use this when you need immediate consistency and writes are rare (read-heavy system). Reads go to any 1 random slave; every write goes to all X nodes (master + all slaves) atomically.
| Operation | Where | Availability | Latency |
|---|---|---|---|
| Reads (R = 1) | Any 1 random slave | Very High | Very Low |
| Writes (W = X) | All X servers, atomically | Very Low β if even 1 replica fails to ack, the write is denied and others roll back | Very High β wait for the slowest server, plus any retry/rollback |
The protocol says write to all X nodes β not "all replicas currently alive." In write-everywhere, if even one replica is down, writes must be denied. Here the master's role is blurred: there's basically no difference between master and slave.
- Can there be data loss? No β every write is replicated everywhere; all copies stay in sync.
- Can stale reads happen? No β all copies are always in sync.
Config D β Immediate consistency: Quorum
R = W = (X+1)/2. Use this when you need immediate consistency and writes are frequent (write-heavy or balanced system). The idea: improve writes at the cost of reads. Write-everywhere has lightning reads but glacial writes; trade a little off each and both become decent.
| Operation | Where | Availability | Latency |
|---|---|---|---|
| Reads R = (X+1)/2 | A majority β more than half the replicas (any random copies) | Decent β at least half must go down to deny a request | Decent |
| Writes W = (X+1)/2 | A majority, atomically (master + a random half of slaves) | Decent | Decent |
Majority = more than half the total. If replication factor is X, the majority is
ceil((X+1)/2). Example: X = 5 β any read or write must succeed at at least
3 nodes to count as successful.
- Can there be data loss? No β we write to a majority, and a majority is at least 2.
- Can stale reads happen? No β you always read the latest data, because a read-majority and a write-majority must overlap in at least 1 server, and that server has the latest write.
Since different replicas can hold different values, every write stamps a timestamp; on read, we return the value with the latest timestamp.
Do we need synchronized clocks across replicas for the timestamp? No β the timestamp is generated at the coordinator (the database app server coordinating the write across replicas), so a single clock is used.
What if some servers are down β does X change? No. X is a
configuration parameter (the minimum copies you must maintain), not the live server count. Quorum always
requires success at ceil((X+1)/2) replicas regardless of crashes. Example: X = 7
β majority = 4. If 4 servers crash, only 3 remain, so no reads or writes can happen until
enough recover. (It's the DB's job to keep the live count at β₯ X most of the time.)
6 Tunable consistency & quorums
You and your friends keep three copies of the same address book. To be sure a phone number is current, you don't have to check all three books β you just need a clever rule. If you always write a new number into at least two books, and always read by checking at least two books, then any read is guaranteed to peek into at least one book that has the newest write. Two-plus-two on three books always overlap! That overlap is the whole magic trick.
Instead of the rigid "one master, slaves are read-only" model, many distributed databases let you treat all replicas more equally and tune consistency per query using three numbers:
| Symbol | Name | Meaning |
|---|---|---|
| N | Replication factor | How many copies of each piece of data exist. |
| W | Write quorum | How many replicas must confirm a write before it counts as successful. |
| R | Read quorum | How many replicas you query and compare on each read. |
If W + R > N, then your read set and your write set are guaranteed to overlap in at least one replica β so any read is certain to see the latest acknowledged write. This single inequality buys you strong consistency. If W + R β€ N, the sets can miss each other and you may read stale data (but reads/writes are faster and more available).
Why the overlap is guaranteed (the intuition)
Picture N=3 replicas as three boxes. A write lands in W of them; a read inspects R of them. By the pigeonhole principle, if W + R is bigger than the total N, the two groups can't be completely separate β at least one box must be in both. That shared box holds the freshest value, and the reader picks the most recent (each value carries a version/timestamp), so it always sees the latest write.
Three replicas hold a key, call them R1, R2, R3. We require 2 to confirm writes and read from 2.
- Write
x = 5: it commits on R1 and R2 (W=2 satisfied), so the write is acknowledged. R3 may still hold the old value for a moment. - Read
x: we query any 2 replicas. The possible pairs are {R1,R2}, {R1,R3}, {R2,R3}. Check each: every single pair contains R1 or R2 β the up-to-date ones! - So the reader always sees at least one replica with
x = 5, compares versions, and returns the newest. Strongly consistent.
Check the rule: W + R = 2 + 2 = 4, and N = 3. Since 4 > 3, overlap is guaranteed. β
Now we only require 1 replica for each.
- Write
x = 5commits on R1 only (W=1). - Read happens to hit R3, which never got the update β it returns the old
x = 4. Stale! π±
Check the rule: W + R = 1 + 1 = 2, and N = 3. Since 2 β€ 3, no overlap is guaranteed. This is the fastest, most available, most write-friendly setting β and only eventually consistent.
Unlocking the full spectrum
Here's the deeper insight from the four configs above: for immediate consistency, R and W don't have to be equal. All that matters is that the read set and write set overlap. Three knobs control everything:
| Knob | Meaning |
|---|---|
| X (= N) | Replication factor β minimum copies maintained for each piece of data at all times. |
| R | Number of reads β minimum servers that must respond with data for a read to succeed. |
| W | Number of writes β minimum servers that must acknowledge for a write to succeed. |
The four configurations of Topic 5 are just special points in this space:
| Setting | Equals | Result |
|---|---|---|
| R = 1, W = 1 | Master-slave, no consistency | Write at master, read 1 random slave β no consistency, perfect availability |
| R = 1, W = 2 | Master-slave, eventual consistency | Write master + 1 slave, read 1 slave β eventual consistency, high availability |
| R = 1, W = X | Write-everywhere | Immediate consistency |
| R = W = (X+1)/2 | Quorum | Immediate consistency, balanced |
R + W β€ X (and W > 1) β eventual consistency.
R + W > X β the servers written to + servers read from exceeds the total available, so by
the pigeonhole principle at least one server is both written to and read from β there's an
overlap β immediate consistency.
Because we can choose any R and W, we get tremendous power:
- If R is low β reads are faster and more available (touch fewer servers).
- If W is low β writes are faster and more available.
- If R + W > X β the system is immediately consistent.
As R + W increases: availability drops and latency rises (more servers must be alive for requests to succeed), while consistency rises (more likely to find an overlap holding the latest write). So we can not only choose our consistency level β we can also tune the system for read-heavy or write-heavy operation. We're no longer stuck picking just "availability" or "consistency"; we can land on any point on the spectrum.
Tuning the dials for different goals
The beauty is you can slide W and R to favour reads, writes, or safety β sometimes per query:
| Setting (N=3) | W + R vs N | Behaviour | Good for |
|---|---|---|---|
| W=3, R=1 | 4 > 3 β | Slow writes (all copies), super-fast reads | Read-heavy data that rarely changes |
| W=1, R=3 | 4 > 3 β | Super-fast writes, slow reads (read all) | Write-heavy logging/metrics |
| W=2, R=2 | 4 > 3 β | Balanced, still strongly consistent | The sensible default |
| W=1, R=1 | 2 β€ 3 β | Fastest & most available, eventually consistent | When stale reads are tolerable |
A higher W means more replicas must be up to accept a write β so strong consistency reduces write availability during failures. With W=3 on N=3, a single replica being down blocks all writes. Quorums don't escape CAP; they just give you a precise knob to choose your point on the spectrum.
How real systems expose this
This model comes from Amazon's 2007 Dynamo paper and lives on in Apache Cassandra, Amazon DynamoDB, Riak, and others. They're leaderless β no single master; you talk to a coordinator node that fans the request out to N replicas and waits for W or R of them.
In Cassandra you set N once (the replication_factor per keyspace) and then choose
a consistency level per statement, which sets W or R for that query:
-- Keyspace pins N = 3 copies per row CREATE KEYSPACE shop WITH replication = { 'class': 'SimpleStrategy', 'replication_factor': 3 }; -- A write that needs W = 2 (QUORUM of 3 = 2) INSERT INTO shop.orders (id, total) VALUES (42, 99) USING CONSISTENCY QUORUM; -- A read that also needs R = 2 β W+R = 4 > 3 β strong SELECT total FROM shop.orders WHERE id = 42 USING CONSISTENCY QUORUM;
Cassandra's named levels map straight onto W and R: ONE = 1,
QUORUM = majority (βN/2β+1 = 2 when N=3), ALL = N. Use
QUORUM for both reads and writes and you've satisfied W + R > N β strong
consistency, tuned by you, no master required.
What about the replicas that missed the write (like R3 above)? Leaderless systems heal them with read repair (when a read notices a replica is stale, it pushes the fresh value back to it) and anti-entropy / hinted handoff (background processes that catch laggards up). So "eventually consistent" really does converge β these are the gears that make "eventually" happen.
How do you write to more than one place atomically?
Whenever a config requires writing to several servers at once (W = 2, quorum, or write-everywhere), those writes must be atomic β all-or-nothing. The standard mechanism is Two-Phase Commit (2PC): a prepare phase where every participant locks and votes "ready," followed by a commit phase where the coordinator tells everyone to commit (or, if anyone voted no, to abort and roll back). If it can't succeed everywhere, the partial write is rolled back and the client retries.
- Theory: youtube.com/watch?v=-_rdWB9hN1c
- Explanation 1: youtube.com/watch?v=eltn4x788UM
- Explanation 2: youtube.com/watch?v=7FgU1D4EnpQ
- Implementation: youtube.com/watch?v=oMhESvU87jM
β Putting it all together
Four topics, one storyline: how to keep copies of your data, and how strict to be about them.
In masterβslave replication a single master takes all writes and ships an ordered log to read-only slaves, so read/write splitting scales reads (never writes). Because slaves replay that log a beat late, they suffer replication lag; the master chooses to wait for slaves (sync, safe but slow), not wait at all (async, fast but can lose writes and breaks read-your-own-writes), or wait for one (semi-sync, the middle). When the master dies, failover elects and promotes the most caught-up slave β while guarding against split-brain with majority quorums and fencing. And if you drop the single master entirely, tunable consistency lets every query pick its own safety level with N, W, and R, where W + R > N is the line between strong and eventual consistency β exactly the CAP trade-off from Session 7, now with a precise dial.
Quick self-check
In masterβslave replication, which operations can the slaves handle, and which must go to the master?
Slaves serve reads (SELECTs). All writes (INSERT/UPDATE/DELETE) must go to the single master. That's read/write splitting, and it's why reads scale but writes don't.
A user updates their avatar then immediately sees the old one. What's happening and how do you fix it?
Their write went to the master but their follow-up read hit a slave that hadn't caught up yet (replication lag) β the read-your-own-writes problem. Fix by reading the user's own recently-changed data from the master, using sticky reads, or waiting until the replica reaches the write's log position.
Which is safer against data loss on a master crash: async or semi-sync? Why?
Semi-sync. It waits for at least one slave to confirm before acking the client, so an acknowledged write always exists on a second node. Pure async acks immediately, so writes not yet shipped to any slave are lost if the master dies.
What is split-brain and what's the simplest way to prevent it?
During a network partition, two nodes both believe they're master and accept conflicting writes. Prevent it by requiring a node to hold a majority quorum to act as master (so only one side of a partition can write) β which is why clusters use an odd number of nodes β backed by fencing/STONITH.
With N=3, you set W=2 and R=2. Is this strongly consistent? Show the rule.
Yes. W + R = 2 + 2 = 4, which is greater than N = 3, so the write set and read set must overlap in at least one replica β and that replica has the latest value. Strong consistency.
You want the fastest, most available writes and can tolerate stale reads. Roughly where do you set W and R (N=3)?
W=1 and R=1. Then W + R = 2 β€ N = 3, so overlap isn't guaranteed β reads may be stale β but both reads and writes succeed by touching just one replica, maximising speed and availability. That's an eventually-consistent configuration.
If the replication factor is X = 5, how many servers form the master/slave split, and what's the quorum majority?
X = 5 means 1 master + 4 slaves (5 total copies). The majority is ceil((X+1)/2) = ceil(6/2) = 3, so any quorum read or write must succeed at at least 3 nodes.
In a write-everywhere (W = X) config, one of the slaves is down. Can a write succeed?
No. Write-everywhere requires the write to land on all X nodes, not just the ones alive. If even one replica is down or fails to acknowledge, the write is denied and the others roll back. That's why write-everywhere is reserved for rare-write, read-heavy systems.
Does the replication factor X shrink when a replica crashes? How does quorum handle a crash with X = 7?
No β X is a configuration parameter (minimum copies to maintain), not the live server count. With X = 7 the majority is 4. If 4 servers crash, only 3 remain, so neither reads nor writes can succeed (quorum needs 4) until enough replicas recover.
π References & Further Reading
Class material
- π Original class notes / handout (Google Doc) β open the shared class material for this session.
- Class handout: "[SST-2028] Master Slave".
Papers, docs & deep dives
- PostgreSQL β High Availability, Load Balancing & Replication β real-world leader/follower replication, sync vs async, and failover.
- Amazon Dynamo (SOSP 2007) β quorum reads/writes (N, R, W) behind tunable consistency.
- Designing Data-Intensive Applications (Kleppmann) β Replication chapter β replication lag, read-your-writes, and promotion in depth.