State machine replication (SMR) is the technique that makes Raft- or Paxos-backed services behave like a single fault-tolerant computer. A deterministic state machine consumes a replicated log of commands; as long as every replica applies entries in the same order, their state stays identical despite crashes or message delays.
Transactional key-value engines, distributed coordinators, and queue schedulers all use SMR to provide linearizable APIs. If you understand how to apply, snapshot, and recover logs you can reason about failover bounds, durability guarantees, and maintenance operations.
This document covers log structure, apply pipelines, snapshotting, and operational playbooks that keep SMR clusters consistent even during chaos events.
Determinism requires requests to be fully specified—no hidden clocks or randomness. Any nondeterminism leads to divergent state even if consensus is perfect.
The applied index is separate from the committed index; crashing after commit but before apply is safe as long as entries are replayed on restart.
A background worker tails the consensus log. When commit index advances, it batches entries, decodes them, and invokes the deterministic state transition. After each batch, it persists the new applied index and any write-ahead redo artifacts.
Apply loops must avoid blocking Raft. Use bounded channels so pressure propagates upstream and leaders slow down before saturating follower disks.
When the log grows beyond a threshold, replicas checkpoint state (e.g., RocksDB backup, serialized B-Tree) plus the last applied index. Older log entries up to that index can be discarded. Followers that fall behind catch up either by streaming remaining log or by installing the snapshot.
Snapshots must be self-describing: include term/index, cluster ID, and checksum so receivers can validate before replacing local state.
After a crash, the node replays the snapshot, then re-applies remaining log entries from the persisted applied index + 1. If the log is truncated beyond that point, the node requests a fresh snapshot from peers.
func (a *Applier) run(ctx context.Context) {
for {
select {
case batch := <-a.commitCh:
for _, entry := range batch {
if err := a.fsm.Apply(entry.Data); err != nil {
a.logger.Error("apply failed", "index", entry.Index, "err", err)
panic(err)
}
a.applied = entry.Index
}
if err := a.store.SetApplied(a.applied); err != nil {
a.logger.Fatal("persist applied", err)
}
case <-ctx.Done():
return
}
}
}
const SnapshotHeader = struct {
magic: u32 = 0x5A4D5301,
term: u64,
index: u64,
checksum: u128,
};
fn writeSnapshotHeader(writer: anytype, term: u64, index: u64, checksum: u128) !void {
var hdr = SnapshotHeader{ .term = term, .index = index, .checksum = checksum };
try writer.writeStruct(hdr);
}
time.Now() or random IDs inside the FSM creates divergent replicas.