← Back to Logs

How Raft Actually Works

Try the interactive lab for this articleTake the quiz (6 questions · ~6 min)

Raft is often introduced as the friendly consensus algorithm. That description is useful once, then it starts hiding the real machinery.

Consensus is not about making servers "agree" in a vague social sense. It is about making a cluster behave like one durable state machine even when machines crash, packets vanish, disks stall, and leadership changes in the middle of writes. If a control plane in Amsterdam accepts a lock acquisition, a configuration update, or a scheduler decision, every future leader has to preserve that decision in the same position in history. If it cannot do that, the cluster is not a database or a co-ordination system. It is a race condition with a logo.

Raft solves a specific problem under a specific failure model. Nodes may crash and later recover. Messages may be delayed, duplicated, or dropped. Storage is assumed to be durable enough that if a node says it has flushed a log entry, that entry survives a reboot. Nodes are not assumed to be malicious. Raft is not Byzantine fault tolerance. It will not save you from a host that fabricates votes, lies about disk flushes, or runs attacker-controlled code. What it does do is turn a group of ordinary crash-prone servers into a system that can elect one leader, replicate one ordered log, and apply only the commands that became safe through quorum.

The easiest way to misunderstand Raft is to think of it as leader election plus heartbeat messages. That is only the visible part. The hard part is the log discipline underneath: when a follower may vote, how a leader proves continuity with earlier history, why a majority append is not always enough to declare commitment, how lagging followers repair conflicts, and how membership changes avoid creating two disjoint majorities. Those details are why etcd can back Kubernetes, why Consul can store service co-ordination state, and why a badly tuned Raft cluster can flap itself into an outage.

This article walks through the actual mechanism. We will use a five-node cluster spread across Amsterdam, Frankfurt, Milan, Brussels, and Athens, because that makes the quorum arithmetic concrete and the network costs honest.

Raft Replicates A Deterministic State Machine, Not A Database File

A Raft cluster exists to replicate commands in one globally agreed order. Each node stores the same sequence of log entries. Each node then applies the committed entries to the same deterministic state machine. If every node starts from the same initial state and applies the same committed commands in the same order, every healthy node reaches the same result.

That state machine might be:

  • a key-value store such as etcd
  • a scheduler's placement state
  • a lock table
  • a metadata catalogue
  • a control-plane configuration store

The key detail is determinism. If entry 417 says set /feature-flags/payments = enabled, every node must interpret that command the same way. Raft does not replicate mutated memory or already-rendered objects. It replicates the ordered input stream.

A log entry is conceptually simple:

index: 417
term: 12
command: set /feature-flags/payments = enabled

The cluster only exposes the command to the state machine after it becomes committed. In Raft, commitment means a leader has established enough quorum-backed evidence that the entry will survive future leadership changes. That wording matters. A follower receiving bytes is not enough. Even a majority storing bytes is not always enough, as we will see later.

Five nodes means the quorum size is:

quorum = floor(N / 2) + 1
       = floor(5 / 2) + 1
       = 3

So any decision that needs a majority needs three votes or three durable appends. Two nodes can fail and the cluster may still retain history, but it cannot continue making progress if it loses three nodes or if network partitions split it into groups smaller than three.

This is the first useful mental model:

client command
   -> leader appends log entry locally
   -> leader replicates entry to followers
   -> majority confirms durable append
   -> leader marks entry committed
   -> state machines apply the entry in order
   -> client sees success

Everything else in Raft exists to keep that pipeline honest across crashes and leadership changes.

Terms, Roles, And Indices Define The Shared Vocabulary

Raft stays understandable by giving a small set of state variables very strict meaning. If you lose track of them, the rest of the algorithm becomes folklore.

Terms Are Leadership Epochs

A term is a monotonically increasing election epoch. It answers the question: under which leadership generation did this event happen?

  • Every node starts in term 0 or 1 depending on implementation.
  • If a node times out and starts an election, it increments its current term.
  • If a node receives an RPC carrying a higher term than its own, it updates its term and steps down to follower.
  • At most one leader may exist per term if the protocol rules are followed.

