Skip to main content

Chapter 5: Consistency Model

GFS’s consistency model is one of its most interesting and often misunderstood aspects. Unlike traditional file systems that provide strong consistency, GFS offers a relaxed model that trades some guarantees for higher performance and simpler implementation. This chapter explores what GFS guarantees, what it doesn’t, and how applications work with this model.
Chapter Goals:
  • Understand GFS’s consistency guarantees and terminology
  • Learn the difference between defined, undefined, and inconsistent regions
  • Master atomic record append semantics
  • Explore how applications handle relaxed consistency
  • Grasp the trade-offs between consistency and performance

Consistency Guarantees

GFS provides different consistency guarantees depending on the operation type and success/failure scenarios.

Consistency Terminology

The “Consistent but Undefined” Paradox

A common point of confusion is how a region can be consistent (all replicas agree) but undefined (meaningless to the application).

The Interleaving Problem

Consider two clients writing to the same 64MB chunk at the same offset (offset 0).
  • Client A writes: [AAAAA]
  • Client B writes: [BBBBB]
If these writes are large (e.g., several MBs) and not handled via “Record Append”, GFS does not guarantee that the write is atomic across the entire byte range. Scenario:
  1. Primary receives both. It serializes them.
  2. But within the network pipeline, fragments of A and B might be interleaved if the client library sends them in multiple RPCs.
  3. Replicas might end up with: [AABBA] or [BBAAA].
Result:
  • Consistent: All replicas (R1, R2, R3) will have exactly the same interleaved data (e.g., [AABBA]) because they all followed the Primary’s serial order of individual packets.
  • Undefined: Neither Client A nor Client B wrote [AABBA]. The data is garbage.
Key Insight: Consistency in GFS refers to replica agreement, not data integrity relative to client intent. This is why GFS strongly recommends “Record Append” for concurrent access, as it guarantees atomicity.

Operation-Based Guarantees

Write That Succeeds on All Replicas:

Consistency Matrix

Visual summary of GFS consistency guarantees:

Application Implications

How do applications work with GFS’s relaxed consistency?

Handling Inconsistent Regions

Detecting Bad Records:

Consistency Best Practices

Use Record Append

Prefer Atomic Appends:
  • Use record_append for concurrent writes
  • Guaranteed atomic and defined
  • No coordination between clients
  • Handle duplicates at read time
  • Perfect for logging and MapReduce

Write-Once Pattern

Immutable After Creation:
  • Write file once, then read-only
  • No mutations after finalized
  • Eliminates consistency issues
  • Safe for concurrent readers
  • Common pattern in data processing

Validate Records

Application-Level Checking:
  • Add checksums to records
  • Use unique IDs for de-duplication
  • Include magic numbers
  • Scan for valid records
  • Skip inconsistent regions

Avoid Overwrites

Don’t Modify Existing Data:
  • No random writes to same location
  • No concurrent writes to same offset
  • Use new files for updates
  • Append-only workflows
  • Checkpoint with new files

Relaxed Consistency Trade-offs

Why did GFS choose relaxed consistency?

Benefits of Relaxed Model

Costs of Relaxed Model


Consistency Violations Examples

Real scenarios that can occur:
Scenario: Concurrent Writes Overwrite Each Other:
Scenario: Reading During Write:
Scenario: Append Retry Creates Duplicates:

Interview Questions

Expected Answer:In GFS, a file region is “defined” when it is:
  1. Consistent: All replicas have the same data
  2. Matches the mutation: The data is exactly what the client wrote
“Defined” is the strongest guarantee GFS provides. It means that:
  • All replicas agree on the data (consistent)
  • The data reflects the client’s write operation completely
  • Any client reading the region will see the expected data
Contrast with:
  • Consistent but undefined: All replicas agree, but data may be a mix of concurrent writes (not what any single client expected)
  • Inconsistent: Replicas disagree, may see different data depending on which replica you read from
GFS guarantees defined regions for:
  • Successful writes (all replicas ACK)
  • Successful record appends (atomic, all replicas apply at same offset)
Failed operations create inconsistent regions that applications must handle.
Expected Answer:Record append provides at-least-once delivery through automatic retry with duplicate tolerance:Mechanism:
  1. Client sends append request to primary
  2. Primary assigns offset and coordinates replicas
  3. If any replica fails, primary returns ERROR
  4. Client automatically retries the entire append
  5. Primary assigns a NEW offset for the retry
  6. Eventually all replicas succeed
  7. Client receives the successful offset
Result:
  • Guaranteed success (at least once): Client retries until success
  • May have duplicates: Failed attempt may have partially applied
  • Application handles duplicates: Uses unique IDs to filter
