AnyLearn
All lessons
Programmingadvanced

Failure and Time in Distributed Systems

Distributed systems break in ways single machines don't: nodes crash silently, messages vanish, and clocks lie. Learn the standard failure taxonomy, why a global clock is physically impossible, and how Lamport and vector clocks let you reason about causality without one.

Not signed in โ€” your progress and quiz score won't be saved.
Lesson progress1 / 8

System models: synchronous vs. asynchronous

Every distributed systems proof assumes a system model that bounds what can go wrong.

  • Synchronous model: message delivery has a known upper bound ฮ”\Delta; clock drift is bounded; steps complete in bounded time. Rare in practice โ€” a GC pause or a busy NIC can blow the bound.
  • Partially synchronous model (Dwork-Lynch-Stockmeyer): the system is eventually synchronous โ€” bounds exist but you don't know when they kick in. Matches real WANs and cloud networks.
  • Asynchronous model: no timing guarantees whatsoever. Messages can be delayed arbitrarily. Hardest to work with โ€” algorithms that are correct here are correct everywhere.

Most production consensus protocols (Raft, Paxos) are designed for partial synchrony: they are safe (never return wrong answers) in an asynchronous model, but live (eventually return answers) only under partial synchrony.

Full lesson text

All 8 steps on one page โ€” for reading, reference, and search.

Show

1. System models: synchronous vs. asynchronous

Every distributed systems proof assumes a system model that bounds what can go wrong.

  • Synchronous model: message delivery has a known upper bound ฮ”\Delta; clock drift is bounded; steps complete in bounded time. Rare in practice โ€” a GC pause or a busy NIC can blow the bound.
  • Partially synchronous model (Dwork-Lynch-Stockmeyer): the system is eventually synchronous โ€” bounds exist but you don't know when they kick in. Matches real WANs and cloud networks.
  • Asynchronous model: no timing guarantees whatsoever. Messages can be delayed arbitrarily. Hardest to work with โ€” algorithms that are correct here are correct everywhere.

Most production consensus protocols (Raft, Paxos) are designed for partial synchrony: they are safe (never return wrong answers) in an asynchronous model, but live (eventually return answers) only under partial synchrony.

2. Failure taxonomy

Failures fall into a hierarchy โ€” each level strictly includes the one above.

Failure typeWhat happensDetectability
Crash-stopNode halts permanently, sends nothing afterEasy (timeout)
Crash-recoveryNode halts then restarts, may lose in-memory stateMedium (rejoin protocol)
OmissionNode runs but drops some sends or receivesHard (message vs. node dead?)
ByzantineNode behaves arbitrarily โ€” lies, replays, colludesVery hard (requires n>3fn > 3f nodes)

The hierarchy matters for algorithm design: a protocol that tolerates crash-stop failures fails catastrophically against Byzantine nodes. Most data-center systems assume crash-recovery; Byzantine tolerance (BFT) is reserved for blockchains or safety-critical systems where nodes may be adversarially controlled.

3. Why there is no global clock

Physical clocks on separate machines drift โ€” even NTP-synchronized clocks have error on the order of milliseconds (wide-area) to microseconds (GPS-disciplined PTP). The fundamental constraint is the speed of light: a clock sync message takes nonzero time in transit, so you can never know the sender's clock reading right now.

The consequence: you cannot order events across nodes by wall-clock time. Consider two writes at t1=10:00:00.001t_1 = 10:00:00.001 on node A and t2=10:00:00.000t_2 = 10:00:00.000 on node B โ€” which came first? Without coordination, you don't know. Spanner's TrueTime API bounds clock uncertainty and forces transactions to wait out the uncertainty window โ€” expensive hardware, not a free lunch. For most systems the answer is logical clocks.

4. Lamport logical clocks

Leslie Lamport's 1978 insight: define a partial order directly from communication โ€” no wall-clock needed.

Happens-before (โ†’\to) is the smallest relation satisfying:

  1. If aa and bb are events on the same process and aa comes before bb, then aโ†’ba \to b.
  2. If aa = "send message mm" and bb = "receive mm", then aโ†’ba \to b.
  3. Transitivity: aโ†’ba \to b and bโ†’cb \to c implies aโ†’ca \to c.

Events not related by โ†’\to are concurrent. Lamport assigns integer timestamps:

On every event: L = L + 1
On send: attach L to message
On receive(msg): L = max(L, msg.L) + 1

Guarantee: aโ†’bโ‡’L(a)<L(b)a \to b \Rightarrow L(a) < L(b). The converse is false โ€” identical or higher timestamps don't imply causality. Lamport clocks capture direction but not full causal history.

5. Vector clocks

Vector clocks fix Lamport's converse gap. Each of nn processes maintains a vector VV of nn counters.

# Process i initializes: V = [0] * n
# On internal event: V[i] += 1
# On send: V[i] += 1; attach V
# On receive from j with timestamp T:
#   V[k] = max(V[k], T[k]) for all k
#   V[i] += 1

Comparison rules:

  • Vaโ‰คVbV_a \leq V_b iff Va[k]โ‰คVb[k]V_a[k] \leq V_b[k] for all kk.
  • aโ†’ba \to b iff Vaโ‰คVbV_a \leq V_b and Vaโ‰ VbV_a \neq V_b.
  • aโˆฅba \parallel b (concurrent) iff neither Vaโ‰คVbV_a \leq V_b nor Vbโ‰คVaV_b \leq V_a.

Vector clocks are characterize happens-before: aโ†’bโ‡”Va<Vba \to b \Leftrightarrow V_a < V_b. The cost is O(n)O(n) space per message โ€” fine for small clusters, painful for thousands of nodes (use version vectors or dotted version vectors instead).

6. Vector clock example: three processes

Three processes P1,P2,P3P_1, P_2, P_3 with vector clocks [v1,v2,v3][v_1, v_2, v_3]:

EventWhoClock after
e1e_1: internalP1P_1[1,0,0]
e2e_2: P1P_1 sends to P2P_2P1P_1[2,0,0]
e3e_3: P2P_2 receives from P1P_1P2P_2[2,1,0]
e4e_4: internalP3P_3[0,0,1]
e5e_5: P2P_2 sends to P3P_3P2P_2[2,2,0]
e6e_6: P3P_3 receives from P2P_2P3P_3[2,2,2]

Now: e1โ†’e6e_1 \to e_6 because [1,0,0]<[2,2,2][1,0,0] < [2,2,2]. And e1โˆฅe4e_1 \parallel e_4 because [1,0,0][1,0,0] and [0,0,1][0,0,1] are incomparable โ€” P1P_1 and P3P_3 never communicated before e4e_4. This is the causality structure vector clocks expose that Lamport timestamps cannot.

7. Happens-before across three processes

Arrows show happens-before relationships derived from message passing.

flowchart LR
  e1["P1: e1 [1,0,0]"]
  e2["P1: send e2 [2,0,0]"]
  e3["P2: recv e3 [2,1,0]"]
  e4["P3: e4 [0,0,1]"]
  e5["P2: send e5 [2,2,0]"]
  e6["P3: recv e6 [2,2,2]"]
  e1 --> e2
  e2 --> e3
  e3 --> e5
  e4 --> e6
  e5 --> e6

8. Practical uses of logical clocks

Logical clocks aren't academic โ€” they drive production systems:

  • Conflict detection in CRDTs and eventual-consistent stores: Dynamo and Riak use vector clocks (actually version vectors) to detect when two writes are concurrent and hand the conflict to the application.
  • Distributed tracing: systems like Jaeger propagate a Lamport-style counter in HTTP headers (traceparent) to reconstruct request causality across microservices.
  • Optimistic replication: a replica accepts a write only if its vector clock shows the write's causal dependencies are already applied โ€” preventing you from seeing a reply before its question.
  • Debugging distributed bugs: tools like Molly and DistSys-Tester inject failures and check vector clock orderings to find violations of expected causal constraints.

The core lesson: when you cannot trust clocks, define order through communication โ€” and vector clocks make that order computable.

Check your understanding

The lesson ends with a 5-question quiz. Take it in the player above to see your score.

  1. A crash-recovery failure differs from a crash-stop failure in that:
    • The node sends incorrect data before halting.
    • The node may restart and rejoin, potentially with stale in-memory state.
    • The node drops some messages but never halts.
    • The node behaves arbitrarily under adversarial control.
  2. Lamport timestamps satisfy: if $a \to b$ then $L(a) < L(b)$. Which additional property do vector clocks add?
    • Vector clocks also bound the physical time difference between events.
    • Vector clocks make the converse true: $L(a) < L(b)$ implies $a \to b$.
    • Vector clocks characterize happens-before in both directions: $a \to b$ iff $V_a < V_b$.
    • Vector clocks reduce message overhead compared to Lamport timestamps.
  3. Process $P_1$ has vector clock $[3, 1, 0]$ and process $P_2$ has $[2, 2, 0]$. What is the relationship between the events at these timestamps?
    • $P_1$'s event happened before $P_2$'s event.
    • $P_2$'s event happened before $P_1$'s event.
    • The events are concurrent โ€” neither happened before the other.
    • The events are on the same process, so physical time determines order.
  4. Why is the partially synchronous model more realistic than the fully synchronous model for most production networks?
    • Partial synchrony allows message reordering, which real networks never do.
    • Full synchrony requires all messages to arrive simultaneously, which TCP prevents.
    • GC pauses, CPU contention, and network congestion can violate fixed timing bounds, making guaranteed upper bounds unrealistic.
    • Partial synchrony is required by the TCP/IP specification.
  5. In a system using vector clocks for replication, node B receives a write with attached clock $[0, 1, 0]$, but B's current state is at $[0, 0, 0]$. What should B do?
    • Apply the write immediately and set its clock to $[0, 1, 0]$.
    • Reject the write permanently as out of order.
    • Check whether the write's causal dependencies are satisfied before applying; here they are, since $[0,0,0]$ precedes $[0,1,0]$.
    • Request the full history from node A to reconstruct causal ordering.

Related lessons