Terms are attached to every log entry. That gives later leaders evidence about how recent a follower's history really is.

Roles Are Operational States, Not Job Titles

Raft nodes move between three roles:

Role What it does What it must not do
Follower Responds to leaders and candidates, stores replicated log entries, applies committed entries Accept client writes as authoritative leader
Candidate Starts an election, requests votes for a new term Assume leadership before winning a majority
Leader Accepts client commands, appends entries, replicates log, decides commitment, sends heartbeats Share leadership with another node in the same term

A node is follower by default. Candidate is temporary. Leader is exclusive.

Indices Track Three Different Things

Raft implementations usually carry several counters. The important ones are:

  • last log index: highest index present in the local log
  • commitIndex: highest index known to be committed
  • lastApplied: highest committed index already applied to the state machine
  • nextIndex[follower]: next log index the leader will try to send to a follower
  • matchIndex[follower]: highest log index the leader knows that follower has stored

These are easy to blur together, but they answer different questions.

A follower might have received entries through index 421 while commitIndex is still 417. Those extra entries are speculative history. They are present, but not yet safe for the state machine to consume.

A leader might know that Frankfurt has matched through 421, Milan through 421, Brussels through 417, and Athens through 409. That distribution determines which entries are committed and which followers need repair.

The Safety Properties Are Better Than The Marketing Summary

The original Raft paper by Diego Ongaro and John Ousterhout describes several core guarantees. These are the real contract.

  1. Election Safety: at most one leader can be elected in a given term.
  2. Leader Append-Only: a leader never overwrites or deletes entries in its own log. It only appends.
  3. Log Matching: if two logs contain an entry with the same index and term, then the logs are identical in all earlier entries.
  4. Leader Completeness: if an entry is committed in a term, every later leader will contain that entry.
  5. State Machine Safety: if a node applied a log entry at a given index, no other node will ever apply a different command at that same index.

Those are not academic decorations. Every rule in the protocol is there to preserve them.

Elections Work Because Timeouts Are Random And Votes Are Constrained

Raft elects a leader when followers stop hearing from the current one. The mechanism sounds simple, but the timer discipline matters.

Followers Wait For Heartbeats Or Append Traffic

A leader sends periodic AppendEntries RPCs, often empty heartbeats when there is no new data. Followers reset their election timers every time they receive valid leader traffic for the current term.

If a follower's election timeout expires first, it assumes leadership may be dead and becomes a candidate.

The candidate then:

  1. increments currentTerm
  2. votes for itself
  3. sends RequestVote to every other node
  4. waits for a majority of votes, another valid leader, or a higher term

A minimal vote request looks like this:

RequestVote {
  term: 13
  candidateId: frankfurt
  lastLogIndex: 417
  lastLogTerm: 12
}

The receiver answers with:

RequestVoteResponse {
  term: 13
  voteGranted: true
}

A node grants at most one vote per term. That alone prevents obvious double elections.

Random Timeouts Prevent Endless Split Votes

If every follower used the same exact timeout, leader failure would often cause several nodes to start elections together. With five nodes, Amsterdam might die and Frankfurt, Milan, and Athens might all become candidates in term 13 at almost the same instant. Each would vote for itself. The cluster could spend multiple rounds colliding.

Raft breaks that symmetry with randomised election timeouts. The original paper used a range such as 150 to 300 ms for its examples. Real systems tune the numbers based on network and disk latency, but the principle stays the same: give each follower a slightly different deadline so one candidate is likely to move first.

A typical failure looks like this:

