Skip to main content

Consistency models

A consistency model is a contract about what a read is allowed to return. It is not a quality setting, and "more consistent" is not "better" — every step up the ladder is paid for in latency, availability, or both.

First, disambiguate the word​

"Consistency" names two unrelated things, and conflating them causes real design errors.

The C in ACIDThe C in CAP
ScopeOne database, one transactionMany replicas of one value
MeansThe transaction leaves the DB satisfying its declared constraintsEvery read sees the latest write
Enforced byConstraints, triggers, the applicationReplication protocol

They are orthogonal. A single Postgres node gives you ACID-C and has no CAP-C problem, because there is nothing to replicate. This page is about the CAP sense. Consistency boundaries makes the prescriptive version of the same argument.

The three broad levels​

Weak consistency​

After a write, reads may or may not see it. No guarantee, no convergence promise.

Sounds useless, and is exactly right for anything where the next value supersedes the last: live video, VoIP, real-time multiplayer position updates. If a packet is lost there is no point replaying it — by the time it arrives it is wrong. Memcached behaves this way by design.

Eventual consistency​

Reads may be stale, but in the absence of new writes, all replicas converge. The staleness window is typically milliseconds.

This is the default for high-availability systems: DNS, S3, Cassandra, most caches and search indexes. It is what AP means in practice.

Eventual consistency is where the surprising bugs live, because "eventually" permits sequences that look impossible to a user:

  • Write a comment, refresh, comment is gone.
  • See a reply before the message it replies to.
  • Read a value, read again, get an older value.

Which is why the useful vocabulary is finer than three levels.

Strong consistency​

Every read reflects all writes that completed before it. The system behaves as if there were one copy. Formally, linearizability.

This is what a quorum protocol buys you: Raft, VSR, etcd, ZooKeeper, Spanner. The price is a round trip to a quorum on every operation, and unavailability of the minority side during a partition — see CAP.

The session guarantees that actually matter​

Most user-visible weirdness is fixed without going all the way to linearizability. These are cheap, and worth naming explicitly in a design:

GuaranteePromiseFixes
Read-your-writesYou always see your own writes"I posted it and it vanished"
Monotonic readsYou never see time go backwardsRefresh showing older data
Monotonic writesYour writes apply in the order you made themEdits landing out of order
Consistent prefixYou never see an effect before its causeReply appearing before the message

Read-your-writes plus monotonic reads covers the large majority of complaints, and both are usually implementable by pinning a user's session to one replica, or by routing that user's reads to the primary for a few seconds after a write. Neither requires consensus.

Choosing​

The question is never "how consistent should the system be". It is which invariant, and what does a violation of it cost:

  • Violation costs money or is legally binding → strong. Ledger balances, inventory, seat allocation.
  • Violation is visible to one user and confusing → eventual, plus the session guarantee that removes the confusion.
  • Violation is invisible or immediately superseded → weak. Metrics, presence, live feeds.

Different fields of the same record can sit in different rows of that table, and usually should.

Sources​