5 min read

Consistency Models

"Consistent" means five different things. Name the one you need, per feature, and pay only for that.


The story

A discussion app stores posts and comments in a database with replicas in three regions. Writes go to the nearest region and replicate to the others asynchronously.

Priya, in Mumbai, posts a question. Arjun, also in Mumbai, sees it a second later and replies. In the Frankfurt replica, Arjun's reply arrives before Priya's question: the two writes went through different replication streams, and the reply's stream happened to be faster.

So a reader in Frankfurt sees an answer to a question that doesn't exist yet:

Each replica eventually has both writes, so the system is eventually consistent. But it broke a promise users take for granted: an effect never shows up before its cause. That promise has a name, causal consistency, and it's one of several levels between "perfectly consistent" and "eventually consistent".


The idea: a spectrum, not a switch

ModelPromiseCostUse for
LinearizableEvery read sees the latest completed write, as if there's one copyCoordination on every op. Unavailable in a partition.Locks, leader election, balances, unique usernames
SequentialEveryone agrees on one order of all writesStill needs a global orderRarely chosen directly
CausalIf B depends on A, everyone sees A before BTrack dependencies. Stays available in a partition.Comments, chat, collaborative edits
Session (read-your-writes, monotonic reads)Each user's view is coherent for themRoute or pin a sessionProfiles, settings, anything a user just edited
EventualReplicas converge in the endCheapest, always availableCounters, likes, feeds, analytics, DNS

The CAP Theorem "C" is linearizability. Causal consistency is the strongest model that can stay available during a partition, which is why it's often the sweet spot for user-facing data.


Session guarantees: the cheap fixes users notice

Most "this app is buggy" complaints come down to four session promises:

You get most of them by sending a user's reads to the primary for a few seconds after they write, pinning a session to one replica, or carrying a "last seen version" token that a replica must have caught up to before it answers (Replication).


Making eventual consistency survivable

With eventual consistency, two replicas can accept conflicting writes. Something has to decide the final value:

  • Last-write-wins (LWW) is fine when overwriting really is the intent (a profile photo). It's wrong for counters, carts and sets. Clock skew also means the "later" write might not be the later one.
  • CRDTs (conflict-free replicated data types: counters, sets, maps, text) merge automatically and correctly. Collaborative editors and Riak use them, and Redis Enterprise's active-active mode too.
  • Application merge: keep both versions and let code or the user decide (Dynamo's shopping cart).

And for causal ordering like the story: attach the ID of what a write depends on (the reply carries the question's ID) and don't show it until its parent is visible.


Choosing, per feature


Cheat sheet

QuestionAnswer
Strongest modelLinearizable: acts like one copy
Strongest that stays available in a partitionCausal
"I saved it but don't see it"Read-your-writes
"It was there, now it's gone"Monotonic reads
Reply before the questionCausal violation. Carry dependency IDs.
Concurrent writes, eventual storeLWW (loses data), CRDT (merges), or app merge
Counters, likesCRDT counter or a single-writer aggregate
Balances, inventory at checkout, locksLinearizable only
CAP's C vs ACID's CLinearizability vs "constraints hold". Unrelated.

Say it in the interview

"I'd pick consistency per feature. The ledger and seat reservations are linearizable on a single leader. Comments and chat get causal ordering: a reply carries its parent's ID and isn't shown until the parent is. Users get read-your-writes on their own edits. Like counts are eventually consistent CRDT counters, so concurrent likes in different regions both count."


Go deeper