Consensus, leader election and distributed locks
We'll cover the following
The problem
Several nodes must agree on one thing (who is the leader, which write comes next, what the config is) even though nodes crash and messages get lost or delayed. Consensus algorithms (Paxos, Raft, ZAB in ZooKeeper) do this with a majority quorum: nothing is decided unless more than half the nodes agree.
- To survive
ffailures you need2f + 1nodes: 3 nodes tolerate 1 failure, 5 tolerate 2. - Use odd sizes. 4 nodes need 3 for a majority, so they still tolerate only 1 failure, the same as 3, at a higher cost.
- Consensus systems are CP (see CAP): the side of a partition that has no majority stops accepting writes.
Raft in one minute
- Every node is a follower, candidate or leader. Time is split into numbered terms; each term has at most one leader.
- The leader takes all writes, appends them to its log and replicates to followers. An entry is committed once a majority has it; only then is it applied and acknowledged.
- Followers expect regular heartbeats. If none arrives within a randomized timeout (roughly 150 to 300 ms), a follower becomes a candidate, bumps the term and asks for votes. A node votes once per term, and only for a candidate whose log is at least as up to date as its own, so committed entries are never lost.
- A leader cut off in a minority cannot commit anything, and it steps down when it sees a higher term.
| System | Consensus used for |
|---|---|
| etcd | Raft; stores all Kubernetes cluster state |
| Consul | Raft; service discovery and config |
| ZooKeeper | ZAB (a Paxos-like protocol); coordination for older Kafka, Hadoop, HBase |
| Kafka KRaft | Raft for cluster metadata, replacing ZooKeeper |
| Spanner, CockroachDB | Paxos / Raft per data range, for strongly consistent distributed SQL |
You almost never implement consensus yourself. You use it through etcd, ZooKeeper, Consul or a database that has it built in.
Leader election in practice
- Candidates race to create an ephemeral node (ZooKeeper) or acquire a lease with a TTL (etcd). The holder is leader and keeps renewing; if it dies, the session or lease expires and another candidate wins.
- Typical uses: one active scheduler or cron runner, primary database failover, the Kafka controller, the owner of a partition.
- For small systems a row in the database you already run (
SELECT ... FOR UPDATE) can be enough, as long as you accept that database as a single point of failure.
Distributed locks and fencing tokens
A lock with a TTL (Redis SET lock:job id NX PX 30000) has a trap: the holder pauses (a long GC, a network stall) longer than the TTL, the lock expires, a second client gets it, and then the first wakes up still believing it holds the lock. Both write.
A: acquires lock -> token 33 ... stalls (GC pause) ... lock expires
B: acquires lock -> token 34, writes to storage with token 34
A: wakes up, writes with token 33 -> storage rejects it (33 < 34)- Fencing token: the lock service hands out an increasing number with each grant, and the resource being protected rejects any write carrying a lower number than the highest it has seen.
- A single-node Redis lock is fine as an efficiency lock (occasionally running a job twice is harmless). For correctness use a consensus-based service (etcd, ZooKeeper) with fencing tokens. The multi-node Redis "Redlock" scheme is debated, so do not lean on it for correctness.
- Often the better answer is to avoid the lock: make the operation idempotent, or use a unique constraint or an optimistic
versioncheck in the database.
Split brain
Split brain means two nodes both think they are the leader after a network partition, and both accept writes. Prevent it with quorum (a minority cannot act) and fencing (a stale leader's writes are rejected).
Check yourselfA 5-node etcd cluster is split by a partition into 3 and 2 nodes. Which side accepts writes, and what happens to a leader on the 2-node side?
Only the 3-node side has a majority, so it elects a leader and commits writes. The 2-node side cannot reach quorum: its old leader cannot commit and steps down once it sees a higher term. Reads served by minority nodes may be stale unless they go through the leader.
Check yourselfWhy do clusters use 3 or 5 nodes, not 4 or 6?
A majority of 4 is 3, so 4 nodes still tolerate only 1 failure, the same as 3, while costing more and adding another node that can fail. Odd sizes give the most fault tolerance per node.
Summary: say it in the interview
- "I would not build consensus. I would use etcd or ZooKeeper for leader election and locks, with lease TTLs and fencing tokens so a paused old leader cannot corrupt data."