T+000 ms  Amsterdam leader fails
T+184 ms  Frankfurt election timer expires first
T+185 ms  Frankfurt becomes candidate for term 13
T+186 ms  Frankfurt votes for itself
T+188 ms  Frankfurt sends RequestVote to Milan, Brussels, Athens
T+194 ms  Milan grants vote
T+197 ms  Athens grants vote
T+197 ms  Frankfurt has 3 votes including itself -> becomes leader
T+198 ms  Frankfurt sends AppendEntries heartbeat for term 13
T+205 ms  Brussels sees new leader and stays follower

The random delay does not guarantee a single-round election every time, but it makes rapid convergence very likely in healthy conditions.

Higher Terms Always Win The Argument

Suppose Milan is still acting like leader in term 12 because it was isolated and slow to notice the cluster moved on. Frankfurt, now leader in term 13, sends an AppendEntries with term = 13. Milan must update its term and step down. A node never keeps leading after learning a higher term exists.

That rule is what lets the cluster recover from stale beliefs after partitions. It is also why timeouts must be conservative enough that healthy leaders are not constantly mistaken for dead ones. A GC pause, scheduler stall, or overloaded disk that delays heartbeats longer than the election timeout can create unnecessary term churn.

A Vote Is Also A Check On Log Freshness

If elections were decided by "first request wins", Raft would be unsafe. A stale node could become leader and overwrite history that the majority already accepted. The voting rule therefore includes a freshness check.

Up To Date Means Comparing Last Term First, Then Last Index

A follower grants its vote only if the candidate's log is at least as up to date as the follower's own log.

The comparison is strict and slightly unintuitive:

  1. Compare lastLogTerm.
  2. The higher last term wins.
  3. If last terms are equal, compare lastLogIndex.
  4. The higher index wins.

So a shorter log can still be more up to date if its last entry belongs to a newer term.

Example:

Frankfurt: lastLogTerm = 12, lastLogIndex = 417
Brussels:  lastLogTerm = 11, lastLogIndex = 421

Frankfurt is considered more up to date even though Brussels has more entries. Brussels' tail is older history. Some of those entries may be uncommitted remnants from an old leader. Voting for Brussels would risk reviving stale history.

Why This Preserves Leader Completeness

Imagine Amsterdam was leader in term 12 and successfully committed entry 417 to Amsterdam, Frankfurt, and Milan. Then Amsterdam crashes.

Any future leader needs to contain entry 417. Why? Because clients may already have seen the command succeed.

Now suppose Brussels does not have entry 417 and tries to become leader. Could it win? Only if a majority votes for it. But at least one node from the majority that stored 417 must be part of any new majority. That node will see Brussels has an older log and refuse the vote. The stale candidate cannot assemble quorum.

This is the heart of Raft safety. Quorum intersection alone is not enough. The intersecting node also has to refuse leaders that lack committed history. The log freshness rule is how it does that.

The Vote Carries Storage Semantics Too

A practical implementation persists currentTerm and votedFor to stable storage before replying. If it does not, a node could reboot and accidentally cast a second vote in the same term. That would break election safety.

The rule sounds small, but it is why disk latency can affect election behaviour. Consensus is not only about network messages. It is also about which promises survive power loss.

AppendEntries Is The Mechanism That Keeps One History

AppendEntries does two jobs at once.

  1. It tells followers which node is leader for the current term.
  2. It replicates log entries while proving continuity with existing history.

The message is richer than the name suggests.

AppendEntries {
  term: 12
  leaderId: amsterdam
  prevLogIndex: 416
  prevLogTerm: 12
  entries: [
    { index: 417, term: 12, command: set /feature-flags/payments = enabled }
  ]
  leaderCommit: 416
}

prevLogIndex And prevLogTerm Are The Fence Posts

When a follower receives this RPC, it first checks whether its own log contains an entry at prevLogIndex with term prevLogTerm.

  • If yes, the follower knows the leader and follower agree up through that point.
  • If no, the follower rejects the RPC.

That check is what prevents a leader from blindly appending onto a divergent suffix.

Suppose Brussels has:

414 term 11
415 term 11
416 term 11
417 term 11

while the real leader in term 12 has:

