Unit 11 · Systems research · Lesson 1 of 4
Invariants, safety, liveness and distributed correctness
Step 1: Learn the ideas
- Fault models: crash-stop, crash-recovery, omission, Byzantine
- Timing models: synchronous, partially synchronous, asynchronous; the FLP result
- Safety and liveness properties
- Invariants, inductive invariants and proof sketches
- Linearizability, sequential consistency and serializability
- Quorum intersection and term or epoch arguments
- TLA+ and model checking (awareness)
- History checkers: Knossos, Porcupine and Elle
- Reading traces and logs to localize violations
Why it matters
Distributed systems fail in interleavings that tests rarely hit: a leader that does not know it was replaced, a retried request applied twice, a read served by a stale replica. The defence is a disciplined argument: what can fail, what must never happen, what must eventually happen, and which invariant connects them. Systems papers state their guarantees in exactly these terms, and interviews for distributed-systems and systems-research roles ask you to argue correctness out loud or to find the bug in a protocol sketch.
Core ideas
Fault and timing models. A guarantee means nothing without its model. Nodes may crash and stop, crash and recover with stable storage, omit messages or behave arbitrarily (Byzantine). Networks may lose, delay, duplicate or reorder messages. Timing may be synchronous (known bounds), asynchronous (no bounds) or partially synchronous (bounds that hold eventually). The FLP result shows that in a fully asynchronous system no deterministic protocol can guarantee consensus if even one process may crash; protocols such as Paxos and Raft therefore keep safety unconditionally and rely on partial synchrony only for liveness.
Safety and liveness. Safety says nothing bad ever happens ("at most one leader per term", "committed entries are never lost"); any violation is visible in a finite prefix of an execution. Liveness says something good eventually happens ("every client request eventually completes"); no finite prefix can violate it, so it needs assumptions such as fairness or eventual timing bounds. Every property can be written as the intersection of a safety property and a liveness property.
Invariants. An invariant holds in every reachable state. To prove one, show it holds initially and that every transition preserves it. If the second step fails, the invariant may still be true but not inductive, and you strengthen it with auxiliary facts, such as "no log entry has a term larger than its server's current term". Raft's safety argument has this shape: Election Safety, Log Matching and Leader Completeness together imply State Machine Safety. Quorum intersection (any two majorities of the same configuration share a member) and monotonically increasing terms or epochs are the recurring building blocks.
Consistency models. Linearizability: every operation appears to take effect atomically at one point between its invocation and its response, respecting real time. Sequential consistency drops the real-time requirement. Serializability concerns multi-object transactions without real-time constraints; strict serializability adds them. Weaker models such as causal or eventual consistency trade guarantees for availability. To check a history for linearizability, find an order of operations that respects real-time precedence and the object's sequential specification. Knossos and Porcupine automate this for registers and key/value maps; Elle checks transactional isolation anomalies.
Model checking. TLA+ describes a system as an initial-state predicate and a next-state relation. The TLC model checker explores every reachable state of a small instance (three servers, two values, bounded terms) and prints a counterexample trace when an invariant fails. It finds design bugs that random testing would need enormous luck to hit, but it is bounded: passing small instances is evidence, not proof. Machine-checked proofs or careful hand proofs cover the general case.
Traces. In practice you debug by reconstructing a timeline: per-node logs with terms, indices and message identifiers, merged in happens-before order. Find the first state that violates an invariant, then ask which message or timeout produced it. The 6.5840 Raft tests write visual timelines of partitions, crashes and checks when a test fails, which makes this skill concrete.
Common misconceptions
- "If tests pass under failures, the protocol is correct." Tests sample a few interleavings; invariants and model checking reason about all of them within a model.
- "Raft makes progress whenever a majority is up." Safety holds always; progress also needs a stable leader and message delays well below the election timeout.
- "Linearizable and serializable mean the same thing." Linearizability is a real-time guarantee on single operations; serializability is about transactions and allows real-time reordering.
- "A true invariant is enough for a proof." It must be inductive; otherwise a step from an unreachable state that satisfies it can break it, and the proof fails.
- "Model checking a small configuration proves the system correct." It shows no violation within the bounds explored; larger configurations or longer histories can still fail.
How to approach it
Restate Raft's Figure 3 properties in your own words and prove one by hand, then work through the 6.5840 linearizability lecture with the Herlihy and Wing paper. Write a small TLA+ specification, plant a bug and read TLC's counterexample. In interviews, open every correctness answer with the fault model, name the invariant, and only then walk through the protocol.
Suggested order
- 1Read Kleppmann’s Cambridge distributed-systems notes, sections 2.3–2.4 (system models and fault tolerance) and 7.2 (linearizability).
- 2Read the Raft paper’s Figure 3 and Section 5.4; write a proof sketch of Leader Completeness in your own words and compare it with Section 5.4.3.
- 3Work through the 6.5840 lecture notes on consistency and linearizability, reading Herlihy and Wing through Section 3.1 as the course assigns.
- 4Read the Jepsen pages on consistency models (linearizable, serializable) and place five models on the hierarchy; skim the FLP paper’s statement and "Defining Liveness" for precise vocabulary.
- 5Watch the first lectures of Lamport’s TLA+ video course, then do the TLA+ model-checking project.
- 6Do 6.5840 Lab 2 (key/value server) and Lab 3 (Raft); when a test fails, use the generated timeline and your logs to find the first invariant violation.
Paper guides: In Search of an Understandable Consensus Algorithm (Extended Version), Dynamo: Amazon's Highly Available Key-value Store, MapReduce: Simplified Data Processing on Large Clusters
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
Distributed Systems (Cambridge Concurrent and Distributed Systems, 2021/22)Start here
University of CambridgeSection: Lecture notes (PDF): system models, Raft, linearizability
Precise definitions of fault and timing models, quorums, linearizability and eventual consistency.
Open(opens in a new tab)Link responded, 5 Oct 2026In Search of an Understandable Consensus Algorithm (Extended Version)Start here
raft.github.ioSection: Figure 3 and Section 5.4: Safety
A complete worked example of invariant-based safety reasoning.
Open(opens in a new tab)Link responded, 5 Oct 2026MIT 6.5840 Distributed Systems
MIT PDOSSection: Lecture notes: Consistency and Linearizability
Linearizability with worked histories, paired with the Herlihy and Wing reading.
Open(opens in a new tab)Link responded, 5 Oct 2026The TLA+ home page
Leslie Lamport (lamport.azurewebsites.net)Awareness-level introduction to specifications, invariants and model checking with TLC.
Open(opens in a new tab)Link responded, 5 Oct 2026Jepsen: distributed systems safety research
Jepsen (jepsen.io)Section: Consistency models
Precise, cross-linked definitions of consistency models and how they relate.
Open(opens in a new tab)Link responded, 5 Oct 2026
Step 4: Practice
For each lab part, write the invariants your code must maintain before coding and assert them at runtime. When a test fails, find the first violated invariant in the timeline before changing code. The Gossip Glomers challenges listed under the distributed-systems topics are a lighter alternative if the 6.5840 labs are too large.
- MIT 6.5840 labs: key/value server, Raft, fault-tolerant and sharded key/valueOpen(opens in a new tab)Not attemptedMIT 6.5840
- Specify and model-check a small protocol with TLA+Open(opens in a new tab)Not attemptedSelf-directed project (TLA+ tools)
- Fault-inject a replicated key/value store and check its historiesOpen(opens in a new tab)Not attemptedSelf-directed project (Porcupine checker)
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 1Is "every request eventually gets a response" a safety or a liveness property, and why?
- Question 2Why must quorum-intersection arguments use majorities of the same configuration?
- Question 3What makes an invariant inductive?
- Question 4Give a history that is sequentially consistent but not linearizable.
- Question 5What does TLC check that randomized testing cannot?
- Question 6What assumptions does Raft need for liveness but not for safety?
You’re done when you can
- State the fault and timing model, three safety properties and one liveness property for Raft without notes.
- Decide correctly whether four small concurrent histories are linearizable, with a justification for each.
- Write a small TLA+ specification, find a planted bug with TLC and explain the counterexample.
- Explain in under two minutes why FLP does not contradict Raft’s guarantees.
- Localize the first invariant violation in a failing Raft lab run from its logs or timeline.
Finish the lesson
Unlocks next: Failure injection and prototype evaluation


