linearizability, serializability and eventual consistency
Linearizability, Serializability and Eventual Consistency
Understand three guarantees that are routinely confused, what each actually promises, why two of them are orthogonal rather than comparable, and which one your system genuinely requires.
Prerequisites
Recommended Knowledge
- Transactions and isolation levels
- ACID properties in relational databases
- Replication and replica lag
- Quorum reads and writes
- CAP and PACELC trade-offs
- Concurrency and race conditions
- Conflict resolution strategies
- Partial failure and timeout ambiguity
Two Different Questions
The persistent confusion between these models dissolves once you recognize that linearizability and serializability answer entirely separate questions. They are not points on one scale.
| Model | Question Answered | Domain |
|---|---|---|
| Linearizability | Do I see the most recent value? | Single object, real-time recency |
| Serializability | Did concurrent transactions behave as if sequential? | Multiple objects, transaction ordering |
| Eventual consistency | Will replicas converge if writes stop? | Replica convergence over time |
Ordering Axis Serializability
Linearizability
Linearizability makes a replicated system behave as though only one copy of the data exists. Every operation appears to take effect instantaneously at some point between its invocation and its response.
Simple Analogy
An announcement over a public address system. Once it is made, everyone in the building has heard it. Nobody can walk into a room and receive the previous announcement instead.
The Recency Guarantee
The essential property is real-time ordering. If a write completes before a read begins, that read must observe the written value or something newer, regardless of which replica serves it.
| Scenario | Linearizable Behavior |
|---|---|
| Write completes, then read begins | Read must see the write |
| Two reads after the same write | Both see the written value |
| Read after another client's read saw a value | Cannot see an older value |
| Read overlapping an in-flight write | May see old or new, but consistently thereafter |
Where It Is Genuinely Required
Operations Needing Linearizability
- Distributed locks and leases
- Leader election and membership
- Uniqueness constraints such as username claims
- Compare-and-set operations
- Coordination flags between services
- Fencing tokens protecting shared resources
Serializability
Serializability concerns transactions rather than individual reads. It guarantees that concurrent transactions produce a result equivalent to executing them one after another in some order.
Simple Analogy
Several shoppers are served at overlapping times, but the final receipts are consistent with having served them one at a time. The order chosen need not match who arrived first.
Anomalies It Prevents
| Anomaly | Description | Example Consequence |
|---|---|---|
| Dirty read | Reading uncommitted data | Acting on a change that rolls back |
| Non-repeatable read | Same row differs within a transaction | Inconsistent calculations |
| Phantom read | New rows appear matching a prior query | Aggregates disagree with detail |
| Lost update | One write silently overwrites another | Concurrent edits vanish |
| Write skew | Two transactions each valid, jointly invalid | A shared invariant is broken |
Write Skew Deserves Attention
Write skew is the anomaly that snapshot isolation permits and serializability prevents. Each transaction reads a valid state, writes a different row, and the combination violates a constraint neither transaction could observe alone.
-- Invariant: at least one doctor must remain on call
-- Transaction A
BEGIN;
SELECT COUNT(*) FROM on_call
WHERE shift_id = 42 AND is_on_call = TRUE; -- returns 2
UPDATE on_call SET is_on_call = FALSE
WHERE doctor_id = 101 AND shift_id = 42;
COMMIT;
-- Transaction B, running concurrently
BEGIN;
SELECT COUNT(*) FROM on_call
WHERE shift_id = 42 AND is_on_call = TRUE; -- also returns 2
UPDATE on_call SET is_on_call = FALSE
WHERE doctor_id = 102 AND shift_id = 42;
COMMIT;
-- Result: zero doctors on call, invariant violated
Comparing the Two Directly
| Property | Linearizability | Serializability |
|---|---|---|
| Scope | A single object | Multiple objects in a transaction |
| Guarantee type | Recency | Ordering equivalence |
| Real-time ordering | Required | Not required |
| Multi-object invariants | Not addressed | Protected |
| Stale reads | Prevented | Permitted |
| Typical origin | Distributed systems literature | Database theory |
| Usual mechanism | Consensus or strict quorum | Locking or optimistic validation |
Serializable but Not Linearizable
- Transactions are correctly ordered
- A read may still return stale data
- Committed writes may not yet be visible
- Common in snapshot-based implementations
Linearizable but Not Serializable
- Each key read returns the latest value
- Multi-key invariants remain unprotected
- Write skew is still possible
- Typical of key-value stores
Strict Serializability
Combining both yields strict serializability: transactions behave as if executed serially, and that serial order respects real time. It is the strongest practical guarantee.
| Guarantee | Ordering Correct | Reads Current | Relative Cost |
|---|---|---|---|
| Strict serializability | Yes | Yes | Highest |
| Serializability | Yes | Not guaranteed | High |
| Linearizability | Single object only | Yes | High |
| Snapshot isolation | Mostly, write skew possible | Consistent snapshot | Moderate |
| Eventual consistency | No | No | Lowest |
Eventual Consistency
Eventual consistency promises only convergence: if updates cease, all replicas will eventually reach the same state. It makes no statement about when, or what is returned meanwhile.
Anomalies It Permits
| Anomaly | What the User Sees | Mitigating Guarantee |
|---|---|---|
| Stale read | An outdated value | Bounded staleness |
| Missing own write | Their update appears lost | Read-your-writes |
| Time moving backwards | Newer value, then older value | Monotonic reads |
| Causal violation | A reply before the original message | Causal consistency |
| Divergent replicas | Different answers per request | Sticky routing |
| Lost write on conflict | A valid update disappears | Version vectors or CRDTs |
Causal Consistency
Causal consistency occupies valuable middle ground. It preserves the order of causally related operations while allowing concurrent operations to be seen in any order.
| Relationship | Ordering Enforced | Example |
|---|---|---|
| One operation reads another's result | Yes | Reply after the original comment |
| Same client, sequential operations | Yes | Edit after create |
| Transitively related operations | Yes | A precedes B precedes C |
| Genuinely concurrent operations | No | Two unrelated posts |
The Full Hierarchy
| Model | Key Property | Coordination Required |
|---|---|---|
| Strict serializability | Serial order matching real time | Consensus on every transaction |
| Linearizability | Real-time recency per object | Consensus or strict quorum |
| Sequential consistency | Common order, not real-time | Global agreement on order |
| Causal consistency | Causally related order preserved | Dependency tracking only |
| Session guarantees | Per-client coherence | Client-side version tracking |
| Eventual consistency | Convergence if writes stop | Background replication |
Implementing Session Guarantees
class SessionContext {
constructor(sessionId) {
this.sessionId = sessionId;
this.observedVersions = new Map();
}
recordWrite(key, version) {
const current = this.observedVersions.get(key) ?? 0;
this.observedVersions.set(key, Math.max(current, version));
}
requiredVersion(key) {
return this.observedVersions.get(key) ?? 0;
}
}
async function sessionAwareRead(key, session) {
const required = session.requiredVersion(key);
const local = await datastore.readLocalReplica(key);
if (local.version >= required) {
session.recordWrite(key, local.version);
return { value: local.value, path: "local" };
}
const quorum = await datastore.readQuorum(key);
session.recordWrite(key, quorum.version);
return { value: quorum.value, path: "quorum-escalation" };
}
Tracking observed versions per session delivers read-your-writes and monotonic reads while serving most requests from a fast local replica.
Selecting a Model Per Operation
| Operation | Required Model | Reasoning |
|---|---|---|
| Distributed lock acquisition | Linearizability | Two holders corrupt the resource |
| Username uniqueness | Linearizability | Duplicates cannot be merged |
| Fund transfer | Strict serializability | Multi-account invariant plus recency |
| Inventory reservation | Serializability | Prevents write skew on stock counts |
| Shopping cart | Causal with session guarantees | User must see their own additions |
| Comment thread | Causal consistency | Replies must follow their parent |
| Product catalogue | Eventual consistency | Brief staleness is harmless |
| View counter | Eventual consistency | Approximate values are acceptable |
| Analytics events | Eventual consistency | Volume outweighs individual accuracy |
const CONSISTENCY_MODEL = {
"lock.acquire": "linearizable",
"username.claim": "linearizable",
"funds.transfer": "strict-serializable",
"inventory.reserve": "serializable",
"cart.read": "session",
"comments.list": "causal",
"catalog.read": "eventual",
"counter.increment": "eventual"
};
function requiredModel(operation) {
const model = CONSISTENCY_MODEL[operation];
if (!model) {
throw new Error(
`Operation ${operation} has no declared consistency model`
);
}
return model;
}
The Cost of Each Model
| Model | Write Path Cost | Availability During Partition |
|---|---|---|
| Strict serializability | Consensus plus conflict checking | Minority side unavailable |
| Linearizability | Quorum round trip | Minority side unavailable |
| Serializability | Locking or validation overhead | Depends on implementation |
| Causal consistency | Dependency metadata only | Remains available |
| Session guarantees | Occasional read escalation | Remains available |
| Eventual consistency | Local acknowledgement | Remains available |
Frequent Misunderstandings
| Claim | Correction |
|---|---|
| "Serializable implies linearizable" | Serializable reads may still return stale data |
| "Linearizable implies serializable" | Single-object recency does not protect multi-object invariants |
| "The C in ACID means CAP consistency" | ACID consistency means invariants hold, nothing about replication |
| "Eventual means a short delay" | No bound is guaranteed unless staleness is explicitly bounded |
| "Repeatable read prevents all anomalies" | Phantom reads and write skew remain possible |
| "Snapshot isolation is serializable" | It permits write skew, which serializability prevents |
| "Strong consistency is a defined term" | It is marketing language with no formal meaning |
Verifying Consistency Claims
Consistency violations are rare, timing-dependent, and invisible in ordinary testing. They require deliberate verification.
Verification Approaches
- Record operation histories and check linearizability
- Run concurrent workloads that violate an invariant if unordered
- Inject partitions during active writes
- Introduce clock skew between nodes
- Test write skew patterns explicitly
- Measure staleness by comparing replica versions
- Assert invariants continuously during load
- Verify session guarantees survive replica failover
describe("inventory serializability", function () {
it("prevents overselling under concurrency", async function () {
await inventory.set("sku-501", 1);
const attempts = Array.from({ length: 20 }, () =>
inventory.reserve("sku-501", 1).catch(() => null)
);
const results = await Promise.all(attempts);
const succeeded = results.filter(Boolean).length;
const remaining = await inventory.get("sku-501");
expect(succeeded).toBe(1);
expect(remaining).toBe(0);
});
});
Monitoring Consistency
Signals Worth Tracking
- Replica lag distribution across the fleet
- Stale reads detected by version comparison
- Session-guarantee escalations to quorum
- Transaction abort rate from conflict detection
- Retry rate on optimistic concurrency failures
- Conflicts requiring resolution after partitions
- Invariant violations detected by background audit
- Latency separated by consistency level
- Clock skew between nodes
Common Design Mistakes
Weak Reasoning
- Treating the models as one ordered scale
- Assuming serializability prevents stale reads
- Assuming linearizability protects invariants
- Accepting "strong consistency" without definition
- Relying on snapshot isolation against write skew
- Applying one model across the entire system
- Treating eventual as a brief delay
- Never testing under concurrency
- Ignoring session-level anomalies
Strong Reasoning
- Separates recency from ordering concerns
- Names the exact guarantee required
- Identifies invariants spanning objects
- Verifies vendor claims against definitions
- Tests write skew explicitly
- Assigns a model per operation
- Bounds staleness where it matters
- Runs concurrent correctness tests
- Uses session guarantees for user-facing reads
System Design Interview Discussion
| Question | What Your Answer Should Cover |
|---|---|
| How do these models differ? | Recency versus ordering as separate axes |
| Can you have one without the other? | Concrete examples in both directions |
| What is write skew? | Snapshot isolation gap and its consequence |
| Which does this operation need? | Invariant analysis rather than a default |
| What does eventual actually guarantee? | Convergence only, with permitted anomalies |
| Why is causal consistency notable? | Strongest model available during partitions |
| How would you verify the guarantee? | History checking and invariant assertions |
| What does each model cost? | Coordination on the write path |
Design Checklist
Production Checklist
- Declare a consistency model per operation
- Identify invariants spanning multiple objects
- Reserve linearizability for coordination primitives
- Use serializability where invariants must hold
- Verify the isolation level your database provides
- Test for write skew explicitly
- Apply session guarantees to user-facing reads
- Consider causal consistency before full ordering
- Bound staleness where unbounded is unacceptable
- Implement conflict resolution for eventual operations
- Avoid last-writer-wins for meaningful data
- Disclose the applied guarantee in responses
- Monitor replica lag distribution
- Audit business invariants in the background
- Run concurrency tests in continuous integration
Knowledge Check
Why are linearizability and serializability orthogonal?
One constrains recency for a single object, the other constrains ordering across transactions. Neither implies the other.
What is write skew?
Two transactions each read a valid state and write different rows, jointly violating an invariant neither could observe alone. Snapshot isolation permits it.
What does eventual consistency guarantee?
Only that replicas converge if updates stop. It places no bound on staleness and permits several user-visible anomalies.
What makes causal consistency valuable?
It preserves the ordering users actually perceive while remaining available during partitions, since it requires no write-path coordination.
What is strict serializability?
Serializability whose chosen serial order also respects real time, combining transaction correctness with recency.
Summary
Linearizability and serializability are commonly confused because both are described as strong, yet they constrain different things. Linearizability is a recency guarantee for a single object, ensuring reads never return a value older than a completed write. Serializability is an ordering guarantee across transactions, ensuring concurrent execution is equivalent to some serial order.
Neither implies the other. A serializable system may return stale data, and a linearizable key-value store may still permit write skew across keys. Strict serializability combines both and is the strongest practical guarantee, at correspondingly high cost.
Eventual consistency promises only convergence when writes cease, permitting stale reads, missing own writes, time moving backwards, and causal violations. Session guarantees address the anomalies users actually notice at modest cost, and causal consistency is the strongest model that remains available during a network partition.
The practical approach is to identify which invariants matter, assign a model per operation, verify what your database actually provides rather than what marketing claims, and test concurrency deliberately because these violations are invisible under sequential testing.
Key Takeaway
Recency and ordering are separate problems. Ask whether an operation needs the latest value, needs multi-object invariants preserved, or needs both. Reserve the strongest models for coordination and money, reach for causal consistency and session guarantees for user-facing reads, and verify the guarantee rather than trusting the label.