system-design · beginner

Strong vs Eventual Consistency — Trade-offs in Distributed Systems

The Central Question

Consider an international financial ledger and user management platform running on the TxLab platform (txlab.com) processing 100,000,000 queries per day across 50,000,000 active users in North America and Europe:


At the exact same millisecond:
  1. User A in New York queries the account balance.
  2. User B in London queries the account balance.

If the architecture enforces Strong Consistency, both User A and User B receive the updated balance of $80 immediately, even if the database must delay User B's request while replicating data across the Atlantic Ocean.

If the architecture enforces Eventual Consistency, User A sees $80, but User B temporarily sees the stale balance of $100 for several hundred milliseconds until asynchronous replication catches up across regions.

This fundamental trade-off governs every distributed system: Should the architecture force readers to wait for global node synchronization (Strong Consistency), or allow temporary replica disagreement to maximize throughput and minimize latency (Eventual Consistency)?

This lesson answers one central question: How do distributed storage systems balance strict Linearizable Consistency against low-latency Eventual Consistency, and how do engineers design consistency models (including Read-Your-Writes, Monotonic Reads, and CRDT conflict resolution) across multi-region database architectures?


The Consistency Model Spectrum

Consistency is not a binary choice between "perfect" and "broken". Distributed databases operate along a continuous spectrum of guarantees:

flowchart LR
  Spectrum[Consistency Guarantee Spectrum]
  
  Spectrum --> Strongest[Linearizability / Strong Consistency]
  Spectrum --> Sequential[Sequential / Serializability]
  Spectrum --> Causal[Causal Consistency]
  Spectrum --> ClientCentric[Read-Your-Writes / Monotonic Reads]
  Spectrum --> Weakest[Eventual Consistency]
  
  style Strongest fill:#d4edda,stroke:#28a745
  style Weakest fill:#fff3cd,stroke:#ffc107

Figure 1: Spectrum of consistency models from strict Linearizability down to Eventual Consistency.

1. Strong Consistency (Linearizability)

After a write operation completes, any subsequent read operation on any node in the cluster must return the newly written value (or a later value). Real-world clock time dictates ordering. The cluster behaves as if it possesses only **one single copy of data**.

2. Eventual Consistency

Replicas are allowed to diverge temporarily during writes. If no new updates occur, all replicas will **eventually converge** to identical states. However, the system provides no bound on how long convergence takes unless explicitly configured with bounded staleness limits.

3. Intermediate Consistency Guarantees

Consistency ModelClient-Visible GuaranteePrimary Use Case
Read-Your-WritesA client that writes value $V$ is guaranteed to see value $V$ on subsequent reads.User updates profile picture or posts a comment.
Monotonic ReadsIf a client reads value $V_1$, they will never subsequently observe an older value $V_0$.Reading a live chat thread or social timeline.
Causal ConsistencyOperations that are causally related are observed in the same order by all nodes.Question-and-answer threads, comment replies.
Bounded StalenessReads may lag behind writes, but by no more than $T$ seconds or $K$ versions.Financial ticker dashboards, stock quotes.

Technical Mechanics: Quorums vs. Async Replication

The choice between strong and eventual consistency dictates the underlying network replication protocol:

sequenceDiagram
    autonumber
    actor Client as Client App
    participant Primary as Primary Node (US)
    participant Replica1 as Sync Replica (US)
    participant Replica2 as Async Replica (EU)
    
    Note over Client,Replica2: STRONG CONSISTENCY (Quorum Write: W + R > N)
    Client->>Primary: 1. WRITE Price = $80
    Primary->>Replica1: 2. Synchronous Replication
    Replica1-->>Primary: 3. ACK Write
    Primary-->>Client: 4. HTTP 200 OK (Strong Write Complete)
    
    Note over Client,Replica2: EVENTUAL CONSISTENCY (Async background shipping)
    Primary->>Replica2: 5. Asynchronous Log Shipping (Cross-Ocean WAN)
    Note over Replica2: 6. Replica EU receives update 250ms later.

Figure 2: Sequence diagram contrasting synchronous quorum writes against asynchronous background log shipping.


Read Repair and Anti-Entropy Background Synchronization

Eventual consistency models employ background repair processes to resolve replica divergence over time:

flowchart TD
  Convergence[Eventual Consistency Convergence Mechanisms] --> ReadRepair[1. Read Repair]
  Convergence --> AntiEntropy[2. Anti-Entropy with Merkle Trees]
  Convergence --> HintedHandoff[3. Hinted Handoff]
  
  ReadRepair --> RRDesc["When a client reads from multiple replicas (R > 1),<br/>if a stale node is detected, the client repairs it asynchronously."]
  AntiEntropy --> AEDesc["Background worker nodes exchange Merkle Tree hashes<br/>to quickly identify out-of-sync key ranges without scanning all rows."]
  HintedHandoff --> HHDesc["If Node C is temporarily offline during write,<br/>Node A stores a 'hint' and delivers it when Node C recovers."]

Figure 3: Taxonomy of background repair mechanisms enforcing eventual consistency.

Hinted Handoff Mechanics

When writing to a Cassandra cluster with replication factor $N=3$, if target `Node C` is temporarily unreachable due to network packet loss, coordinator `Node A` stores a local **Hint** payload on disk containing the mutation data and target node address. When `Node C` recovers and responds to health pings, `Node A` streams the stored hints to `Node C` (**Hinted Handoff**), restoring consistency without triggering heavy anti-entropy scans.

Implementing Causal Consistency with Vector Clocks

In social media systems (e.g. comment threads), if User A posts a question ($M_1$) and User B posts a reply ($M_2$), causality dictates that no user should ever observe $M_2$ without also seeing $M_1$. Causal consistency tracks causal dependencies using **Lamport Timestamps or Vector Clocks**:

Tunable Consistency Levels (Cassandra / DynamoDB)

NoSQL databases allow developers to tune consistency levels **per individual query**:

Monotonic Clocks vs Wall Clocks in Consistency Engines

To prevent system clock adjustments (NTP time steps) from causing out-of-order write resolution, modern consistency engines use **Monotonic Clocks** (`CLOCK_MONOTONIC`) for local duration measurements and TrueTime API error bounds for global ordering.

Client-Side Conflict Resolution Handlers

In eventual consistency systems using vector clocks (such as DynamoDB or Riak), when a read query encounters concurrent un-merged siblings, the database driver passes all conflicting versions to application-level **Client Conflict Handlers**, enabling business logic (such as merging shopping cart items) to resolve discrepancies cleanly.

Complete Worked Example: Go Linearizable vs Eventual Consistency Simulator

Let's inspect a complete Go implementation of a Linearizable vs Eventual Consistency Simulator for the TxLab platform (txlab.com).

package main

import (
"context"
"fmt"
"sync"
"time"
)

type StorageNode struct {
mu sync.RWMutex
value string
version int64
}

type ConsistencyCluster struct {
nodes []*StorageNode
}

func NewConsistencyCluster(numNodes int) ConsistencyCluster {
nodes := make([]
StorageNode, numNodes)
for i := 0; i < numNodes; i++ {
nodes[i] = &StorageNode{value: "initial", version: 0}
}
return &ConsistencyCluster{nodes: nodes}
}

func (c *ConsistencyCluster) StrongWriteLinearizable(val string) {
fmt.Printf("[STRONG WRITE] Synchronously updating all %d nodes...\n", len(c.nodes))
var wg sync.WaitGroup

for i, node := range c.nodes {
wg.Add(1)
go func(n *StorageNode, idx int) {
defer wg.Done()
n.mu.Lock()
n.value = val
n.version++
n.mu.Unlock()
}(node, i)
}

wg.Wait()
fmt.Println("[STRONG WRITE] All nodes synchronized successfully (Linearizable).")
}

func (c *ConsistencyCluster) EventualWriteAsync(val string) {
fmt.Println("[EVENTUAL WRITE] Updating Node 0 immediately; async shipping to others...")
c.nodes[0].mu.Lock()
c.nodes[0].value = val
c.nodes[0].version++
c.nodes[0].mu.Unlock()

// Async log shipping to secondary nodes with simulated WAN latency
for i := 1; i < len(c.nodes); i++ {
go func(n StorageNode, idx int) {
time.Sleep(100
time.Millisecond) // Simulated WAN lag
n.mu.Lock()
n.value = val
n.version++
n.mu.Unlock()
fmt.Printf("[ASYNC REPLICA %d] Eventually updated to '%s'\n", idx, val)
}(c.nodes[i], i)
}
}

func (c *ConsistencyCluster) ReadFromNode(nodeIdx int) string {
c.nodes[nodeIdx].mu.RLock()
defer c.nodes[nodeIdx].mu.RUnlock()
return c.nodes[nodeIdx].value
}


Failure Modes and Engineering Mitigations