414 term 11
415 term 11
416 term 12
417 term 12

The leader sends prevLogIndex = 416, prevLogTerm = 12. Brussels looks at index 416, sees term 11, and rejects the append. That rejection tells the leader the follower's log diverged before the new entries even start.

Leaders Repair Conflicts By Backing Up

A naive leader could decrement nextIndex[brussels] one entry at a time and retry until the follower finds a matching prefix. That works, but it can be slow if the follower is far behind.

The conceptual repair loop is:

leader tries prevLogIndex 417 -> reject
leader tries prevLogIndex 416 -> reject
leader tries prevLogIndex 415 -> accept
leader resends entries 416 onward
follower deletes conflicting local suffix
follower appends leader's entries

Once a follower accepts an append after a matching prefix, it must delete any conflicting entries that follow and append the leader's version. That is how the cluster converges back to one history.

The important safety point is that only uncommitted entries are ever discarded this way. Committed entries cannot disappear from a later leader because the election rules prevented a leader without them.

Heartbeats Are Empty Appends

An empty AppendEntries still carries term, prevLogIndex, prevLogTerm, and leaderCommit. Even with no new data, it serves several purposes:

  • asserts current leadership
  • resets follower election timers
  • advances a follower's commitIndex
  • lets the leader detect liveness and lag

That is why saying "Raft heartbeats are just pings" is misleading. They are miniature log-coherence checks.

Leaders Track Follower Progress Explicitly

For every follower, the leader keeps at least:

  • nextIndex: where to resume sending
  • matchIndex: highest known replicated index

If Athens has acknowledged through 417 and Brussels through 409, the leader can keep accepting new commands while also running catch-up traffic for Brussels. Consensus therefore involves a steady stream of bookkeeping about who has what.

Commitment Is A Quorum Decision, But Not Every Quorum Means Safe Commit

This is the part many shallow explanations skip.

A leader does not mark an entry committed the moment one follower acks it. It waits until the entry is stored on a majority. With five nodes, that usually means leader plus any two followers.

So far, so simple.

The subtlety is that a leader must be careful which entries it treats as committed based on majority replication.

The Easy Case: Committing An Entry From The Current Term

Suppose Amsterdam is leader in term 12 and appends entry 417 with term 12. Frankfurt and Milan both acknowledge it. Amsterdam now knows that three nodes hold entry 417 in term 12.

At this point Amsterdam may advance commitIndex to 417 and tell followers through future AppendEntries that entry 417 is committed.

That is safe because any later leader must contain that entry. Any future majority intersects the majority that already stored it, and the voting freshness rule blocks candidates that lack it.

The Trap: Earlier Term Entries Can Sit On A Majority Without Being Safe To Declare Directly

Now consider a more awkward case.

  1. Amsterdam was leader in term 11.
  2. It replicated entry 416 to Amsterdam, Frankfurt, and Brussels.
  3. It crashed before the cluster fully stabilised around that fact.
  4. Frankfurt becomes leader in term 12.

Frankfurt may observe that entry 416 from term 11 already sits on a majority. Can it immediately declare that index committed purely because a majority has it?

Raft says no. A leader only uses the majority rule directly for entries from its current term.

Why? Because older term entries can appear on different majorities in scenarios where leadership changed before commitment became unambiguous. If leaders were allowed to infer commitment of old term entries too aggressively, they could conclude safety from incomplete evidence.

The safe rule is:

  • once the leader commits an entry from its own current term using a majority
  • all earlier entries in the log become committed implicitly because of log ordering

This sounds conservative because it is conservative. Consensus prefers a small amount of delayed certainty over a large amount of guessed certainty.

leaderCommit Tells Followers How Far They May Apply

When the leader advances commitIndex, it includes that value in AppendEntries.

Followers then set:

commitIndex = min(leaderCommit, index of last new entry)

That prevents a follower from applying beyond what it actually has locally, while still letting it learn the safe boundary from the leader.

