Skip to content

Latest commit

 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Raft, twice — a dual-language teaching implementation

The complete Raft consensus algorithm — leader election, log replication, safety, persistence, snapshots, and cluster membership changes — implemented twice, in Go and in Rust, as mirror images of each other, plus a visual debugger that shows you which source line each node is executing while a real cluster runs.

This repository is built for reading. Roughly 40% of the source is explanation: every file opens with an essay on why it exists, and the tricky lines cite the section of the Raft paper they implement.

Start here → GUIDE.md — the concepts, then a guided tour of the code in reading order, then Go-vs-Rust notes.

Quick start

Requirements: Go ≥ 1.22, Rust ≥ 1.75 (Linux/macOS).

$ scripts/build.sh            # builds Go, Rust, and the visualizer
$ scripts/test-all.sh         # unit tests + all 12 end-to-end scenarios

Drive a cluster by hand

$ scripts/run-go.sh           # or scripts/run-rust.sh
raft> status
id   role      term  commit  applied log     snapshot  leader
n1   follower  1     2       2       [1,2]   @0        n3
n2   follower  1     2       2       [1,2]   @0        n3
n3   LEADER    1     2       2       [1,2]   @0        n3
raft> submit x=5
committed x=5 in 18ms
raft> kill n3                 # SIGKILL the leader...
raft> status                  # ...and watch the re-election
raft> partition n1 | n2,n3    # simulate a network partition
raft> heal
raft> add-server n4           # grow the cluster live
raft> help                    # everything else

Each node is a real OS process speaking newline-delimited JSON over TCP (docs/protocol.md). You can talk to one directly:

$ echo '{"type":"GetStatus","from":"me","body":{}}' | nc 127.0.0.1 21001
{"ok":true,"body":{"id":"n1","term":3,"role":"leader",...}}

The visual debugger

$ scripts/run-visual.sh       # go cluster + visualizer; add `rust` for Rust
# open http://127.0.0.1:8080

Every node streams trace events — each carrying the source file and line that emitted it plus a full state snapshot. The browser UI gives you:

  • the cluster diagram (roles, terms, partitions, RPC arrows) reconstructed as of any event you select — step backward and forward like a debugger;
  • each node's replicated log, entry by entry, with commit/snapshot markers;
  • a code panel showing the real Go/Rust source with the executing line highlighted;
  • buttons that drive the live cluster: put/get, partition/heal, crash a node, force a snapshot.

Scripted failure stories

$ go/bin/raftctl scenario stale-leader     # THE safety demo
$ go/bin/raftctl scenario all              # the whole tour (6 scenarios)
$ rust/target/release/ctl scenario all     # same six, Rust cluster

See docs/scenarios.md for what each one proves.

Repository map

GUIDE.md            ← the book: concepts + code walkthrough (start here)
docs/protocol.md    the wire protocol both implementations speak
docs/scenarios.md   the six failure stories, explained
go/                 Go implementation (stdlib only)
  raft/             the algorithm, one concern per file
  cmd/raft-node     one Raft server = one process
  cmd/raftctl       orchestrator: REPL + scenarios
  orchestrator/     process management, REPL, scenario scripts
rust/               Rust implementation (serde + rand only, no async)
  src/              mirrors go/raft file-for-file
  src/bin/          node + ctl binaries
visualise/          the visual debugger (server + web UI)
scripts/            build / run / test / clean

Scope and honest limitations

Implemented: the full paper — §5 elections & replication & safety, §7 snapshots (single-message InstallSnapshot), and single-server membership changes from the dissertation (chapter 4) with both safety guards. Exactly-once client semantics and linearizable reads (through the log).

Deliberately simplified, each discussed in GUIDE.md where it matters: connection-per-RPC instead of multiplexing; whole-file persistence instead of a WAL; reads through the log instead of ReadIndex/leases; no PreVote; no joint consensus; no snapshot chunking. None of these change the algorithm — they are the production-engineering layer above it.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages