8 min read

The Time-Travelers of S3: How AWS Uses Deterministic Replay to Guarantee Consistency at Exabyte Scale

AWS S3 Deterministic Replay for Exabyte-Scale Consistency

The Time-Travelers of S3: How AWS Uses Deterministic Replay to Guarantee Consistency at Exabyte Scale

Imagine you are building a system that manages over 280 trillion objects and handles more than 100 million requests per second at peak. Now, imagine you need to change the fundamental laws of physics for that system—without a single nanosecond of downtime or a single bit of data corruption.

For fourteen years, Amazon S3 operated under a model of eventual consistency. If you overrode an existing object and immediately tried to read it, you might get the old version. If you deleted a file and listed the bucket, the file might still appear for a few hundred milliseconds. This was the trade-off for the “infinite” scale and high availability that made S3 the backbone of the modern internet.

Then, in late 2020, AWS did the unthinkable: they flipped the switch to Strong Read-After-Write Consistency for all objects, globally, across all APIs, with zero impact on performance and no extra cost.

How do you verify the correctness of a distributed system at this scale? How do you ensure that a race condition occurring once in a trillion operations doesn’t cause a catastrophic data loss? The answer isn’t “more testing.” It’s Formal Verification and Deterministic Replay.

This is the story of how S3 engineers used “time travel” to build the most reliable storage engine on the planet.


The Distributed Systems Nightmare: Non-Determinism

The fundamental problem with distributed systems is non-determinism. In a single-threaded program, if you execute A then B, B always happens after A. In a distributed system like S3, “after” is a hallucination.

Between the time a client sends a PUT request and the time the data is persisted across multiple Availability Zones (AZs), a thousand things can go wrong:

  • Network Partitions: A rack switch fails, and suddenly Node A can talk to Node B, but Node B can’t talk to Node C.
  • Partial Failures: A disk write succeeds on two nodes but hangs on the third.
  • Clock Drift: No two servers on Earth agree exactly on what time it is, making “last writer wins” a dangerous game.
  • Thread Interleaving: The OS scheduler pauses a thread at the exact millisecond between a “check” and an “act.”

Traditional integration testing and even “Chaos Engineering” (like Netflix’s Chaos Monkey) are probabilistic. They inject faults and hope to trigger a bug. But at S3’s scale, “one-in-a-billion” happens every few minutes. You don’t need to find bugs; you need to prove they cannot exist.

Layer 1: Formal Specification with TLA+

Before a single line of S3’s strong consistency code was written, the engineers wrote the “Blueprint.” In the world of high-stakes engineering, this means TLA+ (Temporal Logic of Actions).

TLA+ is not a programming language; it’s a mathematical language designed by Leslie Lamport (the same mind behind Paxos and LaTeX) to describe the behavior of concurrent systems. Instead of writing code, you write properties and invariants.

For example, an invariant for S3 might be:

“If a GET request for Object X returns Version 2, no subsequent GET request for Object X can return Version 1.”

The Model Checker

AWS uses TLA+ to build a “Model” of the system. This model is then fed into a Model Checker (TLC). The checker exhaustively explores every possible state the system could ever be in. It simulates every possible combination of network delays, crashes, and message reorderings.

If there is even one path—no matter how convoluted—that leads to a violation of your invariant, the Model Checker will find it and provide a “counterexample.”

The Catch: Model checkers suffer from the State Space Explosion problem. If your model is too complex, the number of possible states exceeds the number of atoms in the universe. To solve this for S3, engineers had to model the logic of the consistency protocol while abstracting away the implementation details like memory management or networking buffers.

Layer 2: Deterministic Simulation Testing (DST)

Formal models are great, but they aren’t the code that actually runs on the servers. There is often a “semantic gap” between the TLA+ proof and the Java/C++/Rust code. To bridge this, S3 utilizes Deterministic Simulation Testing.

This is where the “Time Travel” comes in.

In a standard production environment, the execution of code is influenced by the external world (the kernel, the hardware, the network). In a Deterministic Simulator, the code is wrapped in a “bubble” where every single source of non-determinism is replaced by a controlled, pseudo-random generator.

What is Mocked?

To achieve true determinism, the simulator must control:

  1. The Scheduler: Instead of the OS scheduling threads, a single-threaded discrete-event simulator decides which “node” or “thread” executes the next instruction.
  2. The Network: Every packet sent between simulated S3 nodes is intercepted. The simulator can drop, delay, reorder, or duplicate packets at will.
  3. The Clock: System.currentTimeMillis() is replaced by a simulated clock that only advances when the simulator says so.
  4. The Disk: I/O operations are simulated to return success, “latencies,” or various error codes (e.g., EIO, ENOSPC).

The Power of the “Seed”

Every simulation run starts with a single 64-bit integer seed. This seed determines the entire history of that universe. If the simulator finds a bug on “Universe #827364,” an engineer can take that exact same seed, run the simulator again, and the bug will manifest identically.

In a production environment, debugging a race condition is like trying to catch lightning in a bottle. In a deterministic simulator, you can pause the lightning, rewind it, and step through it frame-by-frame in a debugger.

# A conceptual look at a Deterministic Simulator Loop
def run_simulation(seed):
    rng = Random(seed)
    world = VirtualS3Cluster(nodes=10, network=VirtualNetwork(rng))

    while not world.is_done():
        event = world.get_next_event() # Could be a packet arrival or a timer
        # The simulator decides the order based on the RNG
        process_event_deterministically(event)

        # Check invariants after EVERY step
        assert world.check_strong_consistency_invariants()

Layer 3: Replay and the “Liveness” Challenge

Most people focus on Safety (nothing bad happens). But in distributed storage, Liveness (something good eventually happens) is just as critical. A system that simply rejects all requests is “safe” (it never returns wrong data), but it’s useless.

S3’s testing framework uses the deterministic engine to hunt for “Liveness bugs” or “Stuttering.” For instance, if three nodes are trying to elect a leader but keep getting timed out because the network is “too jittery,” the simulator can identify that the protocol is too fragile to ever make progress under certain conditions.

The Scale of Simulation

AWS doesn’t just run one simulation. They run millions. Using the massive compute power of EC2, they spin up thousands of instances to run billions of simulated S3 requests daily. They use Guided Fuzzing to prioritize seeds that explore “interesting” parts of the state space—like those that involve heavy disk contention or near-simultaneous node failures.

The Architectural Shift: How Consistency Works Under the Hood

You might wonder: “If strong consistency is so hard, how did they add it to S3 without killing performance?”

The secret lies in the S3 Metadata Layer. When you perform a PUT, the data is stored in a “Bit Index,” but the ownership and versioning are managed by a distributed metadata store.

Before 2020, S3 used a distributed cache for metadata that relied on eventual consistency for the sake of speed. To achieve strong consistency, AWS implemented a new protocol (often rumored to be a highly optimized variation of Paxos or Raft) that ensures all metadata writes are witnessed by a quorum of nodes before the write is acknowledged.

But here’s the kicker: they didn’t just implement a consensus protocol. They used Deterministic Replay to verify the migration from the old eventual consistency logic to the new strong consistency logic. They simulated the transition itself, ensuring that as nodes were upgraded one by one, the “hybrid” state of the cluster never violated consistency.

Why This Matters for the Future of Engineering

The S3 team’s move to formal methods and deterministic simulation represents a paradigm shift in software engineering. We are moving away from the era of “move fast and break things” and into the era of “Correctness by Construction.”

Lessons for Technical Leads:

  1. The “Test-Only” Approach is Dead: For complex distributed systems, unit tests are necessary but insufficient. You cannot test your way to 99.999999999% reliability. You must model your way there.
  2. Invest in Tooling: AWS spent years building internal tools (like the “Ironman” simulation framework) before they could launch Strong Consistency. The ROI on custom testing infra is often higher than the ROI on features.
  3. Minimize Non-Determinism: Even if you aren’t building S3, writing code that is “simulation-friendly” (e.g., dependency-injecting the clock, using actors instead of raw threads) makes your system vastly easier to debug.

The Engineering Curiosity: The “One-Second” Window

One of the most fascinating details revealed by AWS engineers regarding this transition was how they handled the “legacy” eventual consistency window.

During the migration, they maintained a shadow verification system. For every request S3 processed in production, the system would check—in the background—whether the result would have been different under the old vs. new consistency models. They ran this for months, processing trillions of requests, to ensure the new “strong” logic matched the “eventual” logic in every case where they overlapped.

They effectively used the real world as a massive, non-deterministic test suite to validate their deterministic models.

Final Thoughts: The Invisible Foundation

When you upload a photo to an S3 bucket and see it immediately appear in your app, you’re seeing the result of millions of hours of formal mathematical proofs and trillions of simulated “what-if” scenarios.

S3’s ability to provide strong consistency at an exabyte scale isn’t just a triumph of hardware—it’s a triumph of rigorous logic. By mastering “Time Travel” through deterministic replay, AWS has turned the chaos of distributed systems into a predictable, verifiable science.

In a world where data is the most valuable asset, the “eventual” in consistency is no longer good enough. The future belongs to the systems that can prove, mathematically and through every possible simulated reality, that they are correct.

And for S3, that future is already here, running at the scale of the entire internet.


More to explore

Keep diving in