Client Acknowledgement Belongs After Commitment, Not After Local Append

If a leader told the client "success" immediately after appending locally, a crash could lose the command. The client would observe a write that the cluster later forgets. That is exactly what consensus is meant to prevent.

So the normal write path is:

client -> leader: write command
leader: append locally
leader -> followers: AppendEntries
followers: persist and ack
leader: observes quorum for current-term entry
leader: marks committed, applies entry
leader -> client: success

Consensus latency is therefore at least one round trip to a majority plus local and remote storage latency.

Followers Apply Committed Entries Later, And Reads Need Extra Care

A log entry being present is one thing. A log entry being committed is another. A log entry being applied to the state machine is a third.

commitIndex And lastApplied Are Not Synonyms

Suppose Frankfurt has commitIndex = 417 but lastApplied = 416. That means the cluster already decided entry 417 is safe, but the local state machine thread has not yet executed it.

This gap exists in real systems because:

  • the apply loop may batch work
  • snapshots or disk I/O may delay apply
  • the storage engine above Raft may need its own serialisation

The node must apply entries in order, never skipping ahead.

A common internal loop looks like this:

while lastApplied < commitIndex:
    lastApplied += 1
    stateMachine.apply(log[lastApplied])

That loop is where a replicated log turns into visible state.

Reads Have A Safety Problem Too

It is tempting to think reads are free because they do not change the log. They are not free if you want linearizable reads, meaning a read must reflect all writes that completed before the read began.

A former leader that has been partitioned away might still believe it is leader for a short time. If it serves reads from local state without checking whether it still holds authority, clients can observe stale data.

Real Raft systems therefore use extra machinery for safe reads, such as:

  • appending a no-op entry after election so the leader establishes commitment in its own term
  • using a ReadIndex protocol to confirm leadership with a quorum before serving a read
  • using lease-based reads only when timing assumptions are tight and well understood

The point is simple: write safety is not enough by itself. Leadership proof matters for reads as well.

Followers Serving Reads Need An Explicit Staleness Contract

A follower may be useful for stale-tolerant reads, but the application must treat them as potentially behind unless it has a stronger mechanism on top. A Raft follower that is one or two committed entries late is still healthy. It is just not safe for read-after-write guarantees.

This shows up in control planes all the time. A scheduler writes a lock or placement decision through the leader, then another component reads from a follower and still sees the old state. That is not Raft misbehaving. That is the system asking a stale replica for a fresh answer.

Snapshots Truncate History Without Losing Safety

A healthy Raft cluster keeps appending. If it never discarded old log entries, the log would grow forever, recovery would get slower, and new nodes would need to replay ancient history one record at a time.

Snapshots solve that.

The Snapshot Replaces A Committed Prefix

Once entries up to some index are committed and applied, the state machine can emit a compact snapshot representing the resulting state.

Example:

snapshot:
  lastIncludedIndex: 400
  lastIncludedTerm: 10
  state: key-value image, lock table, membership config, metadata

After persisting that snapshot safely, the node may discard log entries 1 through 400 because their effect is now represented inside the snapshot.

The pair (lastIncludedIndex, lastIncludedTerm) is essential. Without it, a follower receiving future AppendEntries would have no way to prove continuity across the truncated prefix.

InstallSnapshot Is For Followers Too Far Behind To Repair Via The Log

Suppose Athens was offline for hours. The leader compacted away everything before index 400, but Athens still needs entries starting around 280. The leader cannot send those old log entries because they no longer exist locally.

Instead it sends an InstallSnapshot RPC:

InstallSnapshot {
  term: 14
  leaderId: frankfurt
  lastIncludedIndex: 400
  lastIncludedTerm: 10
  offset: ...
  data: ...
  done: true
}

Athens installs the snapshot, sets its state machine to that image, records the included index and term, and then resumes normal log replication from entries after 400.

Without this mechanism, very stale followers would have to be rebuilt out of band.

Snapshots Change Recovery Semantics

After compaction, the local log no longer begins at index 1. It begins at some offset after the snapshot boundary. Every implementation therefore needs careful handling for questions like:

  • does prevLogIndex refer to an in-memory log entry or the snapshot marker?
  • what happens if a follower asks for an index older than the truncated prefix?
  • how is lastApplied restored after restart?
  • when is a snapshot durable enough that matching log entries may be deleted?

This is why snapshots are not just a storage optimisation. They are part of the consensus protocol state.

Membership Changes Require Overlapping Majorities

Changing the cluster membership is one of the easiest ways to break a consensus system if you treat it like ordinary configuration.

Suppose you want to move from a three-node cluster {A, B, C} to {D, E, F} by replacing the member list in one step. You now have a dangerous question: which majority is authoritative during the transition?

If the old nodes and new nodes each form their own idea of quorum, you can create disjoint majorities and elect incompatible leaders.

Joint Consensus Forces The Two Configurations To Overlap

Raft handles reconfiguration with a joint consensus phase.

  1. First commit a configuration containing both old and new sets.
  2. During that phase, decisions require a majority of the old config and a majority of the new config.
  3. After that entry is committed and stable, commit the final configuration containing only the new set.

Example transition:

old config:   {Amsterdam, Frankfurt, Milan}
new config:   {Frankfurt, Milan, Brussels, Athens, Warsaw}
joint config: {Amsterdam, Frankfurt, Milan} + {Frankfurt, Milan, Brussels, Athens, Warsaw}

The overlap through Frankfurt and Milan prevents the cluster from splitting into two unrelated authorities.

Membership Is Log State

The active configuration is not a side table. It is part of the replicated log and therefore part of the consensus state machine.

That design choice matters because it means:

  • leaders replicate configuration changes like any other command
  • followers learn membership in the same ordered history
  • crashes during reconfiguration still recover from the same log

If you manage membership outside the log, you are quietly creating a second consensus problem.

Operators Still Need Discipline

Joint consensus keeps the protocol safe, but it does not make careless operations free. Replacing multiple nodes at once, adding a slow WAN node as a voting member, or shrinking the cluster while one node is already unhealthy can still create self-inflicted unavailability.

Consensus gives you a safe machine. It does not excuse unsafe procedures.

Real Raft Clusters Fail In Boring, Operational Ways

The textbook algorithm assumes clean message delay and crash events. Production incidents are uglier.

Slow Storage Looks Like Slow Leadership

Leaders and followers both need durable writes. If the leader's WAL or journal device stalls, heartbeats and appends stall with it. Followers may time out and start elections even though the old leader process never crashed.

If follower disks are slow, write latency rises because quorum acknowledgements arrive later. A node that is technically alive but fsyncing at 80 ms instead of 2 ms can drag the whole cluster.

This is why Raft health dashboards that only show CPU and packet loss miss the plot. Storage latency is a leadership input.

Long Stop The World Pauses Can Trigger Elections

Runtime pauses, overloaded event loops, scheduler starvation, or virtual machine stalls can delay heartbeats long enough that healthy followers declare the leader dead.

The result is a pattern operators recognise quickly:

term 41 leader Amsterdam
term 42 leader Frankfurt
term 43 leader Amsterdam
term 44 leader Milan

That is not resilience. That is leadership flapping. Throughput drops, tail latency climbs, and clients start seeing retries or timeouts.

Many mature implementations add hardening features such as:

  • pre-vote, which asks whether an election would likely succeed before incrementing the term
  • check quorum, where a leader steps down if it can no longer contact a majority
  • leadership transfer, which moves leadership deliberately before maintenance

These are operational refinements around the same core safety rules.

A Recovered Old Leader Returns As A Follower

One recovery path is easy to miss when reading the paper: the old leader may come back. Suppose Amsterdam reboots after Frankfurt already became leader in term 13. Amsterdam still has durable data through index 417 and may still remember that it used to lead term 12, but that memory grants it no authority.

