Distributed systems
Choosing a consistency model per feature
Real systems mix models. For each piece of data, ask what it costs when a reader acts on a stale value, then pick the cheapest model that avoids that cost.
No single consistency model fits a whole product. A bank balance and a like count need different guarantees. The useful question for each piece of data is: what does it cost when a reader acts on a stale value?
The big idea
Ask the question per entity, not per system. "Do we need strong consistency?" has no good answer. "Does a stale seat count let two people book seat 14C?" does.
The answers usually sort into three groups:
- Linearizable: stale reads cause a wrong decision. Balances, seats, usernames.
- Causal or read-your-writes: users notice staleness in their own actions. Comment threads, profile edits.
- Eventual: approximate values are fine. Likes, feeds, analytics.
| Feature | Model | Why |
|---|---|---|
| Account balance, ledger | Linearizable | A stale read can approve an overdraft |
| Seat reservation | Linearizable on the seat | Two buyers must not both get 14C |
| Username uniqueness | Linearizable | Two signups must not claim one handle |
| Editing your own profile | Read-your-writes | You notice the stale value; others do not |
| Comment threads | Causal | Replies must not appear before their parents |
| Like or view counts | Eventual | 1,203 vs 1,207 harms nobody |
Walking through it
A post gets 5,000 likes per second during a spike. If each like is a linearizable increment on one row, every increment queues on that row's leader. At 2 ms per serialized increment, the ceiling is 1,000 / 2 = 500 per second. That is 10 times too slow.
Make the count eventual instead. Twenty app servers buffer their likes and flush one delta per second:
Per server: 5,000 / 20 = 250 likes per second, sent as one write of +250
Database: 20 writes per second for this post, instead of 5,000
Readers: see a count up to about one second oldThat is fine for likes. It would be wrong for a bank balance.
For read-your-writes on Postgres, record the WAL position (LSN) of each user's last write. Read from a replica only when its replayed position has reached that LSN. Otherwise read from the primary. Do not fix this with a sleep.
Common mistakes
- Choosing one model for the whole system. Walk through the entities and assign a model to each.
- Using strong reads everywhere. On DynamoDB, a strongly consistent read costs twice the read capacity. That adds up on a hot table.
- Sharding an inventory counter and assuming no overselling. Each shard can go negative on its own, so the invariant breaks.
Check yourself
- Why is a seat reservation linearizable while a like count is eventual? A stale seat read can sell the same seat twice. A stale like count is off by a few numbers and nobody is harmed.
- Why not fix read-your-writes with a
sleepafter each write? A sleep is a guess about replication lag. It fails when lag spikes, and it slows every write.
Key takeaways
- Ask what a stale value costs, per entity, before choosing a model.
- Strong consistency belongs in a small core: ledgers, inventory, uniqueness.
- Eventual consistency is fine for counts, feeds and analytics, which can be derived from the core.
- Name the model in design reviews, for example "linearizable on the seat, read-your-writes for the cart".
Further learning
Strong consistency usually needs a consensus protocol underneath. See Consensus and Raft for how that works.
For a worked case where seats must not be sold twice, see the ticket booking case study.
Related
CAP, PACELC and consistency models
What "consistent" means once data lives on several replicas, from linearizable to eventual, what each guarantee costs, and how to pick one per feature.
Causal and session guarantees
Weaker promises than linearizability that still fix the bugs users notice. Causal consistency keeps related events in order, and session guarantees protect one client's view.
Case study: ticket booking
Ticketmaster-style inventory under extreme contention, with holds that expire, a virtual waiting room and atomic seat commits so one seat is never sold twice.