Chapter 4: CAP Theorem & Consistency Models
Introduction
The CAP theorem is the most misunderstood concept in distributed systems. Pop-engineering reduces it to "pick 2 of 3" with a triangle diagram, leading to dangerous oversimplifications. The reality: network partitions aren't optional, so every distributed system must choose between Consistency and Availability during a partition.
This chapter covers:
- What CAP actually means (formal definitions, not hand-wavy triangles)
- PACELC: the extension that matters more in practice
- The consistency model hierarchy from linearizability to eventual consistency
- How real systems (DynamoDB, Cassandra, Spanner, etc.) map to these models
- Quorum systems, conflict resolution, CRDTs, and split-brain scenarios
1. CAP Theorem
1.1 Formal Definition
Brewer's Conjecture (2000): In a distributed system with data replication, you cannot guarantee all three of the following simultaneously:
- Consistency (C): Every read receives the most recent write or an error
- Availability (A): Every request receives a response (without guarantee it's the most recent write)
- Partition Tolerance (P): The system continues to operate despite arbitrary message loss/delay between nodes
Gilbert-Lynch Proof (2002): Formalized CAP as a theorem. Key insight: partitions are not optional in asynchronous networks, so the real choice is between C and A when a partition occurs.
Reject writes/reads to minority] D -->|Prioritize A| F[AP: Available but Inconsistent
Accept writes/reads everywhere] style C fill:#2ecc71 style E fill:#e74c3c style F fill:#f39c12
1.2 What C/A/P Really Mean
Consistency (C) - Linearizability
CAP's "C" means linearizability, the strongest consistency model. After a write completes, all subsequent reads see that write. There's a total order of operations consistent with real-time ordering.
all completed writes
Availability (A) - Every Node Responds
CAP's "A" means every non-failing node must respond to requests in a bounded time. Not just "the system is up", but "every reachable node answers queries".
Not Availability: "The system is up" (that's fault tolerance). CAP's A is stronger: every accessible node must respond, even if it can't contact other nodes.
Partition Tolerance (P) - Continue During Split
The system keeps operating when network messages are lost or delayed. In async networks (the internet), partitions are inevitable, so P is not optional.
| Aspect | Popular Understanding | Formal Definition |
|---|---|---|
| Consistency | "All nodes see same data" | Linearizability: total order consistent with real-time |
| Availability | "System is up" | Every non-failing node responds in bounded time |
| Partition Tolerance | "Optional feature" | Must handle network splits (not optional in distributed systems) |
1.3 Gilbert-Lynch Proof Sketch
The proof shows you cannot have both C and A during a partition:
- Setup: Two nodes (N1, N2) with replicated data. Network partition splits them.
- Write to N1: Client writes x=5 to N1. N1 acknowledges.
- Partition: N1 cannot communicate with N2.
- Read from N2: Client reads x from N2.
- Contradiction:
- For Consistency: N2 must return x=5 (latest write) or error. But N2 hasn't received the update (partition).
- For Availability: N2 must respond. It can only return old value (breaking C) or refuse (breaking A).
2. CAP Misconceptions
2.1 "Pick 2 of 3" is Misleading
The triangle diagram is harmful:
Why it's wrong:
- P is not optional: In distributed systems, partitions happen. You can't "not choose" P.
- CA doesn't exist: A single-node system is CA, but it's not distributed.
- It's not binary: Systems trade off degrees of consistency for degrees of availability.
2.2 Spectrum, Not Binary
Real systems aren't purely CP or AP. They offer tunable consistency:
CP] --> T1[Tunable] T1 --> T2[Most Systems
Live Here] T2 --> T3[Tunable] T3 --> Weak[Eventual Consistency
AP] style Strong fill:#e74c3c style T2 fill:#f39c12 style Weak fill:#2ecc71
| System | CAP Label | Reality |
|---|---|---|
| DynamoDB | AP | AP by default, optional CP reads (strongly consistent) |
| Cassandra | AP | Tunable: can do CP with QUORUM writes/reads |
| MongoDB | CP | CP for primary writes, but tunable read concerns |
| Spanner | CP | CP with linearizability (sacrifices availability during partitions) |
| Riak | AP | AP with tunable consistency (R/W values) |
2.3 CAP Only Applies During Partitions
When network is healthy: Systems can be both consistent AND available. CAP constraints only kick in during a partition.
2.4 Latency is Not in CAP
CAP says nothing about latency. A CP system can be slow. An AP system can be fast. PACELC extends CAP to include latency trade-offs.
3. PACELC Extension
3.1 PACELC Definition
PACELC (Daniel Abadi, 2010) extends CAP:
If Partition: choose between Availability and Consistency
Else (no partition): choose between Latency and Consistency
This matters because systems spend 99%+ of time in the "Else" state. The Latency vs Consistency trade-off is what you experience daily.
Why Latency vs Consistency?
To ensure strong consistency during normal operation, you need:
- Synchronous replication to multiple nodes
- Waiting for acknowledgments from quorum/all replicas
- Coordination overhead (locks, consensus)
All of this adds latency. Async replication is faster but eventually consistent.
3.2 Real Systems on PACELC
| System | Partition (PA vs PC) | Else (EL vs EC) | PACELC Label |
|---|---|---|---|
| DynamoDB | PA (available) | EL (low latency, eventual) | PA/EL |
| Cassandra | PA (available) | EL (low latency) | PA/EL |
| Riak | PA (available) | EL (low latency) | PA/EL |
| MongoDB | PC (consistent) | EC (strong consistency) | PC/EC |
| HBase | PC (consistent) | EC (strong consistency) | PC/EC |
| Spanner | PC (consistent) | EC (strong, but optimized latency) | PC/EC |
| Cosmos DB | Tunable | Tunable (5 consistency levels) | Configurable |
| BigTable | PA (available) | EL (eventual) | PA/EL |
3.3 PACELC Decision Matrix
| Use Case | Partition Priority | Normal Priority | Recommendation |
|---|---|---|---|
| Bank account balance | PC (must be consistent) | EC (strong consistency) | PC/EC (MongoDB, Spanner) |
| Social media likes | PA (always available) | EL (fast) | PA/EL (DynamoDB, Cassandra) |
| E-commerce inventory | PC (no overselling) | EC (consistency) | PC/EC |
| Session store | PA (must login) | EL (fast auth) | PA/EL (Redis, DynamoDB) |
| Real-time analytics | PA (always up) | EL (low latency queries) | PA/EL (Cassandra) |
| Financial transactions | PC (correctness) | EC (strong consistency) | PC/EC (RDBMS, Spanner) |
4. Consistency Models Hierarchy
CAP's "consistency" means linearizability, but there's a spectrum of consistency models. Understanding this hierarchy is critical for system design.
Strongest] --> S[Sequential Consistency] S --> C[Causal Consistency] C --> RYW[Read-Your-Writes] RYW --> MR[Monotonic Reads] MR --> MW[Monotonic Writes] MW --> E[Eventual Consistency
Weakest] style L fill:#e74c3c style S fill:#e67e22 style C fill:#f39c12 style RYW fill:#f1c40f style MR fill:#2ecc71 style MW fill:#1abc9c style E fill:#3498db
4.1 Linearizability (Strongest)
Definition: Operations appear to execute atomically and instantaneously at some point between invocation and response. There's a total order of all operations consistent with real-time ordering.
In plain English: The system behaves like a single, non-replicated data structure. After a write completes, all reads see that write.
Formal Properties:
- Total order: All operations have a global order
- Real-time ordering: If op1 completes before op2 starts, op1 appears before op2 in the total order
- Recency: Reads see the most recent write (in the total order)
after write completion
see the new value
Example: Linearizable vs Non-Linearizable
Cost of Linearizability:
- Latency: Must coordinate across replicas (quorum, consensus)
- Availability: Cannot serve requests if majority unreachable (CAP trade-off)
- Throughput: Coordination limits scalability
| System | Linearizable? | How/Why |
|---|---|---|
| Google Spanner | ✓ Yes | TrueTime API + Paxos |
| ZooKeeper | ✓ Yes (writes) | ZAB consensus, writes linearizable, reads sequential |
| etcd | ✓ Yes | Raft consensus |
| DynamoDB | ✗ No (default) | Eventually consistent by default |
| DynamoDB (strong) | ✓ Yes (optional) | Strongly consistent reads (slower, less available) |
| Cassandra | ✗ No | Tunable consistency, but not linearizable even with QUORUM |
4.2 Sequential Consistency
Definition: Operations from all processes appear to execute in some sequential order, and operations from each process appear in the order they were issued. No real-time ordering constraint.
Difference from Linearizability: Sequential consistency doesn't require real-time ordering. If write1 completes before write2 starts (in real time), they can appear in either order in the sequential history.
Sequential: Either order OK C1->>System: read(x) System-->>C1: 1 C1->>System: read(y) System-->>C1: 0 or 2 (either OK for sequential)
Example:
Where It's Used:
- ZooKeeper reads: Writes are linearizable, but reads from any replica are sequentially consistent (see writes in order, but may lag)
- Multiprocessor memory models: Many CPUs provide sequential consistency (or weaker)
| Property | Linearizability | Sequential Consistency |
|---|---|---|
| Total order | ✓ | ✓ |
| Real-time ordering | ✓ | ✗ |
| Per-process order | ✓ | ✓ |
| Recency guarantee | ✓ (immediate) | ✗ (eventual) |
| Performance | Slower | Faster |
4.3 Causal Consistency
Definition: Causally related operations are seen in the same order by all processes. Concurrent (non-causally-related) operations can be seen in different orders.
Causality: Operation A is causally before B if:
- A and B are from the same process, and A happens before B
- A is a write, B is a read, and B reads A's value
- Transitivity: A → C and C → B implies A → B
based on x] W3[Write z=3] -.->|concurrent| W1 style W1 fill:#3498db style R1 fill:#2ecc71 style W2 fill:#e74c3c style W3 fill:#f39c12
Example:
Implementation:
Use vector clocks or version vectors to track causality.
| System | Causal Consistency? |
|---|---|
| COPS (Causal+ consistency) | ✓ Yes (research system) |
| Bolt-on Causal (research) | ✓ Yes |
| MongoDB (causal consistency option) | ✓ Yes (client session) |
| Cosmos DB (session consistency) | ✓ Yes (within session) |
| Cassandra | ✗ No (tunable but not causal) |
4.4 Session Guarantees
Weaker than causal consistency, but practical for many applications. Guarantees apply within a single client session.
Read-Your-Writes (RYW)
If a process writes x, subsequent reads by that process see the write (or later values).
Monotonic Reads
If a process reads x=v1, subsequent reads return v1 or later (never go backwards).
Monotonic Writes
Writes from a process are applied in order.
Writes-Follow-Reads
If a process reads x=v1 then writes y, the write to y is applied after the write that produced v1.
| Guarantee | Violation Example | How to Prevent |
|---|---|---|
| Read-Your-Writes | Write to primary, read from stale replica | Sticky sessions, read-from-primary, version tracking |
| Monotonic Reads | Load balancer sends requests to different replicas with different lag | Session affinity, version vectors |
| Monotonic Writes | Network delays cause writes to arrive out of order | Per-client sequence numbers |
| Writes-Follow-Reads | Read v1, write v2, but v2 arrives at replica before v1 | Version dependencies |
Real Systems:
- DynamoDB: No RYW by default (eventual reads), but strongly consistent reads provide it
- Cosmos DB: "Session consistency" level provides all four guarantees
- MongoDB: "Causal consistency" (with client sessions) provides all four
4.5 Eventual Consistency (Weakest)
Definition: If no new updates are made to an object, eventually all reads will return the last updated value. No time bound.
In practice: Replicas may diverge temporarily, but will converge given enough time without writes.
Reads may return stale data note right of Converged: All replicas agree
Reads consistent
How Convergence Works:
1. Anti-Entropy (Background Sync):
- Replicas periodically compare data with peers
- Exchange missing updates
- Merkle trees for efficient comparison (Cassandra, DynamoDB)
2. Read Repair:
- During read, coordinator queries multiple replicas
- If values differ, return newest, then push to stale replicas
3. Hinted Handoff:
- If replica is down during write, store hint at another node
- When replica recovers, deliver the hint
Problems with Eventual Consistency:
| Problem | Example | Impact |
|---|---|---|
| Stale reads | User updates profile, refresh shows old data | User confusion |
| Read-your-writes violation | Write to leader, read from follower (stale) | Lost updates appear |
| Monotonic read violation | Read from R1 (v2), then R2 (v1) | Time goes backwards |
| Conflicting writes | Two users edit same doc simultaneously | Need conflict resolution |
When Eventual Consistency is OK:
- Social media likes/follows: Exact count doesn't matter immediately
- DNS: Records change infrequently, caching is fine
- Analytics/logging: Approximate counts acceptable
- Content distribution: Stale content for brief period is fine
When it's NOT OK:
- Bank balances: Incorrect balance = lost money
- Inventory: Overselling products
- Access control: Revoked permissions must take effect immediately
- Leader election: Must have single leader
5. Real System Mappings
5.1 DynamoDB
- Default: Eventually consistent reads (faster, lower cost)
- Option: Strongly consistent reads (slower, double cost, less available)
- Writes: Synchronously replicate to 3 AZs, acknowledge after majority (W=2)
5.2 Cassandra
Tunable consistency: Set per-request consistency levels for reads (R) and writes (W).
| Consistency Level | Meaning | Latency | Availability |
|---|---|---|---|
| ONE | Any 1 replica responds | Lowest | Highest |
| QUORUM | Majority (N/2 + 1) respond | Medium | Medium |
| ALL | All replicas respond | Highest | Lowest |
| LOCAL_QUORUM | Majority in local datacenter | Low | High (within DC) |
| EACH_QUORUM | Majority in every datacenter | Very High | Low |
Strong consistency: R + W > N (quorum intersection)
5.3 Google Spanner
- Linearizable: External consistency (stronger than linearizability)
- TrueTime API: GPS + atomic clocks provide tight time bounds
- Commit wait: Wait out clock uncertainty to ensure ordering
5.4 MongoDB
- Writes: Always go to primary
- Read Concern: local, majority, linearizable
- Write Concern: 1 (primary ack), majority, all
5.5 PostgreSQL Replication
- Synchronous replication: Primary waits for standby acknowledgment (strong consistency, higher latency)
- Asynchronous replication: Primary doesn't wait (eventual consistency, lower latency, risk of data loss)
5.6 System Comparison
| System | Consistency Model | Tunable? | CAP | PACELC |
|---|---|---|---|---|
| Spanner | Linearizable (external consistency) | No | CP | PC/EC |
| DynamoDB | Eventual (optional strong) | Yes | AP (default) | PA/EL |
| Cassandra | Tunable (ONE to ALL) | Yes | AP | PA/EL |
| MongoDB | Strong (tunable read concern) | Yes | CP | PC/EC |
| ZooKeeper | Linearizable writes, sequential reads | No | CP | PC/EC |
| Cosmos DB | 5 levels (strong to eventual) | Yes | Configurable | Configurable |
| etcd | Linearizable | No | CP | PC/EC |
| Riak | Eventual (tunable R/W) | Yes | AP | PA/EL |
6. Quorum Systems
Quorums enable consistency without full replication acknowledgment. Key insight: read and write quorums must overlap to guarantee consistency.
6.1 Quorum Formula
R + W > N
- N: Total number of replicas
- W: Write quorum (# replicas that must acknowledge write)
- R: Read quorum (# replicas queried for read)
Why R + W > N? Ensures at least one replica is in both read and write quorums, guaranteeing the read sees the latest write.
6.2 Common Quorum Configurations
| N | R | W | R+W | Consistency | Use Case |
|---|---|---|---|---|---|
| 3 | 2 | 2 | 4 > 3 ✓ | Strong | Balanced read/write |
| 3 | 1 | 3 | 4 > 3 ✓ | Strong | Read-heavy (fast reads) |
| 3 | 3 | 1 | 4 > 3 ✓ | Strong | Write-heavy (fast writes) |
| 3 | 1 | 1 | 2 < 3 ✗ | Eventual | Low latency, high availability |
| 5 | 3 | 3 | 6 > 5 ✓ | Strong | Tolerate 2 failures |
6.3 Quorum Read/Write Process
Quorum Write (W=2, N=3):
Quorum Read (R=2, N=3):
Return value with highest version Coordinator-->>Client: x=5 R3-->>Coordinator: (x=3, version=8) [stale] Note over Coordinator: Trigger read-repair: send v10 to R3 Coordinator->>R3: repair(x=5, version=10)
6.4 Sloppy Quorums & Hinted Handoff
Problem: What if W replicas are unavailable during write?
Strict quorum: Fail the write (unavailable).
Sloppy quorum: Write to different nodes temporarily, deliver later (hinted handoff).
Trade-off: Sloppy quorums improve availability but weaken consistency guarantees. DynamoDB and Cassandra use them.
6.5 Why Quorums Don't Guarantee Linearizability
Even with R + W > N, you can have non-linearizable behavior:
- Concurrent writes: Multiple clients write simultaneously, last-writer-wins based on timestamps (clock skew issues)
- Sloppy quorums: Hinted handoff means writes may not overlap with reads
- Network delays: Version vectors resolve conflicts, but not in real-time order
7. Conflict Resolution
In AP systems (or during partitions), concurrent writes to the same key create conflicts. The system must resolve them.
7.1 Last-Writer-Wins (LWW)
Strategy: Assign a timestamp to each write. Keep the write with the latest timestamp.
Problem: Relies on synchronized clocks. Clock skew can cause wrong resolution.
But B was written after A in real time!
When to use: Acceptable data loss, no strict ordering requirements (e.g., cache, session data).
7.2 Vector Clocks
Idea: Track causality with per-node counters. Detect concurrent writes without relying on wall-clock time.
Vector Clock: Map of {node → counter}. Each node increments its counter on write.
Example:
Comparison Rules:
- VC1 < VC2: VC1 happened before VC2 (VC1[i] ≤ VC2[i] for all i, and VC1 ≠VC2)
- VC1 || VC2: Concurrent (neither dominates)
VC A:1"] Start --> B["B writes x=2
VC B:1"] A --> C["C reads both
VC A:1 and VC B:1"] B --> C C --> Conflict["Conflict Detected
A:1 || B:1"] Conflict --> Resolve["Resolve: x=3
VC A:1, B:1, C:1"] style Conflict fill:#e74c3c style Resolve fill:#2ecc71
Problem: Vector clocks grow over time (more nodes = larger vectors). Pruning strategies needed.
Real Systems:
- Riak: Uses vector clocks, exposes conflicts to application
- Voldemort: Vector clocks with automatic pruning
7.3 CRDTs (Conflict-Free Replicated Data Types)
Idea: Design data structures that can be merged automatically without conflicts. Strong Eventual Consistency: replicas that have seen the same updates have the same state (no manual resolution).
Two flavors:
- State-based CRDTs (CvRDT): Replicas send full state, merge function is commutative, associative, idempotent
- Operation-based CRDTs (CmRDT): Replicas send operations, operations commute
7.3.1 G-Counter (Grow-only Counter)
Increment-only counter (cannot decrement).
A:5, B:3, C:2
sum=10] R2[Replica 2
A:5, B:3, C:2
sum=10] R1 -->|A increments| R1a[A:6, B:3, C:2
sum=11] R2 -->|B increments| R2a[A:5, B:4, C:2
sum=11] R1a -->|Merge| M[A:6, B:4, C:2
sum=12] R2a -->|Merge| M style M fill:#2ecc71
7.3.2 PN-Counter (Positive-Negative Counter)
Counter that can increment and decrement.
7.3.3 G-Set (Grow-only Set)
Add-only set (cannot remove).
7.3.4 2P-Set (Two-Phase Set)
Set with adds and removes (remove wins).
7.3.5 OR-Set (Observed-Remove Set)
Set where removes only affect observed adds (allows re-adding).
7.3.6 LWW-Register (Last-Writer-Wins Register)
Single value with timestamp (LWW resolution).
CRDT Comparison:
| CRDT | Operations | Merge Rule | Use Case |
|---|---|---|---|
| G-Counter | Increment | Max per node | View counts, likes |
| PN-Counter | Increment, Decrement | Sum(P) - Sum(N) | Up/downvotes |
| G-Set | Add | Union | Tag collection |
| 2P-Set | Add, Remove (once) | Added - Removed | Membership (no re-join) |
| OR-Set | Add, Remove (observed) | Remove only seen adds | Shopping cart |
| LWW-Register | Write | Latest timestamp | Session data |
Real Systems Using CRDTs:
- Riak: Riak Data Types (counters, sets, maps)
- Redis: CRDT-based modules (RedisGraph, etc.)
- Akka: Distributed Data (CRDTs for actor state)
- Automerge: CRDT library for collaborative editing
8. Consensus vs Consistency
Common confusion: "Consensus means strong consistency." Wrong. They're different problems.
| Aspect | Consensus | Consistency |
|---|---|---|
| Problem | Agreement among nodes | Data visibility guarantees |
| Question | "What value should we agree on?" | "What value does a read return?" |
| Algorithms | Paxos, Raft, ZAB | Quorums, versioning, replication strategies |
| Goal | All non-faulty nodes agree on same value | Define read/write visibility rules |
| Use Cases | Leader election, log replication, atomic commit | Read consistency, staleness bounds |
8.1 How Consensus Enables Consistency
Consensus algorithms can be used to implement strong consistency models:
- Raft/Paxos: Replicate writes in agreed order → linearizable reads from leader
- ZooKeeper (ZAB): Consensus on write order → sequential consistency for reads
- Spanner (Paxos): Consensus + TrueTime → external consistency
8.2 Systems Without Consensus
You can have strong consistency without consensus:
- Primary-backup replication: Primary orders writes, backups follow (no voting needed for agreement)
- Quorum-based systems: Cassandra with QUORUM reads/writes (no consensus, but strong-ish consistency)
8.3 Systems Without Strong Consistency
You can use consensus without strong consistency:
- Leader election: Use Raft to elect a leader, but don't enforce linearizable reads
- Configuration management: Consensus on config changes, but applications read locally (eventually consistent)
9. Tunable Consistency
Modern systems offer tunable consistency: choose consistency level per operation based on requirements.
9.1 Cassandra's Tunable Consistency
Write Consistency Levels:
| Level | Acks Required | Latency | Durability |
|---|---|---|---|
| ANY | 1 node (even hinted handoff) | Lowest | Lowest (can lose write) |
| ONE | 1 replica | Low | Low |
| TWO | 2 replicas | Medium | Medium |
| QUORUM | Majority (N/2+1) | Medium | High |
| ALL | All N replicas | Highest | Highest (least available) |
Read Consistency Levels:
| Level | Replicas Queried | Latency | Consistency |
|---|---|---|---|
| ONE | 1 replica | Lowest | Eventual |
| TWO | 2 replicas (return first) | Low | Better |
| QUORUM | Majority | Medium | Strong (if R+W > N) |
| ALL | All replicas | Highest | Strongest |
Trade-off Matrix:
9.2 DynamoDB's Consistency Modes
| Mode | Consistency | Latency | Cost | Availability |
|---|---|---|---|---|
| Eventually Consistent Reads | Eventual | ~10ms | 1 RCU | High |
| Strongly Consistent Reads | Strong | ~10-20ms | 2 RCU | Lower (leader only) |
| Transactional Reads | Serializable | ~20-50ms | 4 RCU | Lower |
9.3 Cosmos DB's 5 Consistency Levels
| Level | Guarantee | Use Case |
|---|---|---|
| Strong | Linearizability | Financial transactions, inventory |
| Bounded Staleness | Staleness bounded by K versions or T seconds | Monitoring dashboards (5min lag OK) |
| Session | Read-your-writes, monotonic reads/writes within session | User profiles, shopping carts |
| Consistent Prefix | Reads never see out-of-order writes | Social media feeds (no reordering) |
| Eventual | Convergence eventually | Likes, view counts |
10. Consistency in Practice
10.1 Decision Framework
Linearizable] Q1 -->|No| Q2{User sees own writes?} Q2 -->|Must| RYW[Read-Your-Writes
Session Consistency] Q2 -->|No| Q3{Order matters?} Q3 -->|Yes| Causal[Causal Consistency] Q3 -->|No| Q4{Bounded staleness OK?} Q4 -->|Yes| Bounded[Bounded Staleness
e.g., 5 min lag] Q4 -->|No| Eventual[Eventual Consistency] style Strong fill:#e74c3c style RYW fill:#f39c12 style Causal fill:#3498db style Eventual fill:#2ecc71
10.2 Use Case Mappings
| Use Case | Consistency Model | Reasoning | System Example |
|---|---|---|---|
| Bank account balance | Linearizable | Cannot show incorrect balance, no double-spend | Spanner, traditional RDBMS |
| E-commerce inventory | Strong (or eventual with reservations) | Cannot oversell (or use separate reservation system) | MongoDB, DynamoDB + compensation |
| User profile | Read-your-writes | User must see their own updates immediately | DynamoDB (strongly consistent reads) |
| Social media feed | Consistent prefix | Posts should not appear out of order | Cosmos DB, Cassandra |
| Likes/follows | Eventual | Exact count doesn't matter immediately | Cassandra, DynamoDB |
| Shopping cart | Session consistency | User sees their additions, others don't need to | Cosmos DB session, DynamoDB |
| Leader election | Consensus (linearizable) | Must agree on single leader | ZooKeeper, etcd, Consul |
| DNS | Eventual | Records change infrequently, caching is fine | DNS system |
| Distributed lock | Linearizable | Must prevent concurrent access | ZooKeeper, etcd, Redlock (Redis) |
| Metrics/logs | Eventual | Approximate counts acceptable | Cassandra, InfluxDB |
| Collaborative doc editing | Causal + CRDTs | Maintain edit order, auto-merge conflicts | Automerge, Yjs |
10.3 Mixed Consistency Example: E-commerce
Real systems use different consistency models for different data:
| Data Type | Consistency | System |
|---|---|---|
| User account (balance, payment) | Strong | PostgreSQL |
| Order status | Strong | PostgreSQL / DynamoDB strongly consistent |
| Inventory (available count) | Strong or eventual + reservation | Redis (strong) or Cassandra + reservation system |
| Product catalog | Eventual | DynamoDB (eventual), CDN cache |
| Shopping cart | Session (read-your-writes) | Redis, DynamoDB |
| Search index | Eventual | Elasticsearch |
| Recommendations | Eventual | Cassandra, ML model cache |
10.4 Handling Consistency Violations
When eventual consistency causes user-visible issues:
- Compensation logic: Undo operations (e.g., cancel oversold item, refund)
- User communication: "Your order is being processed" (hide inconsistency window)
- Idempotency: Safe to retry operations (use idempotency keys)
- Optimistic UI: Show expected state immediately, correct if wrong
11. Split-Brain Problem
Split-brain: Network partition causes multiple nodes to believe they're the leader, leading to divergent state and data corruption.
11.1 Example: Split-Brain Scenario
11.2 Prevention Strategies
1. Quorum-Based Leader Election
Require majority to elect leader. Partition with minority cannot elect new leader.
2. Fencing Tokens
Leader obtains incrementing token. Storage rejects writes with stale tokens.
3. STONITH (Shoot The Other Node In The Head)
When partition detected, forcibly power off the old leader (used in HA clusters).
4. Lease-Based Leadership
Leader holds time-bound lease. Must renew regularly. If lease expires, leadership lost.
11.3 Generation Numbers
Each leader election increments a generation/epoch number. Stale leaders are ignored.
Real Systems:
| System | Split-Brain Prevention |
|---|---|
| ZooKeeper | Quorum-based leader election + epoch numbers |
| etcd | Raft consensus (majority quorum) + term numbers |
| Consul | Raft consensus + leader leases |
| MongoDB | Primary election with majority, fencing with optime |
| Kubernetes | etcd-backed leader election (lease mechanism) |
11.4 Split-Brain in Practice
GitHub outage (2018): Network partition between US East and US West. Both sides elected leader, accepted writes for 24 seconds. Required manual data reconciliation.
Lesson: Even with quorum systems, edge cases exist (e.g., brief window before old leader realizes it's partitioned). Use multiple defenses (quorum + fencing + generation numbers).
12. Interview Signals & Mistakes
12.1 Strong Signals
- Differentiates CAP from PACELC: Understands CAP is about partition behavior, PACELC includes latency trade-off during normal operation
- Knows consistency model hierarchy: Can explain linearizability vs sequential vs causal vs eventual
- Maps real systems correctly: DynamoDB is AP/PA-EL, Spanner is CP/PC-EC, Cassandra is tunable
- Understands quorum math: R + W > N, can calculate appropriate R/W for use case
- Explains consensus vs consistency: They're different; consensus can implement consistency but not the same thing
- Tailors consistency to use case: Doesn't default to "strong consistency everywhere" or "eventual is fine"
12.2 Common Mistakes
| Mistake | Why It's Wrong | Correct Answer |
|---|---|---|
| "CAP: pick 2 of 3" | P is not optional in distributed systems | "During partition, choose A or C. Without partition, can have both." |
| "CA systems exist" | Only single-node systems are CA | "Distributed systems are either CP or AP during partitions" |
| "DynamoDB is consistent" | Conflates optional strong reads with default behavior | "DynamoDB is eventually consistent by default, offers optional strong reads" |
| "Cassandra QUORUM is linearizable" | Quorums don't guarantee real-time ordering | "QUORUM provides strong consistency but not linearizability due to timestamps" |
| "Eventual consistency is bad" | Depends on use case | "Eventual consistency is fine for many use cases (likes, views) and enables high availability" |
| "I'll use Raft for consistency" | Conflates consensus with consistency | "Raft provides consensus (agreement on log). For linearizable reads, need leader reads or read indexes." |
| "Strong consistency is always better" | Ignores latency, availability, cost trade-offs | "Use weakest consistency that meets business requirements" |
12.3 Interview Questions to Expect
- "Explain the CAP theorem."
- Weak: "Pick 2 of 3: consistency, availability, partition tolerance"
- Strong: "During network partition, choose consistency (reject requests) or availability (serve stale data). Without partition, can have both. P is not optional in distributed systems."
- "Is DynamoDB CP or AP?"
- Weak: "AP" (incomplete)
- Strong: "AP during partitions by default (eventually consistent reads). Offers optional strongly consistent reads (CP) at cost of latency and availability."
- "How do you ensure strong consistency in a distributed database?"
- Weak: "Use consensus"
- Strong: "Options: (1) Quorum reads/writes with R + W > N, (2) Linearizable reads from leader after consensus (Raft/Paxos), (3) Synchronous replication with fencing tokens to prevent split-brain"
- "When would you use eventual consistency?"
- Weak: "For performance"
- Strong: "When business logic tolerates temporary inconsistency: social media likes, view counts, non-critical metrics. NOT for financial data, inventory, access control where correctness is critical."
- "Explain linearizability vs serializability."
- Weak: "They're the same" (WRONG)
- Strong: "Linearizability: single-operation consistency (reads see latest writes, real-time order). Serializability: multi-operation consistency (transactions execute as if serial). Linearizability is about consistency model, serializability is about isolation level."
- "Design a distributed counter."
- Weak: "Use a database with strong consistency"
- Strong: "Depends on requirements. Exact count: G-Counter CRDT (increment-only, merge by sum). Increment/decrement: PN-Counter CRDT. High write throughput: Shard counter, aggregate periodically (eventual). Low latency: Redis with Lua scripts (strong, single-node). Multi-datacenter: CRDTs with anti-entropy."
12.4 Deep Dive Questions (Senior/Staff Level)
- "How does Spanner achieve linearizability across datacenters?"
- Expected: TrueTime API (GPS + atomic clocks), commit-wait protocol, external consistency guarantee
- "Why can't you have linearizability with pure async replication?"
- Expected: Async replication means no acknowledgment before returning. Client might read from stale replica after write acknowledged. Violates linearizability's real-time ordering requirement.
- "Explain the difference between vector clocks and version vectors."
- Expected: Semantically similar (track causality), but version vectors are per-object, vector clocks are per-process. Version vectors track object history, vector clocks track message causality.
- "Design a system for collaborative document editing (Google Docs style)."
- Expected: CRDTs (operation-based, e.g., Yjs, Automerge), operational transformation (older approach), conflict-free merging, causal consistency, WebSocket for real-time sync, eventual consistency with fast convergence.
- "How would you implement read-your-writes consistency in a multi-datacenter setup?"
- Expected: Options: (1) Sticky sessions (read from same DC), (2) Version tracking (client sends last-seen version, wait until replica catches up), (3) Read-from-leader (sacrifices latency), (4) Causal consistency with version vectors
Summary
Key Takeaways
- CAP Theorem: During partition, choose Availability (AP) or Consistency (CP). Partition tolerance is not optional.
- PACELC: Extends CAP: If Partition (A vs C), Else (Latency vs Consistency). More practical than CAP alone.
- Consistency Hierarchy: Linearizable > Sequential > Causal > Session Guarantees > Eventual
- Quorums: R + W > N guarantees consistency. Doesn't guarantee linearizability due to timestamps and sloppy quorums.
- Conflict Resolution: LWW (clock-based), Vector Clocks (causal), CRDTs (automatic convergence)
- Consensus ≠Consistency: Consensus enables agreement, consistency defines read/write visibility
- Tunable Consistency: Modern systems (Cassandra, DynamoDB, Cosmos DB) let you choose per-operation
- Split-Brain Prevention: Quorum-based elections, fencing tokens, generation numbers, leases
- Use Case Matters: Bank balance → strong, social likes → eventual. Choose weakest consistency that meets requirements.
Real System Quick Reference
| System | Consistency | CAP | PACELC | Best For |
|---|---|---|---|---|
| Spanner | Linearizable | CP | PC/EC | Global strong consistency (bank transactions) |
| DynamoDB | Eventual (optional strong) | AP | PA/EL | High availability, low latency (sessions, catalog) |
| Cassandra | Tunable | AP | PA/EL | Multi-DC, high write throughput (metrics, logs) |
| MongoDB | Strong (tunable reads) | CP | PC/EC | Strong consistency, flexible schema (orders, user data) |
| ZooKeeper | Linearizable writes, sequential reads | CP | PC/EC | Coordination (leader election, config) |
| Cosmos DB | 5 levels (configurable) | Configurable | Configurable | Multi-model, global distribution with SLAs |
Decision Tree
- Critical correctness (money, inventory)? → Strong consistency (CP)
- User must see own writes? → Read-your-writes (session consistency)
- Order of events matters? → Causal consistency
- Can tolerate staleness? → Eventual consistency (AP)
- High availability > correctness? → AP systems (DynamoDB, Cassandra)
- Correctness > availability? → CP systems (Spanner, ZooKeeper)