Topic 15 notes — replication, consensus & distribution
Predictions (fill BEFORE implementing raft.rs)
repl_lag baseline (provided, measured 2026-07-10, macOS F_FULLFSYNC): 2000 × 128 B entries, WAIT-1-style ack per entry:
| follower fsync | entries/s | ack p50 µs | ack p99 µs |
|---|---|---|---|
| every 1 | 339 | 2972.7 | 3506.5 |
| every 8 | 2431 | 18.5 | 3706.3 |
| every 64 | 9665 | 13.6 | 2880.1 |
| never | 18568 | 6.2 | 32.5 |
Topic 5’s fsync ladder, now visible as replication lag: the p50 drops 160× from every-1 to every-8 (most acks ride a group), but the p99 stays ~3 ms — someone always pays the F_FULLFSYNC.
| question | prediction | actual |
|---|---|---|
| ticks to first leader, 5 nodes (timeout 10-20, heartbeat 3) | ||
| how often does seed 0..10 hit a split vote (extra term)? | ||
| stale-leader test: how many ticks after heal until logs converge? | ||
| minority leader: does it stay Leader forever during partition? (it hears no higher term…) |
Implementation log
- raft.rs: tick (election timeout + heartbeats) — election tests green
- receive: RequestVote/Vote — one leader per term across seeds
- receive: AppendEntries consistency check + truncate; AppendResp next_idx repair — replicates_to_all green
- §5.4.2 commit rule — minority + stale-leader tests green
- partition_test timeline recorded here:
Surprises / dead ends:
Questions from the reading guides
Raft paper (reading-raft-paper.md)
- Why persist (term, voted_for, log) but not commit_index:
- Fig 8 without the current-term rule — which intersection fails:
- Why a leader never overwrites its own entries:
- Snapshot needs last_included_term because:
- valkey vs Raft: what async gives up, what it gets back:
valkey replication.c (reading-valkey-replication.md)
- Statement-shipping vs WAL-shipping ↔ topic 5 logical/physical:
- Backlog-size inequality for partial resync success:
- Chained replication offset coherence:
- Why full sync forks (COW):
- M15 stage 1: which PSYNC parts to keep:
raft-rs (reading-raft-rs.md)
- Why no fsync/sockets/threads in the library:
- maybe_commit on matched=[7,5,5,3,2] → commit index:
- next_idx decrement optimization (§5.3 footnote):
- advance_append pipelining — what still can’t reorder:
- Ready → M15 stage 2 mapping:
qdrant consensus (reading-qdrant-consensus.md)
- 10K upserts/s through raft = ? (use the 3 ms fsync above):
- Active/Dead/Partial ↔ Progress replicate/probe/snapshot:
- qdrant vector-read consistency:
- WAL-through-raft: right for a graph DB? FalkorDB’s answer:
- Storage impl behind ConsensusStateRef:
VSR (reading-vsr.md)
- Round-robin primary: removes / costs:
- DOVIEWCHANGE ships logs vs Raft repairs later — when each wins:
- VSR-no-disk loses committed data when:
- Recovery nonce prevents:
- TigerBeetle’s “disk can lie” ↔ topic 5 torn pages:
DDIA ch. 5/8/9 (reading-ddia-repl.md)
- {async, semi-sync, raft} × {RYW, monotonic, prefix} matrix:
- WAIT-1-then-wrong-promotion — which guarantee broke:
- Terms as fencing tokens in M15’s follower:
- Why FLP doesn’t doom Raft in practice:
- Linearizable reads: lease vs ReadIndex vs quorum — M22 pick:
Cross-topic threads
- repl_lag IS topic 5’s fsync ladder: the follower’s durability policy becomes the leader’s observable ack latency. Consensus makes this mandatory (majority must fsync before commit).
- sim.rs = topic 16’s DST in miniature: seeded delivery order + no wall clock ⇒ every partition bug replays from a u64.
- valkey’s replica handshake state machine = topic 7’s nonblocking event-loop pattern; the shared repl buffer = client output buffers.
- (replid, offset) vs (prev_index, prev_term): PSYNC can resume a stream but can’t DETECT divergence; Raft’s consistency check can.
- Hash slots vs ranges = topic 13’s problem in disguise: traversals (range scans) want locality, uniform load wants hashing.
M15 log (WAL shipping → Raft)
- stage 1: M5 WAL streamed over M7 RESP server, PSYNC-shaped (replid+offset, backlog ring, +CONTINUE/+FULLRESYNC)
- WAIT-style ack levels; kill -9 failover: measure acked-write loss per ack level
- stage 2: experiments/raft.rs → the WAL commit path
- latency: async vs WAIT 1 vs raft, same workload (compare against the repl_lag table above)
- read-path decision (stale follower reads?) recorded for M22/M29
Done when
- All 5 raft tests green across seeds; partition_test timeline shows commit freeze + truncation-on-heal; prediction table filled.
- Reading-guide questions answered; M15 stage-1 design sketched.