Types of Failure
Crash, omission, timing and Byzantine failures, from "it stopped" to "it lies". Knowing which ones you're designing for decides how much machinery you need.
“Design for failure” is good advice that doesn’t say which failures. Distributed systems theory sorts them into a ladder, from easiest to handle to hardest. Every rung up needs more machinery.
The ladder
| Failure | What happens | Example |
|---|---|---|
| Crash-stop | A node stops and never comes back | A container killed and not restarted |
| Crash-recovery | A node stops, then returns, possibly having lost in-memory state | A server reboots mid-request |
| Omission | Some messages are lost: sent but never received, or never sent | A dropped packet; a full queue silently discarding |
| Timing | Responses arrive, but too late to be useful | A GC pause makes a healthy node look dead |
| Byzantine | A node behaves arbitrarily: corrupts data, contradicts itself, lies | Faulty hardware, a bug, or a malicious participant |
Why the distinction matters
- Crash failures can be handled by replication and a way to notice the crash, usually a Heartbeat.
- Omission needs retries, which means duplicates, which means idempotency (Message Delivery Semantics).
- Timing failures are the sneaky ones, because a slow node and a dead node look the same from outside. That ambiguity is the heart of FLP Impossibility.
- Byzantine tolerance is expensive: classic protocols need more than three times as many nodes as the failures they tolerate. Most internal systems assume nodes are honest and only crash. Blockchains are the famous exception, because there participants really might lie.
Partial failure is the default
On one machine, things mostly work or crash entirely. In a distributed system, part of the system fails while the rest carries on, and often nobody can tell which part. Designing well means being explicit: “we tolerate crash-recovery and omission, not Byzantine” is a design decision worth writing in an ADR (Architecture Decision Records).
In practice
The frontend has its own version of this ladder. A request can fail fast (crash), never return (omission), return after the user has given up (timing), or return garbage from a misbehaving proxy (a small Byzantine taste). Timeouts, retries with limits, schema validation at the boundary (API Modelling) and clear loading and error states are the same ideas at a smaller scale. Designing what happens after a failure is Regress, Don’t Grind: Graceful Degradation.
- #distributed-systems
- #fault-tolerance
- #reliability
↩ Linked from (5)
- Architecture Decision RecordsEvergreen
…o the natural place to record trade-offs like those in the CAP Theorem or the failure model a system assumes (Types of Failure). See also Design Review Readiness Checklist for the step before a decision is made.
Related: Synchronization · Threads and Processes · Types of Failure · Fallacies of Distributed Computing
- Fallacies of Distributed ComputingEvergreen
…bugs only appear in production, under load, at the worst moment. The fallacies are really a list of the ways failure sneaks in.
- HeartbeatGrowing
…visible connection state is cheap, and it turns a silent failure into a handled one. The wider taxonomy is in Types of Failure.
- Message Delivery SemanticsEvergreen
…a redesign. It's one of the cheapest reliability wins there is. The wider picture of what can go wrong is in Types of Failure, and the underlying channel ideas in Message Passing.
↪ Links to (6)
Related by topic
- Growingmetaphor
Balance Is a Control Loop
Calisthenics Lab - Evergreen
CAP Theorem
Distributed systems - Growing
Message Passing
Distributed systems - Growing
Observability
Platform engineering