<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Replication on Krishnatejaswi S</title>
    <link>https://KTS-o7.github.io/bear/tags/replication/</link>
    <description>Recent content in Replication on Krishnatejaswi S</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <managingEditor>shentharkrishnatejaswi@gmail.com (Krishnatejaswi S)</managingEditor>
    <webMaster>shentharkrishnatejaswi@gmail.com (Krishnatejaswi S)</webMaster>
    <copyright>Krishnatejaswi S</copyright>
    <lastBuildDate>Sun, 03 May 2026 00:00:00 +0530</lastBuildDate>
    <atom:link href="https://KTS-o7.github.io/bear/tags/replication/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Multi-Paxos: From Single Decree to a Replicated Log</title>
      <link>https://KTS-o7.github.io/bear/systems/multi_paxos/</link>
      <pubDate>Sun, 03 May 2026 00:00:00 +0530</pubDate><author>shentharkrishnatejaswi@gmail.com (Krishnatejaswi S)</author>
      <guid>https://KTS-o7.github.io/bear/systems/multi_paxos/</guid>
      <description>&lt;p&gt;Basic Paxos agrees on a single value. That&amp;rsquo;s useful for electing a leader or picking a configuration, but a database needs to agree on a sequence of values &amp;ndash; every write in order, forever. Running one full round of Paxos per log slot would work but it&amp;rsquo;s expensive: two network round-trips per slot, and Phase 1 has to complete before Phase 2 can start.&lt;/p&gt;&#xA;&lt;p&gt;Multi-Paxos is the optimization that makes Paxos practical as a replicated log. The insight is that Phase 1 can be amortized across many slots once you have a stable leader.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Basic Paxos agrees on a single value. That&rsquo;s useful for electing a leader or picking a configuration, but a database needs to agree on a sequence of values &ndash; every write in order, forever. Running one full round of Paxos per log slot would work but it&rsquo;s expensive: two network round-trips per slot, and Phase 1 has to complete before Phase 2 can start.</p>
<p>Multi-Paxos is the optimization that makes Paxos practical as a replicated log. The insight is that Phase 1 can be amortized across many slots once you have a stable leader.</p>
<h2 id="what-phase-1-actually-does">What Phase 1 Actually Does</h2>
<p>Recall basic Paxos. Phase 1 (Prepare/Promise) establishes that a proposer has the highest ballot number any acceptor will respond to. The acceptors promise to ignore any lower-numbered proposer. This is the &ldquo;take control&rdquo; phase &ndash; after it completes, the proposer has permission to drive proposals through Phase 2.</p>
<p>Phase 1 doesn&rsquo;t say anything about which value gets proposed. It just establishes leadership over the acceptors for a given ballot number.</p>
<h2 id="the-amortization">The Amortization</h2>
<p>If the same leader runs Phase 1 once with a high ballot number, it doesn&rsquo;t need to run Phase 1 again for subsequent log slots &ndash; as long as no other proposer challenges it with a higher ballot.</p>
<p>The leader runs Phase 1 once, gets promises from a majority, and then drives Phase 2 directly for slot 1, slot 2, slot 3, and so on. Each slot is just one round-trip (Accept/Accepted) instead of two. Throughput roughly doubles for steady-state operation under a stable leader.</p>





<pre tabindex="0"><code>Phase 1 (once):   Leader → Prepare(ballot=5) → Majority
                  Majority → Promise(ballot=5, ...) → Leader

Phase 2 (per slot):
  Slot 1:  Leader → Accept(ballot=5, slot=1, value=A) → Majority
           Majority → Accepted → Leader → Committed
  Slot 2:  Leader → Accept(ballot=5, slot=2, value=B) → Majority
           Majority → Accepted → Leader → Committed
  ...</code></pre><p>This is Multi-Paxos. The Phase 1 cost is paid once per leader term, not once per log entry.</p>
