Lesson 24 · Consistency models · Module 2

The Consistency Map

Two engineers say "eventually consistent" and mean guarantees that differ by an enormous margin — one of them forbids reads that go backwards in time, the other forbids nothing at all. The models have precise names, they sit in a known order, and the order tells you what each one costs.

The win in this lesson: you will be able to take any guarantee you meet — in a vendor's documentation, in a design review, in your own service — and place it on one map, say what it forbids, and say whether it can still answer requests when the network splits.

1. The word that means nothing on its own

"Eventually consistent" is not a model. It is the residue left when you delete every model. To say something useful you need the actual vocabulary, and the vocabulary is unusually well defined — each model is a rule about which histories a system is allowed to produce.

"A consistency model is a safety property which declares what a system can do. Formally, a consistency model defines a set of histories that a system can legally execute."

Jepsen, Consistency

Which gives you the trick that makes the whole area tractable. Do not try to remember what a model promises — promises are vague and marketing owns them. Remember what it forbids.

"Consistency models are often defined in terms of proscribed phenomena: specific patterns of operations."

Jepsen, Consistency
The one question to ask

When someone tells you their store is consistent, the useful reply is never "how consistent?" It is "name a history it will never produce". A model that cannot answer that is not a model, and a system that cannot answer it has not chosen one.

2. The models, by what each one forbids

Linearizable — the strongest single-object model

"Linearizability is one of the strongest single-object consistency models, and implies that every operation appears to take place atomically, in some order, consistent with the real-time ordering of those operations: e.g., if operation A completes before operation B begins, then B should logically take effect after A."

Jepsen, Linearizability

It forbids any read that misses an already-completed write, from any process, ever. That "real-time" clause is the expensive part: it binds the system to wall-clock ordering that it cannot observe locally, which is why it needs agreement between nodes before it can answer.

Sequential — one order, but not necessarily yours

Drop the real-time requirement and keep the single order, and you have sequential consistency. Everybody agrees on the sequence; nobody promises the sequence tracks the clock.

"A process in a sequentially consistent system may be far ahead of, or behind, other processes. For instance, they may read arbitrarily stale state. However, once a process A has observed some operation from process B, it can never observe a state prior to B."

Jepsen, Sequential Consistency

So it forbids two processes disagreeing about the order of any two writes. It permits the whole system to be minutes behind.

Causal — order only where order was possible

"Causal consistency captures the notion that causally-related operations should appear in the same order on all processes—though processes may disagree about the order of causally independent operations."

Jepsen, Causal Consistency

Jepsen's example is a three-person chat, and it is worth having in your head because it shows exactly which disagreement is legal and which is not:

"Causal consistency allows Attiya to observe “lunch?”, “yes”, “no”; and Barbarella to observe “lunch?”, “no”, “yes”. […] However, no participant ever observes “yes” or “no” prior to the question “lunch?”."

Jepsen, Causal Consistency

It forbids an effect being visible before its cause. Two answers may arrive in either order. Neither may arrive before the question.

The session guarantees — four small promises to one client

Below causal sit four guarantees that constrain only what one process sees. They are weak, cheap, and they are the ones you will actually be offered.

"Read your writes (also known as read my writes) requires that if a process performs a write w, and that same process performs a subsequent read r, then r must observe w’s effects."

Jepsen, Read Your Writes

And the limit, which is the half people forget:

"Note that read your writes does not apply to operations performed by different processes. There is no guarantee, for instance, that if process 1 writes a value successfully, that process 2 will subsequently observe that write."

Jepsen, Read Your Writes

The other three:

  • Monotonic reads — "if a process performs read r1, then r2, then r2 cannot observe a state prior to the writes which were reflected in r1; intuitively, reads cannot go backwards" (Monotonic Reads).
  • Monotonic writes — "if a process performs write w1, then w2, then all processes observe w1 before w2" (Monotonic Writes).
  • Writes follow reads — "if a process reads a value v, which came from a write w1, and later performs write w2, then w2 must be visible after w1. Once you’ve read something, you can’t change that read’s past" (Writes Follow Reads).

Three of those four bundle into one named model, which saves you a lot of words:

"PRAM is exactly equivalent to read your writes, monotonic writes, and monotonic reads."

Jepsen, PRAM

Put in a table

ModelWhat it forbidsAvailable under a partition?
Linearizable Any read missing a write that already completed, in real time No — some or all nodes stop
Sequential Two processes disagreeing on the order of any two operations No — some or all nodes stop
Causal Seeing an effect before the cause it depends on Sticky only — client must not move server
PRAM Any reordering of the operations a single process issued Sticky only
Read your writes Your own later read missing your own earlier write Sticky only
Monotonic reads Your reads going backwards to an earlier state Yes — totally available
Monotonic writes Your second write landing anywhere before your first Yes — totally available
Writes follow reads A write becoming visible before the write it replied to Yes — totally available
Eventual Nothing about any read you can make today Yes — nothing to coordinate

3. The lattice

These are not nine unrelated options. They are ordered, and the order has an exact meaning:

"When we say that model x implies y, we mean that for every history where x holds, y does too; x is “stronger” than y."

Jepsen, Consistency Models

"For single-object models, strict serializable implies linearizable, which implies sequential, which implies causal. Causal implies writes follow reads and PRAM."

Jepsen, Consistency Models
linearizable sequential causal PRAM (= RYW + MW + MR) read your writes monotonic reads monotonic writes writes follow reads eventual consistency above: cannot serve all clients at all during a partition sticky available: fine until a client switches server below the line: totally available. every node keeps answering, always
An arrow means the model above is strictly stronger: every history the upper model allows, the lower one allows too. PRAM is read your writes plus monotonic writes plus monotonic reads, which is why it has three children. Read downward and each step is a thing you stop forbidding; read upward and each step is coordination you start paying for. The solid line is the one to memorise — below it, a partition costs you nothing.