Failure ScenarioRoot CauseSystem SymptomDetection SignalMitigation Strategy
1. Stale Financial ReadingDeveloper chooses Eventual Consistency for bank balance reads; user sees old balance and over-withdraws.Bank ledger accounts experience overdrafts and accounting errors.Financial reconciliation audit log mismatches.Enforce Strong Consistency (Linearizability) for all financial ledger operations.
2. Cross-Ocean Latency ExplosionDeveloper chooses Strong Consistency across US and Asia; every API write takes $400\text{ms}$.User conversion drops by 30% due to slow response times.High p99 API response time metrics on monitoring dashboards.Switch non-critical user profile routes to Read-Your-Writes Eventual Consistency.
3. Anti-Entropy Merkle CPU SaturationBackground Anti-Entropy synchronization runs every 10 seconds, scanning millions of keys.Database server CPU spikes to 100%; production query latency surges.High background worker thread CPU metrics.Increase Merkle Tree audit interval to Off-Peak Hours or use incremental hashing.
4. Read-Your-Own-Writes FailureMobile app posts a comment, but reads from a lagging replica that omits the new comment.Users re-submit duplicate comments thinking the first attempt failed.Surge in duplicate user comment submissions in database tables.Enforce Session-Sticky Routing to Primary for 5s post-write.

What You Should Remember

  1. Consistency is a spectrum: Choose from Linearizability (Strong), Sequential, Causal, Read-Your-Writes, down to Eventual Consistency based on business requirements.
  2. Strong Consistency costs latency and availability: Linearizability requires synchronous cross-node network roundtrips ($W + R > N$), increasing write latency.
  3. Eventual Consistency maximizes throughput: Asynchronous replication delivers sub-millisecond local writes, but introduces temporary replica divergence windows.
  4. Use Read-Your-Writes for user sessions: Route reads to the Primary or recent replica for a few seconds post-write to prevent user-perceived stale reads.
  5. Repair replica divergence with Merkle Trees: Deploy background Anti-Entropy workers to exchange Merkle hashes and repair out-of-sync keys without scanning full datasets.

Glossary of Terms

TermDefinition
Linearizability (Strong Consistency)The guarantee that any read returns the latest written value across all cluster nodes.
Eventual ConsistencyA model where replicas may diverge temporarily but converge to identical states over time.
Read-Your-Writes ConsistencyA guarantee that a user will always see their own recent writes on subsequent reads.
Monotonic ReadsA guarantee that a user will never observe an older data state after observing a newer state.
Merkle TreeA cryptographic hash tree used by background anti-entropy workers to identify missing keys efficiently.
Read RepairAsynchronously updating stale replica nodes when an out-of-date read is detected during a quorum read.

Practice Scenario and Self-Assessment

Architecture Scenario

You are designing the storage tier for an e-commerce platform (`store.txlab.com`): **Questions**:
  1. Formulate the exact consistency model selection (Linearizability vs Eventual Consistency) for Product Reviews vs Inventory Stock.
  2. Design the read-repair and quorum configuration for the Inventory Stock service.

Interactive Self-Assessment

N) before returning success to the client. This forces every write to wait for physical cross-ocean WAN network roundtrips, adding hundreds of milliseconds of latency.">Linearizability requires synchronous cross-region network roundtrips (W + R > N) to confirm write consensus before acknowledging the client.

Linearizability automatically formats persistent NVMe SSD disk drives on read replicas.

Linearizability revokes client HTTPS TLS encryption certificates on edge load balancers.

Linearizability cuts physical CPU hardware clock speeds in half across all database nodes.

It pins the editing user's reads to the Primary post-write, ensuring they see their own newly submitted content immediately without waiting for global replication.

Read-Your-Writes converts relational database primary key indexes into un-indexed CSV files.

Read-Your-Writes replaces public DNS nameservers with local hosts file entries.

Read-Your-Writes reboots operating system hypervisors across all application pods.


What to Learn Next

Track: Distributed Systems

Previous: Consistency Models — From Strong to Eventual

Next: Data Replication — Keeping Copies in Sync

Series: CAP, Consistency & Quorums

  1. CAP Theorem — Consistency, Availability, and Partition Tolerance
  2. Consistency Models — From Strong to Eventual
  3. Strong vs Eventual Consistency — Trade-offs in Distributed Systems (this guide)
  4. CAP, Consistency & Idempotency
  5. Quorum Reads vs Quorum Writes

All series

By Shubham Jain

All articles · Study paths

Shubham Jain · Learning Lab