<h2 id="leader-election">Leader Election</h2>
<p>Basic Paxos has no notion of a leader &ndash; any node can propose at any time, which is why it&rsquo;s correct but chaotic in practice. Multi-Paxos adds an informal leader election layer: one node is designated the distinguished proposer and the others voluntarily defer to it.</p>
<p>&ldquo;Voluntarily&rdquo; is the key word. If followers suspect the leader is dead (no heartbeats for a timeout period), any of them can run Phase 1 with a higher ballot to take over. The old leader doesn&rsquo;t get a veto &ndash; it just gets its Accept messages rejected because the acceptors have now promised a higher ballot.</p>
<p>This is where Multi-Paxos implementations diverge significantly. The Paxos paper doesn&rsquo;t specify how leader election works, what timeouts to use, or how to detect a live leader that&rsquo;s just partitioned. Every real implementation makes different choices here, which is part of why Multi-Paxos implementations are hard to compare.</p>
<h2 id="log-holes">Log Holes</h2>
<p>One complication basic Paxos avoids: with multiple slots running in parallel, you can get holes. The leader accepts slot 1 and slot 3 but slot 2 hasn&rsquo;t been filled yet because a client request was lost. Followers can&rsquo;t apply slot 3 to the state machine without knowing slot 2.</p>
<p>Multi-Paxos implementations handle this with a no-op: when a new leader wins an election, it runs Phase 1 for all uncommitted slots and fills any gaps with a no-op entry. This is what &ldquo;leader reconciliation&rdquo; looks like in practice &ndash; the new leader has to figure out what was committed before it took over and resolve any ambiguity.</p>
<p>Raft avoids holes entirely by requiring that the leader always send entries in order, with no gaps. This simplifies the implementation at the cost of some throughput (you can&rsquo;t pipeline out-of-order).</p>
<h2 id="zab-vs-multi-paxos">Zab vs. Multi-Paxos</h2>
<p>ZooKeeper uses Zab (ZooKeeper Atomic Broadcast), which is often described as &ldquo;Paxos-like&rdquo; but is actually closer to Multi-Paxos with some explicit differences.</p>
<p>The main one: Zab is designed around a primary-backup model where the primary sends updates in a strict FIFO order. The recovery protocol (Phase 1 equivalent in Zab) is designed to ensure the new primary has a superset of all committed entries before it starts serving. Zab also has an explicit synchronization phase where followers sync their logs to the new primary before it starts accepting writes.</p>
<p>Both tolerate the same number of failures and provide the same safety guarantees. The practical difference is that Zab is tuned for ZooKeeper&rsquo;s specific write pattern (broadcast to all followers, wait for majority ack, apply in order) while Multi-Paxos is a more general framework.</p>
<h2 id="multi-paxos-vs-raft">Multi-Paxos vs. Raft</h2>
<table>
  <thead>
      <tr>
          <th></th>
          <th>Multi-Paxos</th>
          <th>Raft</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Leader election</td>
          <td>Ad hoc, not specified in paper</td>
          <td>Built into protocol with explicit terms</td>
      </tr>
      <tr>
          <td>Log holes</td>
          <td>Possible, requires no-op fill on leader change</td>
          <td>Not possible, entries sent in order</td>
      </tr>
      <tr>
          <td>Pipelining</td>
          <td>Supported natively</td>
          <td>Requires extensions</td>
      </tr>
      <tr>
          <td>Understandability</td>
          <td>Requires significant paper-reading and inference</td>
          <td>Designed to be implementable from the paper alone</td>
      </tr>
      <tr>
          <td>Real implementations</td>
          <td>Chubby (Google), custom variants</td>
          <td>etcd, CockroachDB, TiKV, Consul</td>
      </tr>
  </tbody>
</table>
<p>Multi-Paxos and Raft have the same fault tolerance and safety properties. The difference is that Raft specifies the things Multi-Paxos leaves up to the implementer &ndash; which is why Raft implementations tend to be more consistent across codebases.</p>
<p>Google&rsquo;s Chubby uses a Paxos variant internally. Google Spanner uses a Paxos variant per shard. In both cases Google built their own leader election and recovery logic on top of the basic protocol &ndash; which is exactly the work Raft was designed to eliminate.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Raft Log Compaction: Keeping the Log from Growing Forever</title>
      <link>https://KTS-o7.github.io/bear/systems/raft_log_compaction/</link>
      <pubDate>Sun, 03 May 2026 00:00:00 +0530</pubDate><author>shentharkrishnatejaswi@gmail.com (Krishnatejaswi S)</author>
      <guid>https://KTS-o7.github.io/bear/systems/raft_log_compaction/</guid>
      <description>&lt;p&gt;Raft&amp;rsquo;s correctness relies on the log. Every state change is appended to it, replicated to a majority, and then applied to the state machine. This works perfectly until you&amp;rsquo;ve been running for a few months and the log has millions of entries. Replaying the full log on every restart is slow. A new node joining the cluster would have to receive and apply every entry since the beginning of time.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Raft&rsquo;s correctness relies on the log. Every state change is appended to it, replicated to a majority, and then applied to the state machine. This works perfectly until you&rsquo;ve been running for a few months and the log has millions of entries. Replaying the full log on every restart is slow. A new node joining the cluster would have to receive and apply every entry since the beginning of time.</p>
<p>Log compaction is how you fix this. The idea is simple: once a prefix of the log has been applied to the state machine, you don&rsquo;t need the individual entries anymore &ndash; just a snapshot of the state at that point.</p>
<h2 id="snapshots">Snapshots</h2>
<p>A snapshot captures the complete state machine state at a given log index. Once the snapshot is written, all log entries up to and including that index can be discarded.</p>





<pre tabindex="0"><code>Before compaction:
  Log: [1: set x=1] [2: set y=2] [3: set x=3] [4: del y] [5: set z=1]
  Applied through index 4
  State machine: {x: 3, z: 1}

After compaction:
  Snapshot at index 4: {x: 3}  (z not in snapshot -- set z=1 not yet applied)
  Remaining log: [5: set z=1]</code></pre><p>Wait &ndash; index 5 is retained because it hasn&rsquo;t been applied yet when the snapshot is taken. The snapshot covers only committed, applied entries.</p>
