The Runtime Theory
Distributed Systems

Eventual Consistency Is a Spectrum

Strong, causal, read-your-writes — the consistency zoo and when each model is the right engineering choice.

The Runtime Theory Team4 min read#consistency#eventual-consistency#causal-consistency#distributed-systems
On this page

"Eventual consistency" is not one thing. It is the weakest point on a spectrum of consistency models, each with different guarantees, different costs, and different failure modes. Choosing the wrong model for your data is like choosing the wrong tool for the job — it works until it doesn't, and when it doesn't, the data corruption is silent, delayed, and painful to fix. This article walks the spectrum from strongest to weakest, with the trade-offs at each level.

The consistency spectrum

text
strongest ───────────────────────────────────────────── weakest
 
linearizable → sequential → causal → read-your-writes → monotonic-reads → eventual
   (strong)                                                  (weak)
   expensive                                                 cheap
   unavailable during partition                              available during partition

Each level relaxes a guarantee from the level above. The question is: which guarantee does your data actually need?

Linearizability (strong consistency)

Every operation appears to take effect atomically at some point between its invocation and response. All clients see the same order of operations.

text
Client A: write(x=1) ──────→ ok
Client B:              read(x) → 1    (must see the write)

Linearizability is the "gold standard" — it is what you expect from a single-process system. It requires consensus (Raft, Paxos) or synchronous replication, which means every write pays the cost of majority acknowledgment.

When to use it: financial transactions, unique constraint enforcement, leader election, distributed locks. Anywhere the correctness of the system depends on every node seeing the same value at the same time.

Cost: 2–3 RTTs per write (consensus). Unavailable during network partitions (CP behavior).

Sequential consistency

All operations appear in some total order that is consistent with the program order of each individual process, but the total order may not match real-time order.

text
Process A: write(x=1) → write(y=2)
Process B:                        read(y)=2 → read(x)=1

Sequential consistency allows Process B to see y=2 before x=1, even though Process A wrote x=1 first. The guarantee: the order respects each process's own program order. The violation: cross-process order is not real-time.

When to use it: collaborative editing, distributed data structures where per-process order matters but global real-time order doesn't.

Cost: cheaper than linearizability because it doesn't require real-time ordering. But it is still stronger than most applications need.

Causal consistency

Operations that are causally related (one operation's effect influences another) are seen in the same order by all nodes. Concurrent operations may be seen in different orders.

text
write(x=1) → write(y=x+1)      # causally related
read(x)=1, read(y)=2            # all nodes see this order
 
write(a=1) || write(b=2)        # concurrent (no causal link)
Node 1: a=1, b=2                # may see a first
Node 2: b=2, a=1                # may see b first

Causal consistency is the sweet spot for most distributed systems. It is strong enough to prevent the most confusing inconsistencies (you see the effect before the cause) but weak enough to allow high availability and low latency.

The implementation uses version vectors or vector clocks — metadata that tracks the causal history of each operation. When a node receives an operation, it checks the version vector to determine if it is causally dependent on any previous operations. If so, it ensures those operations are applied first.

When to use it: social media feeds, collaborative editing, distributed caches, shopping carts. Anywhere you need "if A happened before B, everyone sees A before B" but don't need real-time ordering of concurrent operations.

Cost: one extra round trip for version vector exchange. No consensus required. Available during partitions (AP behavior with causal ordering).

Read-your-writes consistency

A process always reads its own writes, even if other processes may see stale data.

text
Client A: write(x=1) → ok → read(x) → 1    (always)
Client B:                        read(x) → 0  (may be stale)

This is the minimum consistency model for most user-facing applications. A user who creates a post should always see it in their own feed. Other users may see it with a delay.

When to use it: user profiles, user-generated content, any data where the creator must see their own changes immediately.

Cost: requires session affinity (routing all requests from one user to the same replica) or read-repair (the replica checks if it has the latest write from this client before responding). Both are cheaper than consensus.

Monotonic reads

Once a client reads a value, it never sees an older value on subsequent reads.

text
Client A: read(x) → 1 → read(x) → 2    (never goes back to 0)

Without monotonic reads, a client might read from a replica that is behind, then read from a replica that is further behind, seeing the value "go backwards." This is confusing and breaks user interfaces.

When to use it: feeds, timelines, any data where "going backwards" is visually confusing.

Cost: requires the client to remember the timestamp or version of its last read and ensure subsequent reads are from a replica at least that current.

Eventual consistency

If no new updates are made, all replicas will eventually converge to the same value. "Eventually" is undefined — it could be milliseconds or hours.

text
Client A: write(x=1) → ok
Client B: read(x) → 0  (stale)
Client B: read(x) → 0  (still stale)
Client B: read(x) → 1  (converged)

Eventual consistency is the baseline guarantee of any asynchronous replication. It is the weakest meaningful consistency model — without it, replicas could diverge permanently.

When to use it: DNS, CDN caches, analytics, counters, any data where staleness is acceptable and correctness does not depend on ordering.

Cost: free. No extra coordination, no version vectors, no session affinity. The data may be stale, but the system is always available and always fast.

The engineering choice

The right consistency model is the weakest model that satisfies your correctness requirements:

Data typeRequired modelWhy
Financial balanceLinearizableMust prevent double-spending
User profileRead-your-writesUser must see their own edits
Social feedCausalPosts from the same thread must be ordered
Shopping cartSession guaranteesUser must see their own cart additions
Analytics countersEventualStaleness is acceptable
DNS recordsEventualPropagation delay is inherent
Leader electionLinearizableTwo leaders = data corruption

The mistake most systems make is defaulting to linearizability — the strongest, most expensive model — for all data. This makes the system slow, unavailable during partitions, and complex to operate. The other mistake is defaulting to eventual consistency — the weakest model — for data that requires ordering guarantees. This makes the system fast and available but introduces silent data corruption.