Skip to main content

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

The Consistency Spectrum

┌─────────────────────────────────────────────────────────────────────────────┐
│                    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

┌─────────────────────────────────────────────────────────────────────────────┐
│                    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

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)

Cost of Linearizability

┌─────────────────────────────────────────────────────────────────────────────┐
│                    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

┌─────────────────────────────────────────────────────────────────────────────┐
│                    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

┌─────────────────────────────────────────────────────────────────────────────┐
│                    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

┌─────────────────────────────────────────────────────────────────────────────┐
│                    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

┌─────────────────────────────────────────────────────────────────────────────┐
│                    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

┌─────────────────────────────────────────────────────────────────────────────┐
│                    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

# 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

┌─────────────────────────────────────────────────────────────────────────────┐
│                    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

┌─────────────────────────────────────────────────────────────────────────────┐
│                    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

┌─────────────────────────────────────────────────────────────────────────────┐
│                    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

┌─────────────────────────────────────────────────────────────────────────────┐
│                    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

# 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

┌─────────────────────────────────────────────────────────────────────────────┐
│                    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

SystemDefault ConsistencyWhy
Google SpannerStrict SerializableFinancial data, global transactions
CockroachDBSerializablePostgreSQL compatibility, ACID
CassandraEventual (tunable)High availability, write throughput
DynamoDBEventual (strong optional)Scalability, single-digit ms latency
MongoDBCausal (configurable)Balance of consistency and availability
RedisLinearizable (single)In-memory speed, simplicity
ZookeeperLinearizable writesCoordination requires strong consistency

Interview Practice

Question: What’s the difference between linearizability and serializability?Answer:
AspectLinearizabilitySerializability
ScopeSingle object/registerMultiple objects (transactions)
Real-timeRespects real-time orderAny serial order is valid
DomainDistributed systemsDatabase transactions
ComposabilityComposable (if A and B are linearizable, A+B is too)Not composable
Key Insight: Linearizability is about recency (you always read the latest write). Serializability is about isolation (transactions don’t interfere).Strict Serializability = Linearizable + Serializable
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
Why Causal is special: Causal consistency is the strongest consistency model that’s still “available” in the CAP sense. It preserves important ordering (cause before effect) without requiring synchronous coordination.This is why many modern systems (like MongoDB with causal sessions) default to causal consistency—it’s the best of both worlds for many use cases.
Question: How would you implement a counter that’s consistent across regions?Approaches:
  1. Single leader (linearizable but slow)
    • All increments go through one region
    • Latency = round-trip to leader
  2. 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!
  3. Bounded counter (compromise)
    • Pre-allocate “quota” to each region
    • Increment locally until quota exhausted
    • Request more quota (requires coordination)
Trade-off: Exact count vs. latency/availability

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.

Next Steps