Three unrelated things called "consistency"
Clear this up first, because the overloading causes genuine confusion:
- The C in ACID — the database enforces your declared constraints. This is about integrity rules, and it's mostly the application's job.
- The C in CAP — specifically linearizability. See CAP.
- Consistency models — the subject of this lesson: which orderings of operations a system may expose to readers.
They are not the same thing and don't imply one another. A system can be ACID-consistent and give you stale reads all day.
The two axes
Most confusion dissolves once you see that "strong consistency" is really two separate properties:
| Single object | Multiple objects | |
|---|---|---|
| Real-time order matters | Linearizability | Strict serializability |
| Any order will do | Sequential consistency | Serializability |
- Linearizability is about one object and real time: once a write completes, every subsequent read returns it. It's a recency guarantee.
- Serializability is about transactions over many objects: the result is equivalent to some serial order — not necessarily the real-time one. A serializable database may execute your transaction as though it ran an hour ago.
- Strict serializability is both, and it's what Spanner provides.
The strong models
Linearizability. The system behaves as if there is a single copy of the data and every operation takes effect atomically at some instant between its invocation and its response. Consequences: no stale reads, and every client sees changes in the same order at the same time.
The cost is unavoidable: to guarantee no stale read, the node answering must confirm with others that it isn't behind — a round trip to a quorum, at minimum. Linearizability's price floor is the network round-trip time, and it's why it becomes expensive across regions and impossible during a partition.
Sequential consistency. All operations appear in some single total order that respects each client's own program order — but not necessarily real time. If I write and then phone you and you read, you might still see the old value. Weaker, cheaper, and rarely offered explicitly.
The weak models
Causal consistency. Operations causally related (in the happens-before sense from clocks) are seen in the same order by everyone. Concurrent operations may be seen in different orders by different observers.
This one deserves emphasis, because of a genuinely important theoretical result:
Causal consistency gives you things users actually notice: replies never appear before the message they answer, and an unfriend-then-post sequence isn't reordered so the post is visible to the person you just removed.
Eventual consistency. If writes stop, replicas eventually converge. That is the entire guarantee. It says nothing about when, and nothing about what you see in the meantime — including values going backwards. Useful, and much weaker than most people assume when they choose it.
The client-centric guarantees
Between causal and eventual sits a set of session guarantees — cheap, targeted promises that fix specific user-visible weirdness. These are what you actually reach for in practice:
- Read-your-own-writes — you always see your own updates. Fixes the classic "I saved it and it's gone" bug.
- Monotonic reads — you never see time run backwards. Fixes refreshing and losing data you just saw.
- Monotonic writes — your own writes apply in the order you issued them.
- Consistent prefix reads — you never see an effect before its cause.
These are covered mechanically in the replication lesson. The point here is architectural: you can buy them individually and cheaply, usually by routing a session to a consistent replica or tracking a version token — without paying for linearizability across the whole system.
The hierarchy
From strongest and most expensive to weakest and cheapest:
Strict serializability (Spanner)
↓
Linearizability (etcd, ZooKeeper, single-leader reads)
↓
Sequential consistency
↓
Causal consistency ← strongest available under partition
↓
Session guarantees (read-your-writes, monotonic reads)
↓
Eventual consistency (Dynamo-style defaults, DNS)
Each step down removes coordination, and therefore removes latency and adds availability.
What real systems give you
| System | Default | Available on request |
|---|---|---|
| etcd / ZooKeeper | Linearizable writes | Linearizable reads (ZK reads are not, without sync) |
| Postgres (primary) | Read Committed, linearizable per connection | Serializable |
| Postgres read replica | Eventual (async) | Route to primary |
| DynamoDB | Eventually consistent reads | ConsistentRead=true |
| Cassandra | Tunable per query | QUORUM/ALL |
| MongoDB | Causal within a session | readConcern: majority/linearizable |
| Spanner | Strict serializability | Stale reads for speed |
Note how many are tunable per operation. That's the practical takeaway: consistency is a per-request decision, not a system-wide property.
Choosing
Work backwards from the consequence of being wrong:
- A stale read causes financial or safety harm — money movement, inventory at point of sale, permission revocation, uniqueness. Linearizable, and accept unavailability during a partition.
- A stale read is confusing but harmless — profile, feed, counts, search results. Causal or session guarantees, served from a nearby replica.
- A stale read is invisible — analytics, recommendations, trending. Eventual.
Then, crucially: most systems are mostly the third and second categories, with a small critical core in the first. Designing everything to the standard of the critical core is the most common way to make a system needlessly slow and fragile.
What to take away
- "Consistency" means three unrelated things; disambiguate before answering.
- Linearizability = single object + real time. Serializability = transactions + some order. Strict serializability = both.
- Linearizability's price floor is a network round trip, which is why distance makes it expensive and partitions make it impossible.
- Causal consistency is the strongest model available while remaining available.
- Session guarantees fix most user-visible anomalies cheaply and individually.
- Consistency is chosen per operation. Most operations don't need the strongest setting.
Check yourself
-
A database is serializable. Can a transaction read stale data?
Serializability constrains the outcome to match some serial execution, but says nothing about which one, so a transaction may be ordered as though it ran earlier and read older values. Adding the real-time requirement gives strict serializability, which is what Spanner provides.
-
What is the strongest consistency model a system can provide while remaining available during a network partition?
Anything stronger than causal consistency requires coordination between replicas, which a partition prevents by definition. Causal consistency is a proven ceiling, which makes it a much more interesting target than plain eventual consistency for available systems.
-
Users complain that after saving their profile, a refresh sometimes shows the old value. What is the cheapest correct fix?
The anomaly is specific and session-scoped, so the fix should be too: route that user's reads to the leader or to a replica known to be caught up past their write. Making the whole system linearizable buys a global guarantee at global cost to solve one local symptom.
-
Why does linearizability have a latency floor equal to a network round trip?
Linearizability forbids stale reads, so the responding node must verify it is not behind — which means communicating with a quorum of peers. That check costs at least one round trip, so the guarantee gets more expensive as replicas get further apart and impossible when they are unreachable.