Consistency Models and User Guarantees

LESSON

Distributed Systems Foundations

009 20 min beginner

Consistency Models and User Guarantees

By the end of this lesson, you will be able to...

  • translate a user-facing surprise into a specific consistency guarantee.

  • trace how a minimum-version read prevents a stale replica from breaking "saved."

  • compare eventual convergence, read-your-writes, monotonic reads, causal consistency, and linearizability.

Idea in one sentence: A consistency model is a promise about what an observer is allowed to see after writes.

Core Insight

Nora opens a food delivery app at work.

Her saved delivery address is:

Office, 10 Market Street

Before ordering dinner, she changes it to:

Home, 42 River Road

The app says:

Address saved.

Then Nora goes to checkout. The checkout page reloads from a nearby replica that has not received the new address yet. It shows the old office address.

The database may be behaving exactly as designed. The replica may be healthy. Replication may catch up two seconds later.

But the product just broke a promise.

After the app told Nora the address was saved, Nora should not immediately see the old address as if the save never happened. The technical question is not "is the database consistent?" That question is too vague. The useful question is:

Which observation must this workflow forbid?

Plain meaning:

A consistency model tells the system which stale or reordered results are allowed, and which ones are forbidden.

In this scenario:

Nora's checkout read must not return an address older than the version she just saved.

Technical name:

This is a consistency guarantee. The specific guarantee Nora needs is read-your-writes.

The Naive Idea: Read From Any Healthy Replica

The address service has one write owner and several read replicas.

Madrid owner:
  address/nora version 27 = Office

Dublin replica:
  address/nora version 27 = Office

Lisbon replica:
  address/nora version 27 = Office

The naive read rule is:

Send each read to the nearest healthy replica.

That rule is attractive. It is fast. It keeps traffic local. It avoids bothering the owner for every read.

Then Nora saves her new address.

Madrid owner:
  version 27 -> version 28
  address = Home

Dublin replica:
  still at version 27 for a short time

If checkout reads from Dublin immediately, it may see version 27. That is a valid local copy, but it is not a valid answer for Nora's checkout after the app said "Address saved."

The missing piece is not another replica. The missing piece is an observation rule.

Check: If Dublin is healthy but still at version 27, should it return the office address to Nora's checkout?

Think first, then reveal.

Answer: No, not if Nora's session has evidence that version 28 was saved. Dublin can wait, route to a fresher replica, or return a retryable response. It should not silently return version 27.

A Worked Trace: Carry The Saved Version

The system can protect Nora by carrying a minimum version through her session.

Starting state:

address/nora:
  version 27 = Office

Nora's app:
  minimum address version = none

1. The Write Returns Evidence

Nora saves Home.

Nora app -> Madrid owner:
  PUT address/nora = Home

Madrid owner:
  version 27 -> version 28
  starts replication to followers

Madrid owner -> Nora app:
  saved_version = 28

The response does not mean every replica has version 28. It means Nora's session now has evidence that version 28 exists and is relevant to her next reads.

The app stores:

minimum address version = 28

2. Checkout Reads With A Requirement

Nora opens checkout.

Nora app -> checkout:
  load delivery address
  minimum_version = 28

The router sends the read to Dublin because it is nearby.

Dublin replica:
  local version = 27
  required version = 28

Dublin has several safe choices:

wait until version 28 arrives
route the read to Madrid
ask another replica
return "retry later" instead of old data

It has one unsafe choice:

return version 27 as if it satisfies the read

When Dublin finally applies version 28, it can answer:

Dublin -> Nora app:
  version 28 = Home

This is read-your-writes. After Nora's accepted write, Nora's later reads observe that write or a newer one.

3. The Session Must Not Move Backward

Later, Nora edits delivery instructions.

version 29 = Home + "Ring the side bell"

If her app has already seen version 29, a later checkout read should not show version 28 unless the product explicitly says it is showing an old cached view.

seen by Nora:          version 29
replica can serve:     version 28
allowed silently?      no

This is monotonic reads. Once an observer has seen a newer version, later reads in that observation path should not go backward.

So far, the mechanism is simple:

write response carries evidence
later read carries a requirement
replica checks whether its local state satisfies the requirement

The important design choice is the scope. Does the guarantee follow one browser tab, one device, one account, or every service that uses the address? That scope changes the cost.

What The Common Guarantees Forbid

Consistency models are easier to remember as forbidden surprises.

Eventual convergence says replicas that stop receiving new conflicting writes eventually become the same. It does not promise what Nora's next read will show. It is useful as a background property, but it is not enough for the checkout moment.

Read-your-writes forbids this surprise:

"I saved it, then I immediately could not see it."

It usually protects the writer's session, device, account, or token.

Monotonic reads forbids this surprise:

"I saw the new version, then the system showed me an older version."

It protects one observer from moving backward.

Causal consistency forbids this surprise:

"I saw the effect without the cause."

For example, suppose Nora saves the Home address and then adds delivery instructions: "Ring the side bell." Showing the instruction without the Home address can be confusing because the instruction depends on the address. Causal consistency keeps dependent events in an order that makes sense.

Linearizability forbids an even stronger surprise:

"A later operation missed a completed earlier operation."

Once a write completes, every later operation on that object behaves as if it sees one real-time order. This is useful for locks, inventory decrements, unique username claims, credential revocations, and other operations where one official answer matters.

The guarantees are not a single moral ladder from bad to good. They are tools for different promises. A product may use read-your-writes for address editing, causal order for comments, linearizability for a gift-card balance, and eventual convergence for search indexing.

The Data Path Changes With The Promise

The placement lesson told us where state lives and which replicas may answer. Consistency guarantees tell replicas when a local answer is good enough.

For Nora's address, a session token can carry:

address/nora must be >= version 28

The router can send the read to a follower. The follower can answer only if it has applied version 28 or newer. This preserves Nora's guarantee without forcing every address read to go to the owner.

For causal order, writes may carry dependencies:

instruction "Ring the side bell"
depends on address version 28

A replica that has the instruction but not address version 28 should wait, fetch the missing dependency, or hide the instruction until the cause is present.

For linearizability, the path is stricter. The read or write may need the owner, a quorum, a lease, or another coordination path that can defend one real-time order. That costs more latency and can reduce availability during uncertainty.

Check: A user changes their password and receives "Password changed." Which guarantee is usually closer: eventual convergence or linearizability for later login checks?

Think first, then reveal.

Answer: Linearizability, or a similarly strong coordinated rule, is usually closer. A later login check should not accept the old password just because one authentication replica has not caught up.

Worked Classification

Use the same question for every workflow:

What observation would make the product feel wrong or unsafe?

For a delivery address update, the forbidden observation is narrow. Nora saves Home, then Nora's checkout sees Office. The smallest useful guarantee is often read-your-writes for Nora's session or account. The system can still allow another user, support tool, or analytics job to see a slightly old address if that path does not make a delivery decision.

For a message reply, the forbidden observation is dependency order. A reply that says "yes, use the side door" makes little sense if the original message about the Home address is missing. The useful guarantee is causal consistency for the conversation: show dependent messages only after the messages they depend on.

For a password change, the forbidden observation is broader. After the change is confirmed, a later login check should not accept the old password from any authentication path. A session token on Nora's phone is too narrow. The system needs a stronger authority path, often linearizable or close to it for the credential state.

The method is the same each time. Name the surprise, name the observer, then choose the cheapest guarantee that forbids that surprise.

Trade-offs And Limits

The trade-off is that stronger guarantees prevent specific user-visible surprises, but they spend something.

They may spend:

Weaker guarantees can make ordinary reads fast and resilient. They are safe only when the product names the stale behavior honestly and has a repair story. Search results can be a little stale. A "recent activity" widget can lag. A delivery address shown after "Address saved" has a stricter expectation.

The limit is scope. A session token can protect Nora's current checkout, but it may not protect a background fraud check, a restaurant tablet, or a courier dispatch service unless the evidence travels to those paths too.

Useful signals include:

If these signals rise, the problem may not be storage durability. It may be that response wording and read guarantees do not match.

Common Confusions

Confusion: Strong consistency is always better

Why it is tempting:

"Strong" sounds safe and professional.

Better model:

Stronger guarantees protect stronger promises, but they cost latency, coordination, and sometimes availability. Use them where the forbidden surprise is expensive.

Confusion: Eventual convergence defines the next read

Why it is tempting:

If replicas eventually become the same, it feels like the system is basically safe.

Better model:

Eventual convergence says what happens later if updates stop. It does not say what Nora's checkout may read immediately after "Address saved."

Confusion: Read-your-writes means everyone sees my write

Why it is tempting:

The phrase sounds global.

Better model:

Read-your-writes usually protects the writer or a scoped observation path. Other users may still see an older value unless the product promises more.

Practice

Pick one workflow:

delivery address update
shopping cart update
password change
message reply
bank transfer
dashboard metric
notification read state

Fill in:

state and key:
write:
later read or decision:
forbidden stale or reordered observation:
scope of the promise:
smallest suitable guarantee:
evidence the system must carry:
what a stale replica should do:
cost of the guarantee:
signal that would reveal a violation:

Model answer for message reply:

state and key:
  conversation/launch

write:
  message 10: "Deployment failed"

later read or decision:
  message 11: "I am rolling back" replies to message 10

forbidden observation:
  seeing the reply without the message it depends on

scope:
  everyone reading that conversation

smallest suitable guarantee:
  causal consistency for replies and their parent messages

evidence:
  reply carries dependency on message 10

stale replica action:
  fetch message 10, wait, or withhold the reply

cost:
  dependency metadata and possible waiting

signal:
  buffered replies waiting for missing parent messages

Resources

Key Takeaways

PREVIOUS Replication, Partitioning, and State Placement NEXT Gossip, Membership, and Dissemination