KubernetesLXVI · etcdetcd fundamentals
Raft consensus — leader election, terms, log replication
What you'll learn
- Describe the Raft concepts etcd implements
- Trace a leader election under member loss
- Explain the log replication and commit path
- Reason about what Raft guarantees and what it does not
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
Raft is the algorithm etcd uses to keep multiple replicas of a key-value store in lockstep. It is a deliberate, choreographed version of “the majority wins”: every change is recorded by a leader, replicated to followers, and acknowledged by a majority before it is considered committed. This lesson walks the pieces — terms, leaders, elections, log entries, commit — and what each one buys and what each one costs.
Raft in one sentence
A replicated log: one leader at a time receives every
write; followers replicate the leader’s log entries; a
write is committed when a majority of members have
acknowledged it. Cluster survives floor(N/2) member
losses; it does not survive loss of majority.
Terms
A term is a monotonically increasing integer. Terms form logical epochs:
sequenceDiagram
participant L1 as Leader (term 5)
participant F1 as Follower
participant F2 as Follower
participant L2 as Leader (term 6)
Note over L1: term 5 active
L1->>F1: AppendEntries (term 5)
L1->>F2: AppendEntries (term 5)
L1-->>L1: L1 fails / network partition
F1->>F2: RequestVote (term 6)
F2->>F1: vote granted (term 6)
L2->>F1: AppendEntries (term 6)
L2->>F2: AppendEntries (term 6)
A new term begins whenever a follower concludes the leader is gone and becomes a candidate. Two leaders can exist temporarily during an election; only one wins (the candidate that secures a majority of votes for the new term). A leader that discovers a higher term immediately steps down to follower.
Leader election
flowchart LR
F[Follower] -->|election timeout| C[Candidate]
C -->|RequestVote majority granted| L[Leader]
C -->|higher term seen| F
L -->|AppendEntries beat heart| F
L -->|higher term seen| F
Key parameters:
- Heartbeat interval (
--heartbeat-interval): how often the leader sends emptyAppendEntriesto followers. The default for etcd is 100 ms. - Election timeout (
--election-timeout): how long a follower waits without a heartbeat before voting. The default for etcd is 1000 ms. - Quorum (
floor(N/2) + 1): the number of votes (or acknowledgements) needed.
The election timeout is randomised across followers so that two followers do not both become candidates at the same instant; that randomisation is the only thing standing between a healthy cluster and a livelock.
The replicated log
Every write becomes a log entry. The log entry has:
term: the term in which the entry was created.index: the entry’s position in the log (monotonic).data: the operation (aPut, aTxn, aDeleteRange, etc.).
The leader appends to its log first; then replicates to
followers; then waits for acknowledgements. An entry is
committed when a quorum of members has persisted it to
their logs; the leader’s commitIndex advances; the
followers learn of the advance through subsequent
heartbeats.
sequenceDiagram
autonumber
participant Client
participant L as Leader
participant F1 as Follower 1
participant F2 as Follower 2
Client->>L: txn If(...){Put(k,v)}
L->>L: append to log (term N, index 41289312)
L->>F1: AppendEntries (term N)
L->>F2: AppendEntries (term N)
F1->>L: ack index 41289312
F2->>L: ack index 41289312
Note over L: quorum ack -> commit
L->>F1: AppendEntries (commitIndex=41289312)
L->>F2: AppendEntries (commitIndex=41289312)
L-->>Client: txn OK
If the leader fails after persisting but before acknowledging, a new leader’s election starts from the last committed index, and the uncommitted entries on the old leader are discarded. That is why cluster state never regresses: a new leader cannot claim to have committed entries that a prior leader only replicated.
What Raft guarantees
etcd’s API documentation defines two model guarantees (both from Raft):
- Linearizable reads. A read served by the cluster reflects at least the most recent write at the time the read was issued. Reads go through a “read-index” protocol on the leader or are routed through the leader to ensure they don’t return stale data.
- Linearizable writes. A write that returns success has been committed to a quorum. Any subsequent read is guaranteed to see that write.
Both guarantees depend on the leader being authoritative. A partitioned “leader” that cannot reach a quorum cannot commit new writes; that is the central safety property that prevents split-brain.
What Raft does not guarantee
flowchart LR
W[write attempt] -->|leader=| LO[append & replicate]
LO -->|ack quorum| C[commit]
LO -->|lost quorum| BLOCK[block: no commit]
W2[write attempt] -->|leader unreachable| FAIL[no leader: write rejected]
- Not every write succeeds. If the cluster has lost quorum, writes fail; the leader does not fabricate acknowledgements it does not have.
- Not every read succeeds. Reads that require linearizable semantics fail if the leader cannot confirm its leadership to a quorum (the read-index protocol times out).
- Not every member is up-to-date. Followers can lag. Reads from a stale follower return stale data unless the client asks for a linearizable read that goes through the leader.
- Not every committed entry is applied immediately. The
Applied Indexcan lag theCommitted Indexif a member is busy. A leader with a highraft indexbut a lowraft applied indexis a leader that is committing but not keeping up.
$ etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key endpoint status --write-out=json 2>/dev/null | jq '.[0]'{
"Endpoint": "https://10.0.1.10:2379",
"ID": "c5e9a1b2...",
"Status": {
"leader": "c5e9a1b2...",
"term": 17,
"raftIndex": 41289312,
"raftAppliedIndex": 41289312,
"raftTerm": 17,
"dbSize": 1500000000,
"dbSizeInUse": 880000000
}
}Why the leader matters
Every write goes through the leader. If a follower receives a write request from a client, it forwards to the leader; if no leader exists, the write fails. The read-index protocol ensures linearizable reads by forcing them through the leader:
- The follower confirms the leader is still the leader (heartbeat to a quorum).
- The follower reads its state at the leader’s
commitIndex + 1. - The follower returns the read to the client.
This protocol is what makes a follower safe to read from; without it, a partitioned “leader” on a minority side could serve stale reads.
Failure modes Raft handles
| Failure | Raft behaviour |
|---|---|
| Leader crash | Election; new leader elected by majority |
| Follower crash | Leader retries replication; follower catches up on return |
| Network partition (minority side) | Minority refuses to commit; majority commits unaffected |
| Network partition (majority side) | Whole cluster refuses to commit until healed |
| Slow disk on a follower | Slow acknowledgement; commit waits for quorum |
| Clock skew between members | Heartbeat-based, not clock-based; Raft tolerates skew within reason |
| Replayed messages | Term numbers guarantee old leaders’ messages are ignored after a new term |
What Raft asks of the operator
- Time. The election timeout must be larger than the longest expected network round trip; a tight WAN election timeout with packet loss will trigger spurious elections.
- Quorum. The cluster size determines fault tolerance. Three members: tolerate one. Five members: tolerate two.
- Network. Both low-latency (heartbeats) and reliable (the partition model is unforgiving).
- Disk.
fsynclatency bounds commit latency directly. A member with a slow disk slows every write to the cluster.
UnderTheHood title=“Snapshot install during catch-up”> When a follower has been offline long enough that its log no longer matches the leader’s, the leader sends a snapshot instead of log entries. The snapshot is the compressed state at a known log index; the follower truncates its log up to that index and installs the snapshot. This is what lets a freshly built member join the cluster without streaming the entire log from day one.
Quiz
Knowledge check · 4 questions
Q1. A 5-member etcd cluster has lost 2 members simultaneously. What is the cluster's state?
Q2. By default, every etcd read goes through the leader and pays the same latency as a write.
Q3. Two of three etcd members have intermittent network connectivity to the leader. The leader's term number is rising (4 -> 5 -> 6 -> 7) every minute. Diagnose and remediate.
3-member etcd cluster, members A (leader), B, C. Network between A and B is fine; between A and C is unreliable; between B and C is fine. The cluster console shows term increments every ~60 seconds. The API server logs show intermittent 'etcdserver: request timed out' messages. kubectl apply works most of the time but occasionally returns errors.
Q4. Why does a linearizable read from a follower have to round-trip through the leader?
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Know your quorum arithmetic. 3 members tolerate 1 loss; 5 tolerate 2. Past that, writes halt.
- Tune election and heartbeat for the network. Tight timeouts on a wide-area network will trigger spurious elections; loosen to the largest expected round trip.
- Watch leader changes. Each change is an election. Sustained leader changes correlate with network instability.
- Disk before network. A slow fsync on a single member is the most common etcd regression; check it before chasing the network.
- Linearizable reads on demand.
kubectl getdoes not need them; controllers watching for the most recent state do. Use the right semantics for the right consumer.
Raft is the algorithm etcd uses; understanding it is what turns “etcd is slow” into “the disk fsync on member B is slow”.