<p>The snapshot metadata includes the last included index and last included term. These replace the log prefix. When AppendEntries includes a consistency check against the entry before the new one, the leader uses the snapshot&rsquo;s last index and term as the baseline when the follower&rsquo;s log has been compacted past that point.</p>
<h2 id="when-to-snapshot">When to Snapshot</h2>
<p>Most implementations trigger a snapshot when the log grows past a size threshold &ndash; say 64MB or 256MB. The Raft paper leaves this as an implementation detail. etcd uses 100MB by default. Smaller thresholds mean more frequent snapshots and less log replay on restart, but snapshot creation has a cost.</p>
<p>Taking a snapshot of a large state machine can be expensive. If you&rsquo;re snapshotting a database with gigabytes of data, the snapshot itself might take seconds. During that time the state machine is typically paused or copy-on-write semantics are used to take a consistent point-in-time snapshot without stopping serving. Most production implementations use copy-on-write (fork on Linux makes this cheap for process-based state machines).</p>
<h2 id="installsnapshot-rpc">InstallSnapshot RPC</h2>
<p>Snapshots matter most for a new node joining the cluster or a node that has been down for a long time and fallen significantly behind.</p>
<p>If a follower is so far behind that the leader has already compacted the log entries it needs, AppendEntries won&rsquo;t work &ndash; those entries are gone. Instead the leader sends the snapshot directly with InstallSnapshot RPC.</p>
<p>The follower receives the snapshot, writes it to stable storage, discards its entire existing log, and resets its state machine to the snapshot state. After that it can receive normal AppendEntries for the remaining log entries.</p>
<p>InstallSnapshot is also used when a brand new node joins the cluster. Rather than replaying potentially years of log history, the leader sends the current snapshot and the follower catches up from there.</p>
<h2 id="etcd-in-practice">etcd in Practice</h2>
<p>etcd runs a snapshot at 100MB by default (configurable with <code>--snapshot-count</code>, which actually counts committed entries, not bytes &ndash; the default is 10,000 entries). After snapshotting, etcd retains the last 5 snapshots and the WAL (write-ahead log) segments needed to replay from the oldest retained snapshot. This gives you a window of history for debugging without storing the full log.</p>
<p>etcd also exposes the snapshot mechanism for operator use. <code>etcdctl snapshot save</code> takes a snapshot of the current state to a file. This is the recommended backup mechanism for etcd clusters &ndash; you back up the snapshot, not the raw data directory.</p>
<h2 id="leader-leases-and-linearizable-reads">Leader Leases and Linearizable Reads</h2>
<p>One related problem: reads in a basic Raft cluster go through the leader, which needs to confirm it&rsquo;s still the leader before responding. The way to confirm is to send a heartbeat round to a majority before responding to a read &ndash; which is an extra round-trip per read, expensive under load.</p>
<p>Leader leases are the optimization. When a leader wins an election and sends its first heartbeats, it records the time and grants itself a lease for a fixed duration (typically the election timeout). During that window, it&rsquo;s guaranteed to still be the leader &ndash; any new leader would need a full election timeout to emerge. So it can serve reads locally without a heartbeat round.</p>
<p>The caveat: lease-based reads depend on the leader&rsquo;s clock being accurate relative to other nodes. If a leader&rsquo;s clock runs fast and its lease hasn&rsquo;t actually expired on other nodes&rsquo; clocks while it thinks it has, you can serve stale reads. etcd uses clock bounds and makes the lease duration conservative to avoid this. In practice, lease reads are the default in most etcd deployments because the latency benefit outweighs the theoretical risk on well-synchronized hardware clocks.</p>
<p>Raft&rsquo;s log compaction is not exciting to implement but it&rsquo;s essential for production deployments. A cluster without snapshot support will eventually fall over under its own log weight &ndash; or force every new node to replay history from the beginning, which is equally untenable.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Paxos: How Distributed Systems Agree on Anything</title>
      <link>https://KTS-o7.github.io/bear/systems/paxos_consensus/</link>
      <pubDate>Sat, 02 May 2026 00:00:00 +0530</pubDate><author>shentharkrishnatejaswi@gmail.com (Krishnatejaswi S)</author>
      <guid>https://KTS-o7.github.io/bear/systems/paxos_consensus/</guid>
      <description>&lt;p&gt;Every replicated database, every distributed lock, every leader election comes down to the same underlying problem: how do multiple nodes in an unreliable network agree on a single value, even when some of them crash or messages get delayed?&lt;/p&gt;&#xA;&lt;p&gt;This is the consensus problem. Paxos is the foundational answer. It&amp;rsquo;s also notoriously difficult to implement correctly &amp;ndash; which is exactly why Raft exists. But you can&amp;rsquo;t really understand Raft without understanding what Paxos is doing and why.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Every replicated database, every distributed lock, every leader election comes down to the same underlying problem: how do multiple nodes in an unreliable network agree on a single value, even when some of them crash or messages get delayed?</p>
<p>This is the consensus problem. Paxos is the foundational answer. It&rsquo;s also notoriously difficult to implement correctly &ndash; which is exactly why Raft exists. But you can&rsquo;t really understand Raft without understanding what Paxos is doing and why.</p>
<h2 id="the-constraint">The Constraint</h2>
<p>Two-phase commit solves distributed atomicity but requires the coordinator to stay up. If the coordinator crashes after phase 1, participants are stuck holding locks, unable to proceed. That&rsquo;s not consensus &ndash; that&rsquo;s a single point of failure with extra steps.</p>
<p>Paxos removes that constraint. It guarantees agreement as long as a majority of nodes are up, regardless of which specific nodes fail. Any node can propose a value. No permanent coordinator required.</p>
<h2 id="roles">Roles</h2>
<p>In Paxos, nodes play three roles &ndash; and in practice, any node can play any of them:</p>
<ul>
<li><strong>Proposer</strong> &ndash; initiates a round, tries to get a value accepted</li>
<li><strong>Acceptor</strong> &ndash; votes on proposals, must follow the protocol strictly</li>
<li><strong>Learner</strong> &ndash; learns the final chosen value once consensus is reached</li>
</ul>
<h2 id="the-protocol">The Protocol</h2>
<p>Paxos runs in two phases.</p>
<h3 id="phase-1--prepare--promise">Phase 1 &ndash; Prepare / Promise</h3>
<p>The proposer picks a proposal number <code>n</code> &ndash; unique, higher than any it has seen before &ndash; and sends <code>PREPARE(n)</code> to a quorum of acceptors (any majority).</p>
<p>Each acceptor that receives this:</p>
<ul>
<li>Promises to ignore any future <code>PREPARE</code> with a lower number</li>
<li>If it has already accepted a value in a prior round, includes that <code>(old_n, old_value)</code> in its reply</li>
</ul>
<h3 id="phase-2--accept--accepted">Phase 2 &ndash; Accept / Accepted</h3>
<p>If the proposer receives promises from a quorum:</p>
<ul>
<li>If any promise included a prior accepted value, the proposer <strong>must use the highest one</strong> &ndash; it cannot choose freely</li>
<li>Otherwise it can propose any value it wants</li>
</ul>
<p>It sends <code>ACCEPT(n, value)</code> to the quorum. Acceptors that haven&rsquo;t made a conflicting promise write the value and reply <code>ACCEPTED</code>. Once a quorum accepts, the value is chosen.</p>





<pre tabindex="0"><code>Proposer       Acceptor A    Acceptor B    Acceptor C
   |-- PREPARE(5) --&gt;|             |             |
   |-- PREPARE(5) ---|------------&gt;|             |
   |&lt;-- PROMISE(5) --|             |             |
   |&lt;-- PROMISE(5) --|-------------|             |
   |-- ACCEPT(5,v) -&gt;|             |             |
   |-- ACCEPT(5,v) --|------------&gt;|             |
   |&lt;-- ACCEPTED ----|             |             |
   |&lt;-- ACCEPTED ----|-------------|             |
      [value v is now chosen]</code></pre><h2 id="why-its-correct">Why It&rsquo;s Correct</h2>
<p>The safety guarantee &ndash; that no two values are ever chosen &ndash; comes from the quorum overlap. Any two majorities in an N-node cluster share at least one node. That shared node is the bridge: if a value was accepted in round <code>n</code>, a new proposer in round <code>n+1</code> will hear about it from the shared node and be forced to continue it rather than propose something different.</p>
<p>The constraint that proposers must adopt the highest prior accepted value is what makes this work. A new round can never silently override an old one.</p>
<h2 id="the-gotchas">The Gotchas</h2>
<p><strong>Livelock.</strong> Two competing proposers can keep preempting each other with higher proposal numbers indefinitely &ndash; neither ever reaching phase 2. The fix is to elect a single distinguished proposer (a leader) and have everyone else defer to it. This is what Multi-Paxos does.</p>
<p><strong>Single-value vs. Multi-Paxos.</strong> Basic Paxos agrees on one value. Real systems need a log of values &ndash; a sequence of commands. Multi-Paxos runs Paxos repeatedly for each log slot with a stable leader, amortizing the phase 1 cost across many entries. Once a leader is established, phase 1 only needs to run once per leader lifetime.</p>
<p><strong>Implementation gap.</strong> The original paper was intentionally abstract. &ldquo;Paxos Made Simple&rdquo; is cleaner but still leaves enormous implementation latitude &ndash; enough that teams have shipped subtly broken versions. The gap between the protocol description and a correct, production-safe implementation is one of the main reasons Raft was designed as an explicit replacement.</p>
<h2 id="where-it-runs">Where It Runs</h2>
<ul>
<li><strong>Google Chubby</strong> &ndash; distributed lock service, underpins Bigtable and GFS coordination</li>
<li><strong>Apache ZooKeeper</strong> &ndash; uses Zab (ZooKeeper Atomic Broadcast), a Paxos variant</li>
<li><strong>Google Spanner</strong> &ndash; Paxos per shard for replication across datacenters</li>
</ul>
<p>Paxos is the theory. If you&rsquo;re building something new, you&rsquo;ll probably implement Raft instead &ndash; same guarantees, actually debuggable. But the mental model of quorum-based two-phase consensus is worth having regardless of which one you reach for.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Raft: Consensus for the Rest of Us</title>
      <link>https://KTS-o7.github.io/bear/systems/raft_consensus/</link>
      <pubDate>Sat, 02 May 2026 00:00:00 +0530</pubDate><author>shentharkrishnatejaswi@gmail.com (Krishnatejaswi S)</author>
      <guid>https://KTS-o7.github.io/bear/systems/raft_consensus/</guid>
      <description>&lt;p&gt;Paxos is the algorithm everyone cites and almost nobody implements correctly. The gap between the paper and a working, production-safe implementation is wide enough that teams have shipped subtly broken versions without knowing it for months.&lt;/p&gt;&#xA;&lt;p&gt;Raft was built as a direct response to that. Same safety guarantees, designed from scratch for understandability &amp;ndash; the explicit goal was that a student should be able to implement it correctly from the paper alone.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Paxos is the algorithm everyone cites and almost nobody implements correctly. The gap between the paper and a working, production-safe implementation is wide enough that teams have shipped subtly broken versions without knowing it for months.</p>
