Skip to main content

Leader Election, Leases, Fencing & Split-Brain

Level 5: Level 5: Distributed Systems Corehard35 minleader-electionfencingsplit-brain

A GC pause can create two leaders despite a valid lease, so enforce monotonic fencing tokens at the storage layer; on a 3-2 split the majority leads and the minority is fenced.

One leader, guaranteed, even when the network lies

Many systems need a single active primary: one node that owns writes, holds a lock, or coordinates work. The hard part is not electing one, it is guaranteeing there is never a second one acting at the same time, because the asynchronous network gives you no reliable way to tell a dead primary from a slow one.

Electing is the easy half. Run it through a consensus system: etcd, ZooKeeper, or Consul, or a Raft/Paxos group directly. The primary holds a lease: a time-bounded grant ("you are leader until T+10s") it must renew. If renewals stop, the lease expires and a new election runs. Leases need no per-request coordination, but they carry a hidden assumption: bounded clocks and bounded pauses.

Check yourself
Leader L holds a valid 10-second lease and is mid-write when a 15-second stop-the-world GC pause hits. The lease expires and L2 is elected. What does L do the instant it wakes?

The canonical failure

Leader L holds a 10-second lease and is mid-write. L suffers a stop-the-world GC pause (or the VM is descheduled, or a disk stall) for 15 seconds. From everyone else's view, L went silent, its lease expired, and a new leader L2 was elected and started writing. Then L wakes up. L does not know time passed. It believes it still holds the lease and completes its in-flight write. Now two leaders have both written: split-brain, and the data is corrupted. No clock was "wrong" and no bug was hit; a legal pause alone produced two active leaders.

Check yourself
Where must the defense live so that the woken leader's stale write actually fails?

Fencing tokens: enforce at the resource

Leases alone cannot fix this, because the paused leader's problem is that its own view of "do I still hold the lease" is stale. The fix lives at the resource. Every time leadership is granted, the coordinator hands out a monotonically increasing number (etcd revision, ZooKeeper zxid, a Raft term). The leader attaches that token to every write. The storage layer remembers the highest token it has seen and rejects any write with a lower token. When paused L wakes and writes with token 33, storage has already accepted L2's token-34 writes and rejects L. This is the piece a distributed lock must have: a lock that only tells the client "you have it" is unsafe, because the client can be paused between acquiring and using it. This is exactly Martin Kleppmann's critique of Redlock.

The token is checked where the damage would happen
Step 1 / 3

Stage 1 of 3: Leadership is granted with a monotonically increasing token: an etcd revision, a ZooKeeper zxid, or a Raft term.

A paused leader cannot be trusted to check whether it is still the leader, because its own view is exactly what went stale. Only the resource can know, which is why a lock that merely tells the client 'you have it' is unsafe. This is Kleppmann's critique of Redlock in one picture.

Split-brain and partitions

Take a 5-node cluster split 3-2. Consensus-based leadership requires a majority quorum (3 of 5). The majority side can elect and keep a leader and stays writable; the minority side cannot reach quorum, steps down, and refuses writes. This is the CP choice (Raft/etcd/ZooKeeper). The AP alternative (Dynamo-style) lets both sides keep accepting writes and reconciles later with CRDTs/version vectors. Either way, fence the minority: the losing side must be provably unable to affect shared state. A 2-2 split of 4 nodes has no majority on either side, which is why consensus clusters use odd numbers.

Interview nuance: the answer that gets you hired names both halves: consensus/lease for who leads, and a fencing token enforced at the storage layer for why a paused old leader cannot corrupt state. Stopping at "etcd elects a leader" fails the follow-up "what happens during a GC pause?"

Recap: elect one leader via consensus and a lease, but because a GC pause can briefly create two leaders, enforce fencing tokens (monotonic numbers the storage rejects if stale); on a 3-2 split the majority stays writable (CP) or both sides reconcile (AP), and either way the minority is fenced.

Check yourself

A 5-node cluster splits 3-2. Sort each behavior by which side of the partition it belongs to.

Keeps or elects the leader and stays writable
Cannot reach quorum and steps down
Its late writes bounce off the highest-token rule after the partition heals
Hands out the next, higher fencing token with the new leadership grant

Apply

Your turn

The task this lesson builds to.

Design a single-active-primary system so that when the primary is wrongly suspected and a new one is elected, the old primary cannot corrupt shared state, and specify behavior on a 3-2 partition.

Think about

  1. How can a GC pause make a live leader look dead and cause two leaders?
  2. What do fencing tokens do that leases alone cannot?
  3. How does a 5-node cluster behave when split 3-2?

Practice

Make it stick

A second problem on the same idea, so it survives past today.

Design leader election and fencing for a distributed job scheduler like a Kubernetes controller-manager or a cron system where exactly one active scheduler may assign jobs, running 5 replicas across 3 availability zones, so that a network partition or a 30-second scheduler pause can never cause a job to run twice.

Think about

  1. Where must fencing be enforced so a paused scheduler's stale claim fails?
  2. What second net catches a duplicate even after fencing?
  3. How does the AZ layout interact with etcd quorum?