Consistency Models
Understanding consistency models is fundamental to designing distributed systems. This module covers the entire consistency spectrum, from the strongest (linearizability) to the weakest (eventual consistency).Module Duration: 12-16 hours
Key Topics: Linearizability, Serializability, Causal Consistency, Eventual Consistency, Session Guarantees
Interview Focus: Trade-offs between consistency levels, real-world examples
Key Topics: Linearizability, Serializability, Causal Consistency, Eventual Consistency, Session Guarantees
Interview Focus: Trade-offs between consistency levels, real-world examples
The Consistency Spectrum
Copy
┌─────────────────────────────────────────────────────────────────────────────┐
│ CONSISTENCY SPECTRUM │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ STRONGEST ◄──────────────────────────────────────────────► WEAKEST │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │Linearizable │ │ Sequential │ │ Causal │ │ Eventual │ │
│ │ │ │ Consistency │ │ Consistency │ │ Consistency │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ▲ ▲ ▲ ▲ │
│ │ │ │ │ │
│ Real-time Global order Preserves Eventually │
│ ordering (some order) causality converges │
│ │
│ ──────────────────────────────────────────────────────────────────────── │
│ TRADE-OFF: │
│ ──────────────────────────────────────────────────────────────────────── │
│ │
│ Consistency ─────────────────────────────────────────► Higher │
│ Availability ◄───────────────────────────────────────── Lower │
│ Latency ─────────────────────────────────────────► Higher │
│ Throughput ◄───────────────────────────────────────── Lower │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Linearizability (Strict Consistency)
The Gold Standard: Linearizability is the strongest single-object consistency model. Systems behave as if there’s a single copy of data.
Definition
Copy
┌─────────────────────────────────────────────────────────────────────────────┐
│ LINEARIZABILITY │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ DEFINITION: │
│ ─────────── │
│ Every operation appears to execute instantaneously at some point │
│ between its invocation and response (linearization point). │
│ │
│ PROPERTIES: │
│ ─────────── │
│ 1. Operations are atomic (happen at a single point in time) │
│ 2. Real-time ordering is preserved │
│ 3. All clients see the same order of operations │
│ │
│ EXAMPLE - Linearizable: │
│ ──────────────────────── │
│ Time ────────────────────────────────────────────────────► │
│ │
│ Client A: [──write(x=1)──] │
│ ↓ linearization point │
│ Client B: [──read(x)──] → returns 1 ✓ │
│ │
│ After A's write completes, B must see x=1 │
│ │
│ EXAMPLE - NOT Linearizable: │
│ ────────────────────────── │
│ Time ────────────────────────────────────────────────────► │
│ │
│ Client A: [──write(x=1)──] │
│ Client B: [──read(x)──] → returns 0 ✗ │
│ Client C: [──read(x)──] → returns 1 │
│ │
│ B reads after A completes but sees old value - VIOLATION! │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Real-World Linearizable Systems
- Zookeeper
- etcd
- Google Spanner
Copy
Linearizable writes:
- All writes go through the leader
- Leader assigns sequential zxid
- Write is linearized when majority acknowledge
Reads:
- sync() + read for linearizable reads
- Regular reads may be stale (sequential consistency)
Copy
Fully linearizable:
- Uses Raft for consensus
- Reads and writes go through leader
- linearizable_read option for guaranteed fresh reads
Trade-off: Higher latency for reads
Copy
External consistency (stronger than linearizable):
- Uses TrueTime for global ordering
- Commit-wait protocol
- Even cross-datacenter transactions are linearizable
Trade-off: GPS/atomic clock infrastructure required
Cost of Linearizability
Copy
┌─────────────────────────────────────────────────────────────────────────────┐
│ COST OF LINEARIZABILITY │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ LATENCY: │
│ ──────── │
│ - Writes must be acknowledged by majority │
│ - Reads may need to contact leader or do sync │
│ - Cross-region: 50-200ms per operation │
│ │
│ AVAILABILITY: │
│ ───────────── │
│ - Network partition → one side cannot make progress │
│ - Leader failure → election delay (seconds) │
│ - CAP theorem: Cannot have C and A during partition │
│ │
│ THROUGHPUT: │
│ ─────────── │
│ - All operations serialized through leader │
│ - Consensus overhead per write │
│ - Read scalability limited without compromising consistency │
│ │
│ WHEN TO USE: │
│ ───────────── │
│ ✓ Leader election │
│ ✓ Distributed locks │
│ ✓ Unique ID generation │
│ ✓ Configuration management │
│ ✓ Financial transactions │
│ │
│ WHEN TO AVOID: │
│ ────────────── │
│ ✗ High-throughput read-heavy workloads │
│ ✗ Geographically distributed with low-latency requirements │
│ ✗ Systems where availability is paramount │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Sequential Consistency
Definition and Examples
Copy
┌─────────────────────────────────────────────────────────────────────────────┐
│ SEQUENTIAL CONSISTENCY │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ DEFINITION: │
│ ─────────── │
│ - Operations from each client appear in program order │
│ - All clients see the SAME global order │
│ - BUT: Order may not respect real-time │
│ │
│ DIFFERENCE FROM LINEARIZABLE: │
│ ───────────────────────────── │
│ │
│ Linearizable: Real-time order matters │
│ Sequential: Only program order per client matters │
│ │
│ EXAMPLE - Sequentially Consistent but NOT Linearizable: │
│ ───────────────────────────────────────────────────────── │
│ │
│ Real-time: │
│ Client A: write(x=1) ──────────────────────────────────── │
│ Client B: ──────────────────── read(x) → 0 │
│ │
│ Possible sequential order: B.read(x), A.write(x=1) │
│ This is valid because B's read started before A's write completed! │
│ │
│ For LINEARIZABILITY: B must see x=1 if read starts after write ends │
│ │
│ USE CASES: │
│ ─────────── │
│ - Multi-core CPU memory models │
│ - Zookeeper reads (without sync) │
│ - Some distributed databases │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Serializability
Database Focus: Serializability is about transactions, not individual operations. It’s the isolation property in ACID.
Definition
Copy
┌─────────────────────────────────────────────────────────────────────────────┐
│ SERIALIZABILITY │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ DEFINITION: │
│ ─────────── │
│ Transactions appear to execute in SOME serial order. │
│ The actual order may differ from real-time order. │
│ │
│ EXAMPLE: │
│ ───────── │
│ T1: R(A) W(A) Concurrent execution: │
│ T2: R(A) W(A) │
│ T1: ──R(A)────────W(A)── │
│ T2: ────────R(A)────────W(A) │
│ │
│ Serializable if equivalent to: T1→T2 or T2→T1 │
│ │
│ SERIALIZABLE vs LINEARIZABLE: │
│ ───────────────────────────── │
│ ┌────────────────┬──────────────────┬──────────────────┐ │
│ │ │ Linearizable │ Serializable │ │
│ ├────────────────┼──────────────────┼──────────────────┤ │
│ │ Scope │ Single object │ Multi-object txn │ │
│ │ Real-time │ Yes │ No │ │
│ │ Ordering │ Real-time │ Any serial order │ │
│ │ Domain │ Distributed sys │ Databases │ │
│ └────────────────┴──────────────────┴──────────────────┘ │
│ │
│ STRICT SERIALIZABILITY: │
│ ──────────────────────── │
│ = Serializable + Linearizable │
│ = Transactions respect real-time order │
│ = What Spanner provides │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Isolation Levels
Copy
┌─────────────────────────────────────────────────────────────────────────────┐
│ SQL ISOLATION LEVELS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ WEAKEST ◄─────────────────────────────────────────────► STRONGEST │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Read │ │ Read │ │ Repeatable │ │ Serializable│ │
│ │ Uncommitted │ │ Committed │ │ Read │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ANOMALIES PREVENTED: │
│ ───────────────────── │
│ ┌─────────────────────┬───────┬───────┬───────┬───────────────┐ │
│ │ Anomaly │ RU │ RC │ RR │ Serializable │ │
│ ├─────────────────────┼───────┼───────┼───────┼───────────────┤ │
│ │ Dirty Read │ ✗ │ ✓ │ ✓ │ ✓ │ │
│ │ Non-repeatable Read │ ✗ │ ✗ │ ✓ │ ✓ │ │
│ │ Phantom Read │ ✗ │ ✗ │ ✗ │ ✓ │ │
│ │ Write Skew │ ✗ │ ✗ │ ✗ │ ✓ │ │
│ └─────────────────────┴───────┴───────┴───────┴───────────────┘ │
│ │
│ DIRTY READ: │
│ ──────────── │
│ T1: W(x=10) ← not committed │
│ T2: R(x)=10 ← reads uncommitted data │
│ T1: ROLLBACK ← T2 has phantom data! │
│ │
│ WRITE SKEW: │
│ ──────────── │
│ Constraint: x + y >= 0 │
│ Initial: x=5, y=5 │
│ T1: if (x+y >= 5) then x = x - 5 │
│ T2: if (x+y >= 5) then y = y - 5 │
│ Both read x+y=10, both proceed, result: x=0, y=0, violates constraint! │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Snapshot Isolation
Copy
┌─────────────────────────────────────────────────────────────────────────────┐
│ SNAPSHOT ISOLATION (SI) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ HOW IT WORKS: │
│ ───────────── │
│ 1. Transaction sees consistent snapshot from start time │
│ 2. Writes are buffered │
│ 3. At commit: check for write-write conflicts │
│ 4. First-committer-wins for conflicts │
│ │
│ EXAMPLE: │
│ ───────── │
│ Timeline: ──────────────────────────────────────► │
│ │
│ T1 start: T1 sees snapshot at t=0 │
│ ↓ │
│ T1: R(A=100) R(B=50) ─────────────────── W(A=90) COMMIT │
│ │
│ T2: R(A=100) R(B=50) W(B=40) COMMIT │
│ ↑ │
│ T2 sees snapshot at t=1 │
│ │
│ No conflict! T1 writes A, T2 writes B │
│ Final: A=90, B=40 │
│ │
│ WRITE SKEW STILL POSSIBLE: │
│ ────────────────────────── │
│ Both transactions read same data, write different rows │
│ No write-write conflict detected! │
│ │
│ SERIALIZABLE SNAPSHOT ISOLATION (SSI): │
│ ──────────────────────────────────────── │
│ Detects read-write conflicts too │
│ Aborts transactions that would cause anomalies │
│ Used by: PostgreSQL, CockroachDB │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Causal Consistency
Definition and Intuition
Copy
┌─────────────────────────────────────────────────────────────────────────────┐
│ CAUSAL CONSISTENCY │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ DEFINITION: │
│ ─────────── │
│ If operation A causally precedes operation B, │
│ then all nodes see A before B. │
│ │
│ CAUSALITY RULES: │
│ ──────────────── │
│ 1. Program order: In same thread, A before B → A causes B │
│ 2. Message passing: Send before receive → Send causes receive │
│ 3. Transitivity: A→B and B→C implies A→C │
│ │
│ EXAMPLE - Causally Consistent: │
│ ─────────────────────────────── │
│ │
│ Alice posts: "I got the job!" │
│ Bob (seeing Alice's post): "Congratulations!" │
│ │
│ Carol must see Alice's post before Bob's reply (causal order) │
│ Carol may see unrelated posts in any order (concurrent = no causal order) │
│ │
│ CAUSALLY RELATED vs CONCURRENT: │
│ ──────────────────────────────── │
│ │
│ Client A: W(x=1) ──────────────────────────── │
│ ↘ │
│ Client B: R(x=1) ── W(y=2) │
│ ↓ causally related (B read A's write) │
│ │
│ Client A: W(x=1) ──────────────────────────── │
│ Client B: W(y=2) ──────────────────────────── │
│ ↑ concurrent (no communication) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Implementing Causal Consistency
Copy
# Vector Clock Implementation for Causal Ordering
class VectorClock:
"""
Vector clocks track causality in distributed systems.
Each node maintains a vector of logical clocks.
"""
def __init__(self, node_id: str, num_nodes: int):
self.node_id = node_id
self.clock = {f"node_{i}": 0 for i in range(num_nodes)}
def increment(self):
"""Called before local operation."""
self.clock[self.node_id] += 1
return self.copy()
def update(self, other: 'VectorClock'):
"""Called when receiving message with vector clock."""
for node_id, timestamp in other.clock.items():
self.clock[node_id] = max(self.clock[node_id], timestamp)
self.increment() # Increment after receiving
def happens_before(self, other: 'VectorClock') -> bool:
"""Check if self → other (self causally precedes other)."""
less_or_equal = all(
self.clock[node] <= other.clock[node]
for node in self.clock
)
strictly_less = any(
self.clock[node] < other.clock[node]
for node in self.clock
)
return less_or_equal and strictly_less
def concurrent(self, other: 'VectorClock') -> bool:
"""Check if self || other (concurrent, no causal order)."""
return not self.happens_before(other) and not other.happens_before(self)
# Example usage
alice = VectorClock("alice", 3)
bob = VectorClock("bob", 3)
# Alice writes
alice_write = alice.increment() # {alice: 1, bob: 0, carol: 0}
# Bob reads Alice's write and responds
bob.update(alice_write) # {alice: 1, bob: 1, carol: 0}
bob_write = bob.increment() # {alice: 1, bob: 2, carol: 0}
# Causal relationship
print(alice_write.happens_before(bob_write)) # True
Causal+ Consistency
Copy
┌─────────────────────────────────────────────────────────────────────────────┐
│ CAUSAL+ CONSISTENCY │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ CAUSAL+ = Causal Consistency + Convergent Conflict Handling │
│ │
│ FOR CONCURRENT WRITES: │
│ ────────────────────── │
│ When two writes are concurrent (no causal order): │
│ - All replicas must converge to same value │
│ - Use deterministic conflict resolution │
│ │
│ CONFLICT RESOLUTION STRATEGIES: │
│ ──────────────────────────────── │
│ │
│ 1. Last-Writer-Wins (LWW) │
│ - Attach timestamp to each write │
│ - Higher timestamp wins │
│ - Simple but loses data! │
│ │
│ 2. Multi-Value Register │
│ - Keep all concurrent values │
│ - Application resolves on read │
│ - Used by Riak, DynamoDB │
│ │
│ 3. CRDTs │
│ - Mathematically guaranteed to converge │
│ - See replication module for details │
│ │
│ DATABASES WITH CAUSAL+: │
│ ──────────────────────── │
│ - MongoDB (with read/write concern configurations) │
│ - Cassandra (with LWT for some operations) │
│ - COPS (research system) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Eventual Consistency
Definition and Variations
Copy
┌─────────────────────────────────────────────────────────────────────────────┐
│ EVENTUAL CONSISTENCY │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ DEFINITION: │
│ ─────────── │
│ If no new updates are made, eventually all replicas converge │
│ to the same value. │
│ │
│ THE WEAKEST USEFUL GUARANTEE: │
│ ───────────────────────────── │
│ - No guarantee about WHEN convergence happens │
│ - No guarantee about order of updates │
│ - During updates, different replicas may return different values │
│ │
│ TIMELINE: │
│ ───────── │
│ Update ─────────────────────────────────────► Convergence │
│ ↑ inconsistency window ↑ │
│ │
│ Replica A: [x=1] ─────────────────── [x=5] ─── [x=5] │
│ Replica B: [x=1] ── [x=5] ──────────────────── [x=5] │
│ Replica C: [x=1] ──────────────────────── [x=5][x=5] │
│ │
│ During inconsistency window: │
│ - Read from A: x=1 │
│ - Read from B: x=5 │
│ - Application must handle this! │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Strong Eventual Consistency
Copy
┌─────────────────────────────────────────────────────────────────────────────┐
│ STRONG EVENTUAL CONSISTENCY (SEC) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ EVENTUAL CONSISTENCY + DETERMINISTIC CONVERGENCE │
│ │
│ PROPERTIES: │
│ ─────────── │
│ 1. Eventual delivery: Every update is eventually delivered │
│ 2. Convergence: Replicas with same updates have same state │
│ 3. Termination: Updates are processed in finite time │
│ │
│ KEY DIFFERENCE FROM EC: │
│ ──────────────────────── │
│ EC: "eventually the same" (when? who knows?) │
│ SEC: "same updates → same state" (immediate after sync) │
│ │
│ HOW TO ACHIEVE SEC: │
│ ──────────────────── │
│ Use CRDTs (Conflict-free Replicated Data Types) │
│ - Mathematically proven to converge │
│ - No coordination needed │
│ - Examples: G-Counter, OR-Set, LWW-Register │
│ │
│ EXAMPLE - G-Counter (Grow-only Counter): │
│ ───────────────────────────────────────── │
│ │
│ State: {node_a: 5, node_b: 3, node_c: 2} │
│ Value: sum(state) = 10 │
│ │
│ Merge: take max of each node's count │
│ merge({a:5, b:3}, {a:4, b:5}) = {a:5, b:5} │
│ │
│ Properties: │
│ - Increment is local (no coordination) │
│ - Merge is commutative, associative, idempotent │
│ - Always converges! │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Session Guarantees
Read-Your-Writes
Copy
┌─────────────────────────────────────────────────────────────────────────────┐
│ SESSION GUARANTEES │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ SESSION GUARANTEES provide consistency within a single client session. │
│ Weaker than linearizability but practical for many applications. │
│ │
│ 1. READ YOUR WRITES (RYW) │
│ ───────────────────── │
│ After a write, subsequent reads by same client see the write. │
│ │
│ Example - WITHOUT RYW: │
│ User updates profile → refreshes page → sees old profile! │
│ │
│ Implementation: │
│ - Track write timestamp per client │
│ - Ensure reads go to replica with at least that timestamp │
│ - Or: sticky sessions to same replica │
│ │
│ 2. MONOTONIC READS │
│ ──────────────────── │
│ If client reads value v, subsequent reads won't return older values. │
│ │
│ Example - WITHOUT monotonic reads: │
│ Read shows 10 likes → refresh → shows 8 likes → confusing! │
│ │
│ Implementation: │
│ - Track last read timestamp │
│ - Ensure subsequent reads from equal or newer timestamp │
│ │
│ 3. MONOTONIC WRITES │
│ ───────────────────── │
│ Writes by a client are applied in order on all replicas. │
│ │
│ 4. WRITES FOLLOW READS │
│ ──────────────────────── │
│ A write following a read is ordered after that read on all replicas. │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Implementation Patterns
Copy
# Session-based consistency implementation
class SessionContext:
"""
Tracks consistency requirements for a client session.
"""
def __init__(self, session_id: str):
self.session_id = session_id
self.last_write_timestamp = 0
self.last_read_timestamp = 0
def record_write(self, timestamp: int):
"""Called after successful write."""
self.last_write_timestamp = max(self.last_write_timestamp, timestamp)
def record_read(self, timestamp: int):
"""Called after successful read."""
self.last_read_timestamp = max(self.last_read_timestamp, timestamp)
def min_read_timestamp(self) -> int:
"""Minimum timestamp a read must satisfy for session guarantees."""
# Read-your-writes: must see own writes
# Monotonic reads: must not go backwards
return max(self.last_write_timestamp, self.last_read_timestamp)
class ConsistentClient:
def __init__(self, replicas: list, session: SessionContext):
self.replicas = replicas
self.session = session
async def read(self, key: str):
min_timestamp = self.session.min_read_timestamp()
# Find replica with fresh enough data
for replica in self.replicas:
if replica.current_timestamp >= min_timestamp:
value, timestamp = await replica.read(key)
self.session.record_read(timestamp)
return value
# No replica fresh enough, wait or use quorum read
return await self.quorum_read(key, min_timestamp)
async def write(self, key: str, value: any):
# Write to primary
timestamp = await self.primary.write(key, value)
self.session.record_write(timestamp)
return timestamp
Choosing a Consistency Model
Decision Framework
Copy
┌─────────────────────────────────────────────────────────────────────────────┐
│ CONSISTENCY MODEL SELECTION │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ QUESTION 1: What are the correctness requirements? │
│ ─────────────────────────────────────────────────── │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Need → Model │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ Bank transfers, inventory → Serializable / Strict │ │
│ │ Leader election, locks → Linearizable │ │
│ │ Social feeds, comments → Causal │ │
│ │ Page views, analytics → Eventual │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ QUESTION 2: What are the availability requirements? │
│ ──────────────────────────────────────────────────── │
│ │
│ High availability (5 nines) → Eventual / Causal │
│ Some downtime OK → Linearizable / Serializable │
│ │
│ QUESTION 3: What are the latency requirements? │
│ ─────────────────────────────────────────────── │
│ │
│ Single-digit ms → Local reads (eventual) or caching │
│ < 100ms → Async replication, causal │
│ > 100ms OK → Synchronous replication, linearizable │
│ │
│ QUESTION 4: Geographic distribution? │
│ ─────────────────────────────────── │
│ │
│ Single region → Strong consistency feasible │
│ Multi-region → Consider causal or eventual │
│ Multi-region strong → Need Spanner-like infrastructure (TrueTime) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Real-World Examples
| System | Default Consistency | Why |
|---|---|---|
| Google Spanner | Strict Serializable | Financial data, global transactions |
| CockroachDB | Serializable | PostgreSQL compatibility, ACID |
| Cassandra | Eventual (tunable) | High availability, write throughput |
| DynamoDB | Eventual (strong optional) | Scalability, single-digit ms latency |
| MongoDB | Causal (configurable) | Balance of consistency and availability |
| Redis | Linearizable (single) | In-memory speed, simplicity |
| Zookeeper | Linearizable writes | Coordination requires strong consistency |
Interview Practice
Q1: Linearizable vs Serializable
Q1: Linearizable vs Serializable
Question: What’s the difference between linearizability and serializability?Answer:
Key Insight: Linearizability is about recency (you always read the latest write). Serializability is about isolation (transactions don’t interfere).Strict Serializability = Linearizable + Serializable
| Aspect | Linearizability | Serializability |
|---|---|---|
| Scope | Single object/register | Multiple objects (transactions) |
| Real-time | Respects real-time order | Any serial order is valid |
| Domain | Distributed systems | Database transactions |
| Composability | Composable (if A and B are linearizable, A+B is too) | Not composable |
Q2: CAP and Consistency
Q2: CAP and Consistency
Question: If you choose availability in CAP, what consistency can you still have?Answer:
- Not available during partition: Linearizable, Serializable
- Available during partition: Causal, Eventual
Q3: Design a globally consistent counter
Q3: Design a globally consistent counter
Question: How would you implement a counter that’s consistent across regions?Approaches:
- Single leader (linearizable but slow)
- All increments go through one region
- Latency = round-trip to leader
- G-Counter CRDT (eventually consistent, fast)
- Each region has its own counter
- Merge by taking max per region
- Read = sum of all regions
- No coordination needed!
- Bounded counter (compromise)
- Pre-allocate “quota” to each region
- Increment locally until quota exhausted
- Request more quota (requires coordination)
Key Takeaways
Consistency is a Spectrum
From linearizable (strongest) to eventual (weakest). Choose based on your requirements.
Stronger = Slower
Strong consistency requires coordination, which adds latency and reduces availability.
CAP is About Partitions
During partitions, choose consistency (reject writes) or availability (accept divergence).
Session Guarantees Help
Read-your-writes and monotonic reads provide practical consistency within a session.