<p>Raft was built as a direct response to that. Same safety guarantees, designed from scratch for understandability &ndash; the explicit goal was that a student should be able to implement it correctly from the paper alone.</p>
<p>It works. etcd runs on it. Kubernetes&rsquo; entire cluster state lives in etcd. CockroachDB uses a Raft group per range. TiKV, Consul &ndash; Raft is everywhere Paxos was supposed to be.</p>
<h2 id="the-decomposition">The Decomposition</h2>
<p>Raft&rsquo;s core move is breaking consensus into three subproblems that can be understood and implemented independently:</p>
<ol>
<li>Leader election &ndash; pick one node as leader at any time</li>
<li>Log replication &ndash; leader accepts entries, replicates to followers</li>
<li>Safety &ndash; no two nodes ever commit conflicting entries</li>
</ol>
<p>Everything flows through a single leader. There&rsquo;s no &ldquo;any node can propose&rdquo; ambiguity like in basic Paxos. The leader is the sole source of truth for what enters the log. That constraint makes the rest of the protocol tractable.</p>
<h2 id="terms-and-roles">Terms and Roles</h2>
<p>Raft uses a logical clock called a <strong>term</strong> &ndash; a monotonically increasing integer. Each election starts a new term. If a node sees a message from a higher term than its own, it immediately updates and steps down if it was leader. Terms are how stale leaders get detected and evicted.</p>
<p>Every node is one of three things at any moment:</p>
<ul>
<li><strong>Leader</strong> &ndash; accepts client requests, replicates entries, sends heartbeats to prevent new elections</li>
<li><strong>Follower</strong> &ndash; passive, responds to RPCs from leaders and candidates</li>
<li><strong>Candidate</strong> &ndash; transitional state during an election</li>
</ul>
<p>Every node starts as a follower.</p>
<h2 id="leader-election">Leader Election</h2>
<p>Followers expect periodic heartbeats from the leader via AppendEntries RPCs (sent even when there are no entries to replicate). If an election timeout fires without a heartbeat, the follower converts to a candidate:</p>
<ol>
<li>Increment current term, vote for self</li>
<li>Send RequestVote to all peers</li>
<li>A peer grants its vote if it hasn&rsquo;t voted this term and the candidate&rsquo;s log is at least as up-to-date as its own</li>
<li>First candidate to collect a majority wins, becomes leader, starts sending heartbeats immediately</li>
</ol>
<p>Split votes happen when two candidates start elections simultaneously and each gets half the cluster. Neither reaches majority. Both time out and retry with a new term. Raft handles this with randomized election timeouts (typically 150&ndash;300ms) &ndash; making simultaneous timeouts unlikely without coordination overhead.</p>
<h2 id="log-replication">Log Replication</h2>
<p>Once a leader is elected:</p>
<ol>
<li>Client sends a command to the leader</li>
<li>Leader appends the entry to its local log (not yet committed)</li>
<li>Leader sends AppendEntries to all followers in parallel</li>
<li>Once a majority have written the entry, the leader marks it committed</li>
<li>Leader applies the entry to its state machine, replies to client</li>
<li>On the next heartbeat, followers learn the commit index and apply the entry too</li>
</ol>





<pre tabindex="0"><code>Client → [write x=5] → Leader
Leader  → AppendEntries(x=5) → Follower A  ✓
Leader  → AppendEntries(x=5) → Follower B  ✓
Leader  → AppendEntries(x=5) → Follower C  (unreachable)
[Majority = Leader + A + B → COMMIT] → apply x=5</code></pre><p>Follower C is behind but not a problem. When it reconnects, the leader sends it the missing entries.</p>
<h2 id="safety-log-matching">Safety: Log Matching</h2>
<p>Raft&rsquo;s key safety property: if two logs contain an entry with the same index and term, all preceding entries are identical.</p>
<p>This is enforced by the AppendEntries consistency check. When the leader sends an entry, it includes the index and term of the entry immediately before it. A follower rejects the append if that preceding entry doesn&rsquo;t match its own log. The leader then backs up and resends from an earlier point until it finds a common prefix, then overwrites the diverged entries.</p>
<p>The vote restriction reinforces this: a node won&rsquo;t vote for a candidate whose log is less up-to-date than its own. This guarantees the new leader always has all committed entries &ndash; it never needs to fetch missing entries from other nodes after winning an election.</p>
<h2 id="leader-failure">Leader Failure</h2>
<p>If the leader crashes, the election timeout fires on one of the followers and a new election starts. The vote restriction ensures the winner has the most complete log among the majority. No repair phase, no querying all nodes &ndash; safety comes from the constraint, not from post-election cleanup.</p>
<h2 id="raft-vs-paxos">Raft vs. Paxos</h2>
<table>
  <thead>
      <tr>
          <th></th>
          <th>Multi-Paxos</th>
          <th>Raft</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Design goal</td>
          <td>Correctness</td>
          <td>Correctness + understandability</td>
      </tr>
      <tr>
          <td>Leader</td>
          <td>Distinguished proposer (informal)</td>
          <td>Explicit, enforced by protocol</td>
      </tr>
      <tr>
          <td>Log holes</td>
          <td>Can have gaps, complex to fill</td>
          <td>No gaps, entries apply in order</td>
      </tr>
      <tr>
          <td>Config changes</td>
          <td>Ad hoc</td>
          <td>Joint consensus built in</td>
      </tr>
      <tr>
          <td>Implementations</td>
          <td>Chubby, Zab (variants)</td>
          <td>etcd, CockroachDB, TiKV, Consul</td>
      </tr>
  </tbody>
</table>
<p>Both tolerate up to (N-1)/2 failures in an N-node cluster. The fault tolerance is identical. The difference is that Raft implementations are actually correct in practice because the protocol is debuggable.</p>
<h2 id="where-it-runs">Where It Runs</h2>
<ul>
<li><strong>etcd</strong> &ndash; Kubernetes&rsquo; backing store; the entire cluster state (pods, services, configs) is a Raft log</li>
<li><strong>CockroachDB</strong> &ndash; Raft per range; each 512MB range is an independent 3&ndash;5 node Raft group</li>
<li><strong>TiKV</strong> &ndash; Raft groups per region, underpins TiDB</li>
<li><strong>Consul</strong> &ndash; service discovery and distributed KV</li>
</ul>
<p>If you&rsquo;re building anything that needs replicated state and strong consistency, Raft is the default answer. The paper is readable in an afternoon. The TLA+ spec exists if you want to verify your implementation. Start there.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