Example:
  • Attempt 1: Succeeds on R1, R2, fails on R3 → Error returned
  • Partial state: R1 and R2 have record at offset 1000
  • Attempt 2: Succeeds on all at offset 1003 → Success
  • Result: Record at 1003 (guaranteed), possible duplicate at 1000
Application Code:
At-least-once is perfect for idempotent operations and batch processing where duplicates can be filtered.
Expected Answer:GFS’s relaxed consistency model enables higher performance through several mechanisms:1. No Distributed Consensus:
  • Strong consistency requires Paxos/Raft for every write (2-3 round trips, 50-100ms)
  • GFS uses lease-based primary authority (1 round trip, 5-10ms)
  • Primary makes serialization decisions locally without voting
  • 10x latency improvement
2. Leases Instead of Locks:
  • Traditional: Distributed locks (expensive, deadlock-prone)
  • GFS: 60-second leases with automatic timeout
  • No explicit release protocol needed
  • Failures handled by timeout, not complex recovery
  • Primary can process thousands of operations per second
3. Decoupled Data and Control Flow:
  • Strong consistency: All communication through coordinator
  • GFS: Data pushed in pipeline, control to primary separately
  • Maximizes network bandwidth utilization
  • Parallel data transfer while primary makes decisions
4. Acceptable Inconsistent Regions:
  • Failed writes create inconsistent regions
  • Client retries overwrite with defined data
  • System doesn’t block waiting for consensus
  • Higher availability and throughput
5. Application-Level Handling:
  • Cost shifted to application (de-duplication, validation)
  • But applications can optimize for their use case
  • MapReduce already handles duplicates for fault tolerance
  • Perfect synergy with workload
Trade-off:
  • Performance: 10x lower latency, 10x higher throughput
  • Cost: Application complexity, not suitable for all workloads
For Google’s batch processing workload (MapReduce, logging, analytics), this trade-off was perfect.
Expected Answer:Building a database on GFS is challenging due to relaxed consistency. Several approaches:Approach 1: Log-Structured Merge (LSM) Tree:
  • Write-ahead log (WAL) using record append
  • Immutable sorted string tables (SSTables) as GFS files
  • Compaction creates new files
  • Like Bigtable implementation:
    • WAL: Append-only (perfect for record append)
    • SSTables: Write-once, immutable (no consistency issues)
    • Memtable: In-memory, not in GFS
Approach 2: Snapshot Isolation:
  • Store each version in separate GFS file
  • Atomic rename for version transition
  • Readers see consistent snapshots
  • Writers append to new version
  • Garbage collect old versions
Approach 3: External Coordination:
  • Use Chubby/Zookeeper for consistency
  • GFS for storage only
  • Coordinator provides locks, transactions
  • GFS provides durability, availability
  • Example: Bigtable uses Chubby for coordination
Approach 4: Application-Level MVCC:
  • Multi-version concurrency control
  • Each record has version number
  • Record append for new versions
  • Readers filter to consistent version
  • Garbage collect old versions
Key Principles:
  1. Don’t rely on GFS for consistency
  2. Use append-only patterns
  3. Leverage immutability where possible
  4. Add coordination layer for transactions
  5. Handle duplicates and validation in app
Real Example: Bigtable:
  • WAL on GFS (record append)
  • SSTables on GFS (immutable)
  • Chubby for coordination
  • Client library handles consistency
  • Perfect layering of systems
You wouldn’t build traditional RDBMS on GFS directly, but log-structured systems work well.

Key Takeaways

Consistency Model Summary:
  1. Three States: Defined (best), Consistent but undefined (mixed), Inconsistent (bad)
  2. Record Append: Atomic, at-least-once, defined on success, handles duplicates
  3. Regular Writes: Defined on success, inconsistent on failure, undefined if concurrent
  4. Application Responsibility: Validate records, de-duplicate, handle inconsistency
  5. Performance Trade-off: Relaxed consistency enables 10x better performance
  6. Workload Match: Perfect for append-heavy batch processing, not for OLTP
  7. Design Pattern: Write-once, append-only, immutable after creation
  8. Record Format: Magic numbers, checksums, unique IDs, length markers

Up Next

In Chapter 6: Fault Tolerance, we’ll explore:
  • How GFS handles master failures and recovery
  • Chunk replication strategies and re-replication
  • Detecting and handling chunkserver failures
  • Data integrity across component failures
  • Disaster recovery mechanisms
The consistency model defines what GFS guarantees—now we’ll see how it maintains those guarantees despite constant failures.