Currently in testing: the GitHub code will be opened once complete.

Raft Parameters

ItemValue
Heartbeat interval500ms (cluster_heartbeat_ms)
Unresponsive threshold2000ms (cluster_election_timeout_ms) — once heartbeats have been missing this long, the leader is presumed dead
Actual election-start window1750-2000ms — randomized per node to prevent simultaneous candidacies (split vote). The worst case equals exactly the unresponsive threshold you configured
Client stall on leader failuremeasured at unresponsive threshold + 0.3-0.5s (about 2.3-2.5s at the defaults) — detection plus one redirect
Node count3 or 5 (enforced at config load — anything else refuses to boot)
Node IDits (cluster_self) position in the cluster_peers list — which is why the list order must be identical on every node
Bootstrap500ms after startup, every node initializes with the same membership — ignored if joining an already-initialized cluster
Log storagein-memory (volatile) — a restarted node recovers via replication/snapshot
Lease-expiry detectionthe leader checks every 100ms and commits Expire via consensus
wait timeout granularitythe wait timeout (T) is also decided on the same 100ms tick — it can arrive up to 100ms late
Leader-change noticewhen the leader changes, an L is pushed immediately to every connected client

Choosing the Heartbeat and Unresponsive Threshold

Both are tuned via cluster_heartbeat_ms and cluster_election_timeout_ms in the configuration. The unresponsive threshold (T) is exactly how long service stalls when the leader fails; set it too short, on the other hand, and a live leader gets misjudged as dead, triggering needless elections.

Heartbeat / TDetection windowWorst-case delay on leader kill (measured)Recommended for
100ms / 600ms450-600ms~0.9sSame rack / same AZ, very stable latency
100ms / 1000ms750-1000ms~1.2sSame AZ
250ms / 2500ms1875-2500ms~2.8sMulti-AZ
500ms / 2000ms1750-2000ms~2.4sDefault — balanced for multi-AZ
500ms / 5000ms3750-5000ms~5.3sCross-region / environments with large latency spikes
  • Steady-state latency is unaffected by these values (no measurable p50 change) — they only govern recovery time during a failure.
  • A follower dying has no client-visible impact at any setting. The delays above occur only when the leader dies.
  • Constraints: cluster_election_timeout_ms must be at least 600ms, and at least 4× the heartbeat. (A single scheduling stall under load has been measured swallowing two heartbeats whole.)

Why 3 or 5 Nodes

A commit needs a majority. An even-numbered configuration only adds cost without adding fault tolerance, so the server refuses it.

Node countMajorityConcurrent failures tolerated
220 — a single failure stops the cluster. No better than single mode
321
431 — same as 3 nodes, just costs more
532

Failure Behavior Summary

SituationBehavior
Client request to a non-leader nodeM (leader address), or E no_leader if the leader is unknown
Leader failurea new leader is elected within the unresponsive threshold (1750-2000ms at the defaults). Requests during that window get E no_leader → the client retries
Mid-leader-changepending acquire requests are cleared with M/E no_leader, and the client retries against the new leader
Node restartboots with empty state → catches up via a peer's log replication/snapshot
Majority lostcommits become impossible → writes stop (safety first), resuming automatically once the majority is restored

Terminology

  • quorum — more than half of all nodes (2 of 3, or 3 of 5). Since any decision requires quorum agreement, two partitioned groups can never both commit conflicting decisions at once.
  • unresponsive threshold (election timeout) — how long a follower waits without a heartbeat before concluding the leader has died and starting an election. Randomized per node to reduce simultaneous candidacies.