4. One history, two verdicts

A model is only real to you once you can look at a history and say which models it breaks. Two examples, and both are things your system probably does today.

Monotonic reads satisfied, read your writes violated

one process primary replica read x → 0 write x = 1 → acknowledged committed on the primary, not yet anywhere else replicate x = 1 — still in flight read x → 0, from the process that just wrote 1 monotonic reads: held. 0 then 0 — the reads never went backwards. read your writes: violated. A process failed to observe its own acknowledged write.
A read-from-replica setup produces this every day. Note how little the weaker guarantee catches: monotonic reads is perfectly happy, because the process never saw the world move backwards — it simply never saw its own write at all. The shaded band is the window in which the two models disagree. Widen it by adding replication lag; it does not close on its own.

Causal satisfied, sequential violated

writer P1 writer P2 reader R1 reader R2 write x = a write x = b neither writer read the other first — the two writes are causally independent a becomes visible b becomes visible b becomes visible a becomes visible R1 saw a then b. R2 saw b then a. There is no total order both agree with. causal: held, nothing was seen before its cause. sequential: violated, and so is linearizable.
This is Jepsen's lunch conversation drawn as a history. The two writes are independent, so causal consistency lets the readers disagree about their order — and a system built to stay up during a partition will take that licence. Sequential consistency is the step where that disagreement becomes illegal, and the shaded band is exactly the evidence you would show to prove the violation.

5. Which models survive a partition

Now the property that decides architecture. The line runs through the lattice in one place, and Jepsen states it in one sentence:

"All models at or stronger than cursor stability, snapshot isolation, and sequential cannot be totally available in asynchronous networks. All models at or stronger than read your writes can be at most sticky available. Weaker models (of those listed here) can be totally available."

Jepsen, Consistency Models

Three bands, and each has a concrete operational meaning.

Not available at all

"This model cannot be totally or sticky available; in the event of a network partition, some or all nodes will be unable to make progress."

Jepsen, Linearizability — the identical sentence appears on Sequential Consistency

Not "gets slower". Unable to make progress. A minority partition holding a linearizable store must refuse your request, because the only honest alternative is to answer from state it cannot prove is current.

Sticky available

"Causal consistency is sticky available: even in the presence of network partitions, every client connected to a non-faulty node can make progress. However, clients must stick to the same server."

Jepsen, Causal Consistency

Read your writes carries the same caveat, phrased as an operational rule:

"Read your writes is sticky available: if a network partition occurs, every node can make progress, so long as clients never change which server they talk to."

Jepsen, Read Your Writes
"Sticky" is a load-balancer word, and that is the point

Sticky availability is a guarantee you can lose by accident. A retry that lands on a different node, a connection pool that reopens elsewhere, a failover, a client that reconnects through a different edge — each of them silently drops you out of the band you thought you were in. Nothing errors. The guarantee just stops applying. This is the same lesson as Lesson 04 from the other direction: a retry is not a free repeat of a request, it is a new request with different properties.

Totally available

Monotonic reads, monotonic writes and writes follow reads each carry the strongest availability claim on the map — "even during a network partition, all nodes can make progress" (Monotonic Reads), and "Every node can make progress regardless of network partitions" (Writes Follow Reads).

And Jepsen spells out the exact trade you make to get there:

"If you need total availability, you’ll have to give up causal (and read-your-writes), but can still obtain writes follow reads, monotonic reads, and monotonic writes."

Jepsen, Causal Consistency

Why stronger always costs coordination

The pattern in the lattice is not a coincidence. Every model above the line constrains what different processes may see relative to each other. A node cannot satisfy a constraint about other nodes' observations using only local state — it has to hear from them first. That message is the cost, and a partition is precisely the condition in which the message does not arrive.

Everything below the line constrains only one session against itself. A single node can enforce that alone, out of what it already knows, which is why a partition changes nothing.

6. Where this still leaks

Three residual risks, and the first two are how teams get this wrong in practice.

  • A system is not on one point of the map. Stores routinely offer different models per operation — a consistency level chosen per query, a linearizable compare-and-set alongside eventually consistent reads, a transactional path beside a fast path. "Which model does it give?" is the wrong question; "which model does this call give?" is the right one, and the answer can change when someone edits a config.
  • Guarantees do not compose across objects. Linearizability is a single-object model — "the scope of 'an object' varies. Some systems provide linearizability on individual keys in a key-value store" (Linearizability). Two linearizable keys do not make a linearizable pair of keys, and two services each keeping causal order do not give you causal order across the pair. Every hop through a queue, a cache or a second datastore is a place where the guarantee ends and nobody writes it down.
  • The map is what a model permits, not what your vendor implements. A model is a claim about every history the system can produce; the only way to know is to generate histories and check them, which is the entire reason Jepsen exists. Documentation describes the intent.

7. Check yourself

8. Back to your world

Take the last design you shipped that reads from anywhere other than the place it writes. A cache, a replica, a search index, a second service. Write down the strongest model it actually provides, then write down which of the nine rows above your product requirement needs. They are rarely the same row, and the gap is where your next incident lives.

The two questions to carry: name one history this system will never produce, and what happens to that promise when the network splits and my client reconnects somewhere else? If the second answer is "nothing changes", you are below the line and you are safe. If it is "I do not know", you are sticky available and you are one failover away from finding out.

Ask me things. Good directions: "draw a history that is causal but not read your writes" · "why is linearizability single-object, and what fixes that?" · "how would I test which model my store really gives?" · "is sticky availability worth anything in a world of load balancers?" · "I think eventual consistency is fine for everything. Grill me."