Unit 11 · Systems research · Lesson 3 of 4
Failure injection and prototype evaluation
Step 1: Learn the ideas
- Fault types: crash, restart, pause, partition (full, partial, asymmetric), clock skew, disk errors
- Jepsen architecture: generators, nemesis, histories and checkers
- Linearizability and isolation checkers: Knossos, Porcupine and Elle
- Chaos engineering: steady-state hypotheses and blast radius
- Deterministic simulation testing
- Failure studies: error handling, network partitions and storage faults
- Prototype evaluation: availability, recovery time and degraded performance
- Reproducibility and reporting of fault experiments
Why it matters
A fault-tolerance claim is a claim about behaviour under failure, so steady-state benchmarks cannot support it. Independent analyses of widely used databases and queues have repeatedly found lost writes, stale reads and split-brain behaviour under partitions in systems whose documentation promised stronger guarantees. Systems research reviewers therefore expect evidence under injected faults, and practitioners use the same techniques to find bugs before users do. In a research interview, being able to design such an experiment for your own prototype is a strong signal.
Core ideas
Choose faults from the failure model. Crash and restart processes, with and without losing unsynced data; pause them (a stopped process imitates a long garbage-collection pause); partition the network completely, partially (some nodes still see each other) and asymmetrically; add latency and loss; skew clocks; and inject disk errors or corruption. Failure studies are a good guide: the majority of catastrophic failures in widely used distributed data systems came from mishandling errors the software had already detected, most network-partition failures were catastrophic and many could be triggered by isolating a single node, and a single file-system fault on one replica can cause data loss or unavailability despite redundancy.
The Jepsen pattern. Several clients issue concurrent operations from a generator and record every invocation and completion, including timeouts whose outcome is unknown. A nemesis injects faults on a schedule. Afterwards a checker tests whether the history could have come from the claimed model: Knossos or Porcupine for linearizable registers and maps, Elle for transactional isolation anomalies. Indeterminate operations must be treated as possibly applied; ignoring them hides real anomalies or invents false ones.
Chaos experiments. In production or production-like environments, state a hypothesis about an observable steady-state metric such as successful requests per second, introduce a real-world event such as an instance failure, and look for deviations while limiting the blast radius and defining abort conditions. Chaos experiments test the whole socio-technical system (alerts, fallbacks, retries, operators), not one protocol's safety.
Deterministic simulation. Run the distributed system in one process with simulated network, disk and time, driven by a pseudorandom seed. Faults and message reorderings become cheap to explore, and any failure replays exactly from its seed. The cost is architectural: every source of nondeterminism (threads, clocks, I/O) must go through controllable interfaces.
Evaluating a prototype. Report what happens during and after faults: throughput and latency over time with fault windows marked, unavailability duration, time to recover or elect a new leader, data loss or anomalies found by the checker, and how results vary across repeated runs. Compare with baselines under the same fault schedule. State what was not tested; a clean history under one schedule is evidence for those faults, not a proof of correctness.
Common misconceptions
- "No anomalies found means the system is correct." Checkers only see histories produced by the faults and workloads you ran; coverage matters as much as the checker.
- "Timed-out operations can be counted as failures." A timed-out write may have been applied, so histories must treat it as indeterminate.
- "Chaos engineering means randomly killing things in production." It is hypothesis-driven experimentation with controlled scope and abort criteria.
- "Killing processes covers crash faults." Many bugs need crashes at specific points, such as between writing data and syncing it, or during recovery itself.
- "Fault-tolerance results can be reported like throughput results." They need time series around fault events and recovery metrics, not only run-wide averages.
How to approach it
Read a few Jepsen analyses to absorb the method, then reproduce it at small scale: record histories from your Raft-based key/value store or another small replicated service under partitions and check them with Porcupine. Turn the findings of one failure study into three concrete test cases. In interviews, describe the fault model, workload, checker and metrics before naming tools.
Suggested order
- 1Read two Jepsen analyses end to end and, for each, write down the workload, the faults, the checker and the anomalies found.
- 2Read "Simple Testing Can Prevent Most Critical Failures" and "An Analysis of Network-Partitioning Failures in Cloud Systems"; turn their findings into a list of faults to inject.
- 3Read the FoundationDB simulation and testing page for deterministic simulation, and skim the storage-fault paper for disk-level fault injection.
- 4Read the "Chaos Engineering" paper and the principles page; write one steady-state hypothesis for a service you know.
- 5Read the Porcupine blog post on linearizability testing, then do the fault-injection and history-checking project on a replicated key/value store.
- 6Optional: run the chaos-experiment project on a small multi-service application.
Paper guides: In Search of an Understandable Consensus Algorithm (Extended Version), Dynamo: Amazon's Highly Available Key-value Store
Step 2: Check off what you can do
Tap each one you can genuinely do or explain. Each earns 10 XP.
Step 3: Go deeper
Jepsen: distributed systems safety researchStart here
Jepsen (jepsen.io)Section: Analyses
Worked examples of the workload, nemesis, history and checker method applied to real systems.
Open(opens in a new tab)Link responded, 5 Oct 2026Simple Testing Can Prevent Most Critical Failures: An Analysis of Production Failures in Distributed Data-Intensive SystemsStart here
USENIXEvidence on which code paths cause catastrophic failures, to target fault injection.
Open(opens in a new tab)Link responded, 5 Oct 2026An Analysis of Network-Partitioning Failures in Cloud Systems
USENIXWhich partition scenarios break real systems and how to test them.
Open(opens in a new tab)Link responded, 5 Oct 2026FoundationDB: Simulation and Testing
FoundationDB documentationDeterministic simulation testing with seed-reproducible fault injection.
Open(opens in a new tab)Link responded, 5 Oct 2026Chaos Engineering
arXivHypothesis-driven resilience experiments with controlled blast radius.
Open(opens in a new tab)Link responded, 5 Oct 2026
Step 4: Practice
Start with one fault type and one checker, then add faults one at a time so you can attribute anomalies. Record every run’s seed, fault schedule and history. Report anomalies with the minimal history that shows them, plus availability and recovery-time plots with fault windows marked.
- Fault-inject a replicated key/value store and check its historiesOpen(opens in a new tab)Not attemptedSelf-directed project (Porcupine checker)
- MIT 6.5840 labs: key/value server, Raft, fault-tolerant and sharded key/valueOpen(opens in a new tab)Not attemptedMIT 6.5840
- Hypothesis-driven chaos experiment on a small multi-service applicationOpen(opens in a new tab)Not attemptedSelf-directed project (chaos engineering principles)
Record attempts on each problem’s page (+15 XP, +10 more when solved on your own).
Step 5: Test yourself
Answer each one out loud or on paper before you finish the lesson.
- Question 1Which faults would you inject first for a leader-based replicated store, and why?
- Question 2What is a partial partition, and why does it break systems that survive full partitions?
- Question 3Why must a checker treat timed-out operations as possibly applied?
- Question 4What does a chaos experiment’s steady-state hypothesis look like?
- Question 5What must a system’s design provide for deterministic simulation to work?
- Question 6What does a clean Jepsen-style run allow you to claim?
You’re done when you can
- Design a fault-injection experiment for a replicated store, naming faults, workload, checker and metrics, in 15 minutes.
- Run a history-checking experiment under partitions and explain any anomaly or why none appeared.
- Explain how indeterminate operations are handled in history checking.
- Describe deterministic simulation testing and its architectural cost in under two minutes.
- Present availability and recovery-time results with fault windows marked and run-to-run variation shown.