The first higher-term AppendEntries or RequestVote forces Amsterdam to update its term and step down. After that, it behaves like any other follower. If it missed index 418, Frankfurt sends the missing entries. If Frankfurt compacted that history away already, Amsterdam may need a snapshot. If Amsterdam had any local, uncommitted tail that the new leader does not recognise, that tail is overwritten during log repair.

This is a practical reason clients should not pin trust to a node identity such as "the Amsterdam server is the writer". The writer role is ephemeral. Safety comes from the current term plus quorum-backed log state, not from a machine's previous status.

WAN Placement Changes The Cost Model

Raft works across regions, but physics still bills you.

If your five voting members are spread across Amsterdam, Frankfurt, Milan, Brussels, and Athens, the leader only needs acknowledgements from any two peers beyond itself to commit in a five-node cluster. That means the leader placement influences the median and tail write latency. A leader in Frankfurt might commit quickly if it usually wins acks from Amsterdam and Brussels. A leader in Athens may see a different latency profile.

This is why serious deployments think about voter placement, learner nodes, and whether every region really needs to vote. A node that improves disaster recovery but worsens every commit path may be better as a non-voting replica.

Timeouts Need Margin Above Normal Jitter

Election timeouts that are too short cause false elections. Timeouts that are too long slow genuine failover.

There is no universal number. The right value depends on:

  • normal network round-trip time between voters
  • storage latency under load
  • scheduler and GC pause behaviour
  • batching and heartbeat interval
  • how much failover delay the application can tolerate

A cluster that is solid inside one datacentre can become unstable if copied unchanged across several European cities. Consensus tuning is about measured timing, not cargo-cult defaults.

A Majority Available Is Necessary, Not Sufficient, For Healthy Service

A cluster can still have quorum and behave badly.

Examples:

  • one lagging follower causes large snapshot traffic after every restart
  • the leader is alive but overloaded, so writes technically succeed yet exceed SLOs
  • followers keep restarting and forcing catch-up work
  • membership changed recently and the remaining quorum is geographically awkward

Consensus does not replace capacity planning, observability, or good failure drills.

Why Raft Feels Simple Only After You Respect The Edge Cases

Raft earned its reputation because its major pieces line up with an operator's intuition.

  • one leader accepts writes
  • followers replicate the leader's log
  • elections happen when the leader disappears
  • majority decides what survives

That story is true. It is also incomplete.

The actual reason Raft works is that every seemingly small rule closes a specific safety hole.

  • Randomised timeouts stop constant election collisions.
  • One vote per term stops obvious double leaders.
  • Log freshness in RequestVote stops stale leaders from reviving old history.
  • prevLogIndex and prevLogTerm stop leaders from appending onto divergent suffixes.
  • Conflict deletion repairs uncommitted branches.
  • Current-term commit rules stop unsafe commitment inference.
  • leaderCommit separates replicated presence from state-machine application.
  • Snapshots preserve continuity while truncating history.
  • Joint consensus prevents membership changes from creating split authority.

If you remember only one thing, remember this: Raft is not a voting algorithm attached to a log. It is a log safety algorithm that uses elections to decide who may extend the log next.

That is why Raft-backed systems can be so useful in the control plane. Kubernetes needs one truth for lease state and object metadata. Service registries need one truth for health and membership co-ordination. Metadata services need one truth for namespace and placement decisions. All of them are really asking for the same thing: one ordered, durable history that stays coherent when machines fail.

When that machinery is healthy, Raft feels boring. A leader appends, followers ack, commit advances, clients move on.

When that machinery is unhealthy, the symptoms are also boring in a different way. Elections fire too often. Commits get slower. Lagging followers need snapshots. Reconfiguration becomes scary. The cluster stops feeling like one brain and starts feeling like five tired machines arguing over the last valid copy of the truth.

Consensus is the work of making sure that argument always ends the same way.