Raft-Inspired KV Cluster
Build a small replicated key-value store in Go, based on the Raft consensus algorithm, the same idea that keeps etcd and Consul consistent. Three or five nodes elect a leader; clients write to the leader through an HTTP API; the leader copies each write to the other nodes and only confirms it once a majority has it, so data survives a node crashing. If the leader dies, the others elect a new one within a second or two. Nodes talk to each other over gRPC and save their state to disk so they can restart. This is a learning implementation, focused on understanding, not production use. You'll learn leader election, log replication, terms and majorities, persistence and crash recovery, and testing distributed systems by injecting failures.
- Estimate
- ~17.5h
- Steps
- 7
- Completed by
- 0
- Proposed by
- codeseed.app
net/http · gRPC · PostgreSQL
Project roadmap
- 01
Set up nodes and their RPCs
~2.5hRead the Raft paper (sections 5.1 to 5.4) first. Define a gRPC service in raft.proto with RequestVote and AppendEntries, using the message fields from the paper's Figure 2, and generate the Go code. Each node starts with an id, a list of peer addresses, a gRPC port and an HTTP port, from flags or a config file. Done when: three local nodes start and can call each other's RPCs.
- 02
Elect a leader
~3hImplement the three states (follower, candidate, leader) and terms. A follower that hears nothing from a leader within a random timeout (150 to 300 ms) becomes a candidate, increases its term, votes for itself and asks the others for votes. A node grants at most one vote per term. A candidate with a majority becomes leader and sends empty AppendEntries as heartbeats. Protect shared state with a mutex. Done when: three nodes elect exactly one leader, and killing it elects a new one.
- 03
Replicate the log
~3hEach node keeps a log of entries (term plus command). The leader appends client commands to its log and sends them with AppendEntries, including the previous entry's index and term. Followers reject entries that don't match and the leader steps back until the logs agree. When an entry is stored on a majority, the leader marks it committed and tells the followers. Done when: entries written to the leader appear, in order, in every node's log.
- 04
Apply commands to the key-value store
~2hApply committed entries, in order, to an in-memory map: set key value and delete key. Add an HTTP API on each node: PUT and DELETE /kv/{key} work only on the leader (followers answer 307 with the leader's address), and return only after the command is committed and applied. GET /kv/{key} reads from the leader. Done when: a value written through the leader can be read back, and followers redirect writes.
- 05
Persist state and recover
~2.5hSave currentTerm, votedFor and the log to disk, and sync the file (fsync) before answering an RPC, as the paper requires. On startup, load them and rebuild the key-value map by replaying committed entries. Use a simple append-only file format with a checksum per entry so a partly written entry at the end is detected and discarded. Done when: restarting all nodes keeps every committed value.
- 06
Add the election restriction and status
~1.5hImplement the rule that a node only votes for a candidate whose log is at least as up to date as its own (paper section 5.4.1), so a new leader always has every committed entry. Add GET /status on each node showing its state, term, leader, log length and commit index. Done when: the status endpoint shows a consistent view across the cluster.
- 07
Test with failures
~3hWrite Go tests that run a 3- or 5-node cluster in one process, with a network layer that can drop messages between chosen nodes, and check: a leader is elected, writes are replicated, a new leader is elected after the old one is isolated, a minority can't commit writes, and data survives restarts. Run them with -race. Done when: go test -race ./... passes reliably when run several times.
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack