Distributed Consistency
One machine is simple. It works, or it is down, and when it is down nobody gets a wrong answer. Two machines is where this turns hard. Their clocks do not agree, so neither can say which of two things happened first. Cut the wire between them and each one carries on serving customers, certain that it is the one in charge. Both are behaving correctly. They now hold different answers, and somebody has to decide which answer the world gets.
One small network sits under every widget on these pages. Machines hold values, a message takes a whole number of ticks to cross, some messages are thrown away, and a switch stops messages crossing from one side to the other. A tick is one step of a clock this course controls, not a real second. When a widget says three machines ended up holding two different values, that run really happened and the values were really counted at the end of it. No number on these pages was typed in by hand.
You should be comfortable with the idea that machines talk by sending each other messages, that a message can be lost or delayed without anybody being told, and that the two ends have to cope with that themselves. The course Reliable Data Transfer builds all of it from nothing. If you have not done it, Step 1 here re-explains the parts this course leans on. No programming is needed: two labs ask you to write a one-line rule and every piece of that line is explained first.
The steps
The sale that goes missing
A server is a machine whose job is to answer other machines. The machines that ask it things are called clients, and one thing a client asks for is called a request. The answer coming back is a reply. Nothing in that arrangement is clever: a shop server that holds the number of jumpers left in stock is a machine with a number written down and a habit of answering questions about it.
The number it holds is its state. Looking at the state is a read, and changing it is a write. With one machine there is one copy of the state. With two or more machines, messages and failures can leave the copies at different versions.
What is a tick, and why not use real seconds
Every widget here counts time in ticks. A tick is one step of a clock we control, and nothing happens between two ticks. A message posted on tick 4 that takes two ticks to travel is delivered on tick 6, and until then it exists but has not arrived.
Real networks work in thousandths of a second, which is far too fast to watch and far too vague to reason about. Ticks let you press a button and see exactly one thing happen. Everything you learn about ticks is true of milliseconds; you are just able to see it.
Ana: add one, then press
Tick three or four times. Watch the request sit in the wire list for a couple of ticks
before the log says it arrived and the counter moved. Then press Ana: add one and
Ben: add one one after the other and press Run until quiet.Crash the server while a request is still on the wire. Requests are
thrown away and nobody gets a reply, which is annoying, but no client is told a wrong number and there
is no second copy to argue with. One machine gives you exactly two states of the world: working, or
not working.Why does a single sale need two trips
Selling one jumper is not one action. The client has to find out how many there are, work out the new number, and send that new number back. That is a read, some arithmetic, and a write: two trips across the network with a gap in the middle.
The gap is where everything goes wrong for the rest of this page. While one client is thinking, the number it read is already out of date, and it does not know. Nothing in the network can tell it, because nothing in the network is watching.
If one machine is so much simpler, why have two
Because one machine is one power cut away from a shop that cannot sell anything, and one broken disk away from a shop that has lost its records. A second machine holding a copy means the shop survives losing either one. That is the reason people put up with everything in this course.
The second reason is size. One machine can only answer so many requests a second, and one machine in London answers a customer in Sydney slowly no matter how fast it is. Copies close to the customer are the only fix and a copy is a second machine with its own opinion.
Run this schedule and read the stock at the end. It says 8, which is
ten jumpers minus two sales. Now press Clear and place the four steps in an order where
the stock ends up wrong, then press Check my schedule.Show me one that loses a sale places
one for you, and it is not the only one that works.Clocks lie
There is an obvious fix for the lost sale, and almost everybody reaches for it first. Make every write carry the time it happened. When two writes turn up for the same thing, keep the one with the later time and throw the other away. The time carried on a write is called a timestamp, or a stamp for short, and the rule is called last write wins.
It works, as long as the two machines agree what time it is. They do not. Each machine has its own clock, and a clock is a small crystal wobbling a few million times a second with something counting the wobbles. No two crystals wobble at the same rate, so two clocks set together this morning are apart by the afternoon. The gap between two clocks has a name: the skew.
The widgets from here on label their machines node A, node B, or n1 to
n5. A node is one machine considered as part of a group, and that is the whole of what
the word means. This course says machine when there is one and node when it is one of several.
How can a clock be wrong when it is just counting
The counting is exact. The wobbling is not. A quartz crystal is cut to shiver at a chosen rate, and the rate it actually manages depends on how it was cut, how warm it is now, and how old it is. A typical one is out by a few seconds a month and a warm one in a badly cooled machine is worse.
Nothing about that is a fault, and no amount of money fixes it, because a clock that is out by one part in ten million is still out. Atomic clocks in laboratories are out by less, and they still drift. The lesson is not that clocks are bad. It is that two of them are never quite the same and a rule that compares readings from two different clocks is resting on a difference that nobody measured.
Set both clocks together
now, then press Let an hour pass a few times and watch the gap between them
grow. Then press Let a day pass. The last card is the skew, in seconds, and the bar
underneath shows how big that gap has become.Why not just ask a time server and be done with it
Machines do exactly that. There are servers whose only job is to say what time it is, and your machine quietly asks one every few minutes. It helps a great deal: instead of drifting for a day, a machine drifts for a few minutes and is then pulled back.
What it cannot do is make two clocks equal. The answer arrives by message, and a message takes time. Your machine knows the round trip took 40 thousandths of a second, but not whether that was 20 out and 20 back or 35 out and 5 back, so the time it sets itself to is a good guess with a margin around it. In practice machines on the same network land within a few thousandths of a second of each other, which sounds close until you remember that two writes to the same value can easily be less than a thousandth of a second apart.
What "later" is actually being asked to mean
When you say one write is later than another, you mean something about the real world: this one happened after that one, so it should win. When a machine compares stamps, it is doing arithmetic on two numbers that came from two different clocks. Those are not the same question, and the second one is only a useful stand-in for the first while the skew is smaller than the gap between the writes.
That is the whole trap. The rule looks like it is asking "which happened later" and is really asking "which clock was reading higher", and nobody notices the difference until two writes land close together.
I predict blue survives,
because blue really was written ten seconds after red, then press Merge and reveal.
The log shows both machines comparing stamps and deciding. Then press Try another skew and
predict again, and drag the slider down to 0 to see when the rule starts telling the truth.Did this happen before that
If a clock reading cannot be trusted, what is left? Something surprising: the messages themselves. An event is one thing happening on one machine at one moment. Writing a value is an event. Sending a message is an event. A message arriving is an event on the machine it arrives at.
Two facts hold no matter what any clock says. A machine does its own events in its own order, because it did them one after the other and it remembers. And a message is always sent before it arrives, because nothing arrives before it leaves. That is all. Chain those two facts together and you get the only ordering a group of machines can actually be sure of.
Chaining them gives a test you can run with a finger. Event X happened before event Y if you can get from X to Y moving only forwards along one machine's own line, or forwards along a message. If you cannot get from either one to the other, then neither of them could have known anything about the other, and the two events are concurrent. That word is the one to watch: it does not mean the two events happened at the same moment, it means nothing in the system can put them in an order. The relation itself is called happens-before. It is the backbone of every step after this one.
What counts as one event
Whatever you decide to write down. In the picture below, each machine does three things, and each of
those is one event with a name like a1 or c2. The letter says which machine,
the number says which of that machine's own events came first.
The choice of what to record does not change the answers. If you split one event into two, both halves happen on the same machine in a known order, so every chain that ran through the old event runs through both halves. The reasoning survives being more or less detailed, which is the sign that it is about the messages rather than about the bookkeeping.
Show me an ordered pair,
then press Show me a concurrent pair, and read what changes in the picture. Then pick
any two of the nine event buttons yourself, such as b1 and c3, and the line
underneath says whether one had to come first.Why this test can be trusted when a clock cannot
Look at what it is made of: no clocks, no assumption about how fast anything runs, nothing that can drift or be set wrongly. Walking the arrows uses two facts and no others, and both are things a machine would report about itself. I did these two things in this order. This message left here before it got there.
So the answer it gives is exactly what the machines could have known, and nothing more. That is also why it stays silent so often. A pair of events with no chain between them is a pair the system holds no evidence about. Putting them in an order anyway is not a measurement. It is a guess wearing the clothes of one.
Concurrent does not mean at the same time
Two concurrent events can be an hour apart. Concurrent here means "no chain of arrows connects them", which is a statement about who knew what, not about when. An event on a machine in Tokyo on Monday and an event on a machine in Peru on Friday are concurrent if no message passed between those machines in between.
The useful way to read it is: neither one could have influenced the other. That is why the ordering does not matter, and why claiming an order anyway is the mistake. A pair that nothing could distinguish is a pair you are free to put in either order, and any two machines are free to make opposite choices without either being wrong.
Check this order and read which arrow that breaks. Then press
Clear and place all nine yourself in an order that respects every arrow, pressing
Check this order whenever you want to test it.Counting instead of timing
Arrows in a picture are fine for us, but a machine cannot see the picture. It needs the ordering written down in something it can carry on a message and compare with arithmetic. The trick is to stop measuring time and start counting events.
Give every machine a counter that starts at zero. Every event on that machine adds one to it. When a machine sends a message, the message carries the counter's value. When a message arrives, the receiving machine first jumps its counter up to the number the message carried if that number is higher, and then adds one. Three rules, no clocks and the counters are called logical clocks because they order events without measuring anything.
Why jump up on a receive instead of just adding one
Because the arriving message is proof that something already happened somewhere else. If a message says "I was at 7 when I sent this", then everything the sender had done was numbered 7 or less, and the receiving of it comes after all of that. A counter that answered 3 would be claiming this event came before things it demonstrably came after.
Jumping up is how one machine's history gets folded into another's. It is also why the counters do not stay near each other: a machine that talks to a busy machine inherits its high numbers, and a machine nobody talks to stays low.
Next event nine times,
reading the line at the bottom each time. The number under each dot is that event's stamp, and the
three cards show what each machine's own counter holds. Watch what happens at b2,
c2 and a3, which are the three arrivals, and use ◀ Back to go
over them again.Count all nine. The promise runs one way only. If one event really did
happen before another, its number is smaller. The reverse is not true: a smaller number does not prove
anything, because two concurrent events get numbers too and one of them has to be smaller. The
slider under the picture drags through the count if you would rather scrub than press.One number per event is not enough, then, because one number always sorts and can never say "I do not
know". The repair is to give every machine a whole row of counters instead: one for itself and one for each
other machine it knows about. Three machines means three numbers,
written [2, 1, 0], and a row of numbers kept in a fixed order like that is called a
vector. The position says which machine the number is about. So [2, 1, 0] reads "I have
done 2 things, I know of 1 thing the second machine did. Nothing at all about the third".
An event still adds one, but only to its own machine's number. A message carries the whole row, and on arrival the receiver takes the larger of the two numbers in each position before adding one to its own. Now a comparison can say something a single counter cannot. Suppose every number in X's row is at least as big as Y's, and at least one is bigger. Then everything Y knew, X knew, so Y happened before X. And if each row is ahead in one position and behind in another, each machine knew something the other did not, so the two events are concurrent, proved rather than guessed. Rows used this way are called vector clocks, and Step 5 leans on them entirely.
Who decides which position belongs to which machine
They agree on it in advance, from a shared list of names. Position one is n1 because
everybody was handed the same list, and a row of numbers means nothing to a machine that does not have
that list. In real systems the row is usually stored as pairs, a name and a number together, which
costs more room and saves the argument.
Adding a machine later makes every row longer. Every older row then has to be read as though it carried a zero in the new position, which is exactly what it means: nobody had heard of that machine yet. Taking a machine away is the harder direction. Its number holds real evidence about what it did before it left, and dropping the position throws that evidence away.
If vectors are exact, why does anybody keep the single counter
Because of size. One number per machine means a stamp on every message that grows with the number of machines, which is fine for five and awkward for five thousand. A single counter is one number whatever the size of the system, and it never needs a shared list of names to be understood.
It also does one thing vectors cannot. Vectors leave concurrent events unordered, honestly, and sometimes a system needs to pick one anyway so that every machine picks the same one. A single counter always yields an order, and the machine's own name breaks the ties, so everybody agrees on a winner even though nobody is claiming it really happened first. Knowing that a cheap answer is approximate is more useful than pretending it is not.
a1 and
b2, are picked already, so press Check my pair and read why that pair is no
use for this hunt. The table gives every event both kinds of stamp side by side. Then press
Clear and hunt for a pair on two machines that had not heard from each other yet.Both halves are right
Now break the network instead of a machine. A cable is cut, or a switch fails, or somebody unplugs the wrong thing, and the group of machines is left in two pieces that can each talk among themselves and not across. That is a partition. This page calls it a cut.
The machines cannot see the cut. A machine on the left sends a message to a machine on the right and gets no reply. That is exactly what it would see if the other machine had crashed, and exactly what it would see if the other machine were fine but slow. Three different worlds, one identical view, and no way to tell them apart from inside.
Why can a machine not tell a crash from a cut
Because the only evidence either way is a message arriving, and all three situations produce the same thing: no message. There is no signal for "the machine you want is gone" and no signal for "your messages are not getting through", because whatever sent that signal would have to reach you, and reaching you is the thing that is broken.
You could add a second, separate wire to check on the first, and people do. Now there are two things that can break, and a machine that hears nothing on either one is in exactly the position it started in, with a bit more equipment. The uncertainty is not a gap in the design. It is a fact about being at one end of a connection.
Cut the network, then
press n1 writes "north" and n3 writes "south", then press Run until
quiet. The four cards show what each machine holds. Now press that first button again, which
by then reads Network is cut, to mend the network, and press Gossip
everything, which makes every machine tell every machine it can reach what it is holding.What gossip means here
Telling every machine you can reach what you now hold, and letting them pass it on. There is no leader in that arrangement and no list of who has heard what: each machine repeats what it knows and the information spreads like a rumour, which is where the name comes from.
It has one good property that matters for the rest of this course. If the machines keep gossiping and the network eventually works, everybody eventually hears everything, without anybody having to know who is up. This provides eventual convergence, but it does not promise when convergence occurs or what a read may return before then. Step 11 tests whether that guarantee fits the application.
What a conflict is, and what a merge rule is
A conflict is two writes to the same thing where neither happened before the other. Not two writes that arrive in a funny order, and not two writes that disagree. Concurrent writes, proved concurrent by their vectors, with nothing in the data saying which should win.
Something has to happen next, and whatever you choose is a merge rule. Keep the later stamp. Keep the bigger value. Keep both and hand them to a person. Add them together. Every one of those is a real rule that real systems use, and Lab 10 makes you look at what each one destroys.
Keep both and ask later is the only rule here that
destroys nothing, and its price is real: something further along has to know what to do with two
answers, and for the signpost there is no sensible answer at all. A person has to choose.You cannot have everything
The cut leaves a machine with two options and no third. It can answer the customer from whatever it happens to hold, which may be out of date, and accept writes that may later be thrown away. Or it can refuse to answer at all until it can reach enough of the others to be sure. Answering is called being available. Never giving an answer that is out of step with the others is called being consistent.
While the network is cut you may have either one. Not because nobody has been clever enough yet, but because the machine has no information: a cut-off machine that answers is guessing, and a cut-off machine that refuses is admitting it cannot know. This step makes you pick one and then shows you the bill.
Where "answer only with a majority" comes from
A cut divides five machines into two groups, and only one of those groups can hold three or more of them. So "answer only if you can reach more than half of the machines" has a property no other rule has: at most one group can ever satisfy it, whatever the shape of the cut. A group of more than half is called a majority, and this is why the rule is majority rather than "at least two".
Two out of five would let both sides carry on, which is the split brain from Step 5 with extra steps. More than half is the smallest rule that makes two halves unable to both feel in charge.
Answer anyway
and press Run the twelve operations. Read the five cards, then press Only answer
if you can reach a majority and run the same twelve again. Every number on those cards comes from
what the twelve customers were actually told.What an out-of-date answer costs, in real money
It depends entirely on the question, which is why this is a decision and not a rule. An out-of-date count of likes on a video costs nothing: it is a number nobody checks twice. An out-of-date bank balance means an overdraft the bank did not agree to. An out-of-date seat map means two people with the same seat, and a very long conversation at the gate.
So real systems make the choice per question rather than once for the whole company. The same shop will happily show you a stale count of how many people are viewing this item, and will not sell the last one twice. Both live in the same building, and the interesting engineering is deciding which values sit on which side of that line.
The name this choice goes by
People call it the CAP theorem, from consistency, availability and partition tolerance. It is often quoted as "pick two of three", which is a poor way to say it, because a partition is not a thing you pick. Networks get cut whether you approve or not.
The experiment gives the precise choice: when the network is cut, a machine can answer without knowing the other side's state or refuse to answer. When the network is fine, you can have both, and a great deal of practical work goes into keeping the periods of being cut short and rare so that the choice hardly ever has to be made.
Run both rules and read
the six bars in pairs. Each pair is the same measurement under the two rules: how many customers got
an answer, how many answers were wrong, and how many accepted writes were later discarded.Overlapping on purpose
The majority rule from Step 6 is one setting of a more general idea, and the general idea is worth having, because it lets you buy exactly as much certainty as you want to pay for.
Keep the value on N machines. A write is not accepted until it has reached W of them. A read asks R of them and keeps the newest answer it gets back. A set of machines big enough to act on its own like that is called a quorum. So W is the size of a write quorum, and R the size of a read quorum. Now the question is: when is that read guaranteed to see the newest write? Nobody has to guess, because the widget below runs two hundred rounds and counts.
How a read knows which of several answers is newest
Every write is given a number that goes up, and each machine stores that number next to the value. So a read that asks three machines gets back three pairs, and the newest is simply the one with the biggest number. That is all the vector clock machinery from Step 4 collapsed into one counter. It is allowed here because the writes all go through the same counting.
The read does not need a majority to work out which answer is newest. It only needs to have asked at least one machine that saw the newest write. That is the entire subject of this step: not counting for the sake of counting, but making sure two sets of machines cannot avoid each other.
out of date as
the widget starts, with N at 5 and both R and W at 2. Seventy of the two hundred reads missed the newest
write. Now drag the R slider up one notch at a time and watch that number: 3 is still not enough, and at
4 it reaches zero. Then press Kill copy 1 and Kill copy 2.Why the two sets have to overlap, said with a shelf
Put five books on a shelf. Somebody puts a bookmark in two of them. Somebody else, who cannot see the bookmarks, opens four of the five. Can they miss both bookmarks? No: only one book is left unopened, and there are two bookmarks, so at least one bookmarked book was opened.
Two plus four is six, and six does not fit in five without something being in both groups. That is the whole proof, and it is why the rule needs R plus W to be strictly bigger than N. Two bookmarks and two books opened, out of four books, is exactly enough room for the two groups to keep apart. It is the case that catches almost everybody.
New to code: what a function is, and what "return" means
The next lab has you edit one line of a program. A function is a named piece of a program that
takes some values in and hands one value back. function safe(n, r, w) { starts a function
called safe that expects three numbers, and inside it those three numbers are called
n, r and w. Anything after // on a line is a note to
the reader and is ignored by the machine.
return is how the function hands its answer back and stops. return false;
means "the answer is no". The two answers a yes-or-no question can have are written true
and false. So return r + w > n; hands back true when r plus w is bigger
than n, and false when it is not, and > is the ordinary greater-than sign. The lab
checks your line by calling it with ten different sets of numbers and comparing the answers, so it is
grading what your rule does rather than how you wrote it.
Run before changing
anything, so you can see that both printed lines say false. Then change
return false; to your own rule, press Run again to read the two lines, and
press Check my rule when they look right. Start over puts the original line
back.n=4, r=2, w=2, which is the one
that catches people, and n=5, r=5, w=1, where the read asks everybody. If your rule
answers those two correctly it is the real rule and not a near miss. When you have passed,
Show me one that works shows the same idea written with a comment explaining it.The two generals
Everything so far has been about coping. This step is about something you cannot cope with, and it is worth meeting on purpose, because a great deal of engineering time has been spent trying to build it anyway.
Two commanders are camped on two hills with a town in the valley between them. They win only if they attack at the same time, and lose badly if either attacks alone. The only way to talk is to send a messenger through the valley, where the messenger may be caught. Neither commander can see the other. What do they agree on, and how many messengers does it take?
Why two generals and not two servers
They are two servers. The hills are two machines, the valley is a network that loses messages, and attacking together is any decision two machines have to take identically: both charge the card, or neither does. The story is from 1975 and it stuck because the picture is easier to hold in your head than the machines are.
Everything in the story maps onto something in Step 5. A messenger caught in the valley is a lost message. A commander waiting and hearing nothing is a machine that cannot tell a cut from a crash. The answer the story gives applies to the machines exactly, and it is not a comforting answer.
Send the next message four
or five times and read the last line of the list each time. Then press Send five more
and read that last line again. It says the same thing with different names in it.Send the next one, but lose
it and compare what the sender sees with what it saw a moment ago: nothing on that side is
different. The sender cannot tell a lost message from a delivered one whose reply has not come yet, and
the last message sent always has that problem, whichever message is last.Why a hundred confirmations do not help
Suppose somebody hands you a plan that always works and uses exactly six messages. Look at the sixth one. Whoever sent it never finds out whether it arrived, so that sender must behave the same way in both cases, so the plan works just as well if the sixth message is never sent at all. You now have a plan that uses five.
Run that argument again on the fifth, and the fourth, until you have a plan that uses no messages, where one commander attacks with no idea what the other will do. That plainly loses, so the six-message plan cannot have worked either. Nothing in the argument mentioned six, which is why the answer is not "use more messages".
Remove the last message
six times, reading the line it adds each time. Each line is the same argument applied to one fewer
message. Then set the slider to a bigger number and press Remove them all.What this does not mean, because real shops do take payments
What is impossible is certainty: no plan makes both sides sure, in every possible run, using finitely many messages. What is entirely possible is being confident enough. Send the confirmation three times and the chance that all three are lost is small, and you can make it as small as you can afford.
The other move real systems make is to stop needing both sides to decide at the same instant. Write down what you intend to do first, agree afterwards, and make the action safe to repeat so that doing it twice by accident has the same effect as doing it once. Almost every payment system you have used works that way, and it works because it stopped asking for the thing that cannot be had.
How far behind the copies are
Most systems do not let every machine take writes, because Step 5 showed what that costs. Instead one machine is the leader, the only one allowed to accept a write, and the others are followers that keep copies. The leader writes down each accepted value in order. That ordered list of values is called a log. One value in the log is an entry, and adding one to the end is called appending.
Every time the leader appends an entry, it sends a copy of that entry to each follower. The copy takes time to arrive. So there is always a moment when the leader has an entry that a follower does not, and a customer reading that follower is told the old value. How long that lasts is the replication lag.
Why followers exist at all if they are behind
Three reasons, and they are the reasons from Step 1 again. A follower can take over if the leader dies, which turns a disaster into a pause. A follower can answer reads, so a hundred readers do not all queue behind one machine. And a follower close to the customer answers quickly, which no amount of leader is going to fix for a customer on the other side of the world.
Being a little behind is a small price for those three, and often the value being read has not changed for hours anyway. The trouble is not lag by itself. It is lag that nobody accounted for in a place where a stale answer causes harm, and lag that grows without limit while nobody is watching.
Write five, one per tick,
then press Customer reads follower two. Five values are written and that customer is
told nothing yet, because follower two is eight ticks away and not one copy has landed. Then
press Run until quiet and read the same follower again.What an acknowledgement is, and why waiting for one is a choice
When a follower has written an entry into its own copy, it sends a small message back to the leader saying so. That message is an acknowledgement, usually shortened to ack. It is the only way the leader ever learns that a copy landed.
So the leader has a decision on every write. Tell the customer it is done immediately, and be fast but hand out stale reads. Or wait for the acks first, and be slower but never have a copy behind. There is no third option, and the next lab races the two.
Reading your own writes, and why it feels like a bug
The version of lag that customers actually complain about is this one. You change your name, the leader accepts it, the page reloads, the reload happens to be answered by a follower that has not heard yet, and your old name comes back. Nothing is broken and no data was lost, and every person this happens to is certain the site lost their change.
The usual fix is small and worth knowing: for a short while after somebody writes, send that person's reads to the leader, or to a follower that has caught up past their write. It costs almost nothing, and it turns an alarming bug report into a promise you can write down. Step 11 asks you to check exactly this promise against a running system.
Race them again and read
the four bars. The top two are how long the twenty customers waited, the bottom two are how many
reads were out of date. Then drag Ticks to the further follower out to 12 and press Race
them again: of the two waiting bars, watch which one grows and which does not move at all.Dead, or just slow
If the leader dies, a follower has to take over, and quickly, because until it does nobody can write anything. So something has to notice the death. The usual arrangement is a heartbeat: the leader sends a short "I am here" message every few ticks, and a watcher declares it dead when the messages stop for longer than some agreed budget. That budget is called the timeout.
The watcher sees exactly one thing, and it is not death. It sees silence. Silence from a machine that has died and silence from a machine that is briefly overloaded are the same silence and the timeout is a guess about which one this is.
Why a healthy machine goes quiet for a while
All sorts of ordinary reasons. Its disk is busy, so the write it was doing took twenty times as long as usual. The machine it shares a building with started a backup and the network between them filled up. Its own memory needed tidying, and the tidying stopped everything else for a moment.
None of that means the machine is unwell in any way that matters, and all of it produces a gap in the heartbeats. This is why the timeout cannot simply be set low: a low timeout does not detect more deaths, it invents them.
Try 5 ticks, then
Try 40 ticks, and compare the false alarms card with the real death spotted
card. The watched machine is healthy until tick 700 and then really does die, and every number here
comes from one nine hundred tick run.What two leaders at once actually does
It is the split brain from Step 5, arrived at by a different route. Both leaders accept writes, neither knows about the other, and the two lists of entries diverge. When somebody notices, one of the two lists has to be thrown away and the customers whose writes were in it were told those writes had succeeded.
Real systems defend against this by making the old leader unable to do damage rather than by trying harder to detect it. Every leader carries a number that goes up each time a new one is chosen, and followers refuse anything carrying an old number. The demoted leader can shout as much as it likes and nobody is listening. The next course in this stream builds that machinery.
What a good timeout looks like in practice
Nobody good picks one number and leaves it. The machine watches how long the gaps between heartbeats usually are for this particular machine, and suspects it when the current silence is far outside its own usual range. A machine that is normally slow gets more rope than one that is normally instant, which is the rule you are about to write.
The other half of the answer is to stop treating suspicion as a verdict. Instead of "dead" or "alive", keep a number saying how suspicious things look, and let whatever depends on it decide how much suspicion is enough. A leader takeover can demand a lot of evidence, and a load balancer sending a request elsewhere can act on very little, and both read the same number.
Run without changing
anything and read the two printed lines. The starting rule says a machine is dead after 10 ticks of
silence, which calls a 70 tick silence dead even for a machine that has taken 40 ticks before and been
fine. Change that line so it uses worstSeen, then press Check my rule.What a system can promise
These failures do not make distributed systems unusable. They show why each design needs a precise contract. State whether reads may be stale, what a successful write guarantees, which failures are tolerated, and how long recovery may take. Then test those claims with the corresponding fault.
So this step has no new mechanism in it. The first lab is a cluster of five machines with every switch from the whole course on it and nothing to get right. The second gives you five promises and one running system, and asks you which of them that system can honestly make.
The names these five promises go by
"Every request gets an answer" is availability."A second read never shows something older than the first" is monotonic reads."You always see your own last write" is read your own writes."Once the network is mended, every copy ends up the same" is eventual consistency. And a write that is accepted and never quietly discarded is durability of the accepted write.
Learning the names is worth ten minutes because they are how the promise is written in a manual, and a manual that promises eventual consistency is telling you, in two words, that it does not promise the other four. Reading that sentence properly is most of what this course was for.
n4 to choose that machine,
then Write a new value here, then Run until quiet. Everyone agrees. Now
press Cut the network, write on n1 and on n5, run until quiet
again, and press Read from here on a few different machines.Why "eventually the same" is worth having at all
It sounds like the weakest promise on the list, and it is. It is still the difference between a system that heals itself and one that needs a person. It says that if the machines can talk again and somebody keeps gossiping, the copies stop disagreeing without anybody being told who is up or what broke. A system that does not promise it has to be repaired by hand after every cut.
What it does not tell you is when, and it does not tell you what happens to conflicting writes on the way. Those are separate questions with separate answers and a system can promise this one and still throw away your write. Reading the promise for exactly what it says, and no more, is the habit worth keeping.
How a promise is tested, rather than argued about
The way Lab 22 does it. Write down what the customers did and what they were told, in order, then check the list of promises against that record. Nobody's opinion is involved: either a customer was shown a value older than one they had already seen, or no customer was.
This is a real technique with real tools behind it. People test databases by running a pile of clients against a cluster while cutting its network at random, recording every answer, and then checking whether any promise in the manual was broken by that record. The number of well-known databases caught breaking their own manuals this way is larger than you would hope.
Answer anyway,
press Run the customers, and read the log of what the three customers were told. Then
tick the promises you think this setup keeps and press Check my answer. It names the first
one you have wrong and quotes the evidence from the run.Only
answer with a majority and work the other one out from scratch. A different set of promises
survives, and neither set is all five. That list, honestly filled in, is what a system is allowed to
claim, and being able to produce it for something you built is the difference between engineering and
hoping.Take any claim about a group of machines and work out which of it survives a cut, a crash and a slow machine. That is a skill with a market rate, and you now have it.
What you built up to
- Cause a lost update, and say exactly why the gap between a read and a write is where it comes from.
- Explain why two clocks disagree, and why "keep the later write" throws away the later write.
- Order events without a clock, using only what machines could have known, and say when no order exists.
- Read a vector stamp and tell "before" from "concurrent".
- Recognise split brain, and pick a merge rule knowing what it destroys.
- Choose between answering and being right during a cut, with the counts in front of you.
- Set N, R and W so a read cannot miss the newest write, and know why the rule is strict.
- Explain why no number of messages makes two machines certain, without hand-waving.
- Tell replication lag from data loss, and price the cost of waiting for every copy.
- Pick a failure timeout knowing which two things you are trading.
- Audit a system against a written list of promises, using a record of what customers were told.
Where this goes
- Raft and Consensus. This course was about what goes wrong. That one is the machinery that copes: elect one leader properly, replicate a log so no accepted write is ever lost, then kill the leader mid-write and watch the rest heal without a person.
- Inside a Database. One machine, taken seriously: how a write survives the power being pulled out halfway through, which is the promise every copy in this course was quietly assuming.
- Reliable Data Transfer. If you came here without it, the layer underneath: making a message arrive at all, across a network that loses, delays, duplicates and reorders.
Read a history against a model
A consistency model is a set of allowed histories. A history records when each operation started, when it finished, its input and its result. Linearizability requires every completed operation to appear at one instant between its call and return, while preserving real-time order. Sequential consistency preserves each client's program order but may choose a different order for operations that did not overlap in real time.
Causal consistency preserves cause before effect and may leave concurrent operations unordered. Eventual consistency only promises convergence after updates stop and all updates arrive. “Strong” and “eventual” are not complete specifications; name the operations, model, failure assumptions and any bounded-staleness limit.
One object or a transaction?
Linearizability is normally stated per object. Strict serializability combines serializable multi-object transactions with real-time order. Do not claim the second after testing only the first.
Read the original linearizability paper and the Jepsen model map.
Keep one user's session sane
A system may choose weaker global consistency and still protect one user's path. Read your writes keeps a user from saving a change and immediately seeing an older copy. Monotonic reads prevent a session from moving backward, monotonic writes preserve its update order, and writes-follow-reads keep an update after the version it used.
Sticky routing is one implementation, not the promise itself. A session token carrying a version can move with the client and make another replica wait or forward the read. Decide what happens when the required version is unavailable: wait, fail, or explicitly return weaker data.
Why a session token is evidence
The token names the minimum version this client has already observed. A replica can compare that requirement with its local version instead of guessing from elapsed time.
Merge by construction
A conflict-free replicated data type gives concurrent updates a merge rule that is associative, commutative and idempotent, so delivery order and duplicates do not change the converged answer. A grow-only counter keeps one component per replica and merges each component by maximum. Its value is the sum.
The data type decides semantics. A grow-only set cannot remove. An observed-remove set tracks which additions a removal observed, so a concurrent unseen add can survive. CRDT convergence does not automatically preserve a bank balance, uniqueness constraint or inventory floor; application invariants may still require coordination.
State-based and operation-based forms
State-based replicas merge whole or delta states with a join. Operation-based replicas deliver operations under stated ordering and delivery assumptions. The proof obligations differ.
See the CRDT overview.
Repair replicas in the background
Read repair fixes replicas encountered by a read. Anti-entropy compares replicas in the background, often using hashes over ranges so equal regions are skipped. Hinted handoff temporarily stores an update for an unavailable owner. None of these makes an acknowledged write durable unless the acknowledgement rule already placed enough copies.
Tombstones represent deletion long enough for every replica to learn it. Remove them too early and an old value can return during repair. Keep them forever and metadata grows without bound. Garbage collection therefore needs evidence about replica membership, repair completion and the maximum time an old replica may rejoin.
Why repair and consistency are separate
Repair changes how long replicas disagree. The read and write rules decide which disagreement a client may observe before repair finishes.
Coordinate a multi-service change
Two-phase commit asks participants to prepare durably, then tells all of them to commit or abort. It can make the decision atomic, but a prepared participant may block while the coordinator is unavailable. Consensus can replicate the coordinator decision; it does not remove every application and availability trade-off.
A saga commits local transactions and runs compensating actions after a later failure. Compensation is a new business action, not time travel. The transactional outbox stores a state change and an event in one local transaction; a relay may publish the event more than once, so consumers use stable IDs and idempotent effects. “Exactly once” must name the boundary being measured.
Why compensation can fail
The world may have changed since the original action. A refund can fail, a seat may have been resold, and an email cannot be unsent. Design retries, escalation and a visible incomplete state.
Use time with an error bound
Step 2 showed that bare wall clocks lie. A clock service can instead return an interval: the true time is no earlier than this bound and no later than that one. If a transaction must be ordered after everything that definitely finished before it, the system can wait until the uncertainty interval has passed its commit timestamp.
Hybrid logical clocks combine a physical-time estimate with a logical counter. They remain close to wall time while preserving causal order when clocks move backward or messages arrive from the future. Neither method excuses an unmeasured clock error. Monitor uncertainty, reject implausible jumps and specify behaviour when the bound grows.
What TrueTime contributes
Google Spanner uses a bounded time interval plus waiting and replicated transaction machinery to provide external consistency. The clock interval is one component, not a replacement for consensus or concurrency control.
See Google Cloud's explanation of TrueTime and external consistency.
Try to falsify the promise
A happy-path load test does not validate consistency. Generate overlapping operations from independent clients, record invocation and completion, inject process pauses, crashes, partitions and clock changes, then ask a checker whether any legal history explains the results. Preserve incomplete operations rather than quietly deleting them.
Random testing finds some schedules. Deterministic simulation and model checking explore chosen state transitions repeatedly and shrink a failure to a small counterexample. AI tools can propose fault schedules or summarise a long trace, but the model, raw history and executable checker remain the evidence.
Why client observations matter
Internal logs can agree while clients receive an impossible result. Build the checked history from request and response boundaries, then use internal traces to explain a violation.
Continue the distributed systems path
- Raft and Consensus builds a replicated log under leader failure.
- Inside a Database develops local transaction and recovery machinery.
- Fault Tolerance connects these guarantees to SLOs, incident evidence and regional recovery.