Skip to content

Replication

FrogDB implements asynchronous primary-replica replication using the Redis PSYNC2 protocol. The standard replication commands (REPLICAOF, ROLE, INFO replication) behave as documented by the Redis replication docs; this page covers setup, write quorum, the sync mechanism, and monitoring. Cluster metadata and failover coordination live one layer up in Clustering; replication is the data plane beneath it.

  • Raft-coordinated or manual failover. FrogDB has no Sentinel and no external orchestrator. In cluster mode a Raft leader can promote a replica automatically (auto-failover, see Clustering); otherwise promotion is manual via CLUSTER FAILOVER.
  • RocksDB checkpoints for full resync instead of an RDB transfer. The primary streams a consistent RocksDB checkpoint rather than serializing an RDB file.
  • SHA256 integrity verification. The checkpoint payload carries a SHA256 checksum that the replica verifies on receipt.
  • Replicas do not evict independently. Eviction decisions are made on the primary and applied on replicas through the replicated write stream, not recomputed locally.
  • Memory-aware full sync. A full resync is bounded by fullsync-max-memory-mb; a FULLRESYNC is rejected when the buffered payload would exceed that limit.

Replication is configured under the [replication] section. A minimal replica points at its primary:

[replication]
role = "replica" # standalone | primary | replica
primary-host = "primary.internal"
primary-port = 6379

A primary that requires acknowledged replicas before returning success to writers:

[replication]
role = "primary"
min-replicas-to-write = 1
min-replicas-timeout-ms = 5000

REPLICAOF <host> <port> (and REPLICAOF NO ONE) also changes the role at runtime without a restart.

The full key set and defaults:

KeyDefaultPurpose
rolestandalonestandalone, primary, or replica.
primary-host""Primary to connect to; required when role = "replica".
primary-port6379Primary port for a replica.
min-replicas-to-write0Replicas that must acknowledge a write before it returns success (0 disables).
min-replicas-timeout-ms5000How long a write waits for those acknowledgements.
ack-interval-ms1000How often a replica sends REPLCONF ACK.
fullsync-timeout-secs300Maximum duration of a full sync.
fullsync-max-memory-mb512Buffering cap for full sync; a FULLRESYNC over this is rejected.
state-filereplication_state.jsonPersists the replication ID and offset for partial-sync recovery.
connect-timeout-ms5000Replica-to-primary connect timeout.
handshake-timeout-ms10000Replication handshake timeout.
reconnect-backoff-initial-ms100Initial reconnect backoff.
reconnect-backoff-max-ms30000Maximum reconnect backoff.
replication-lag-threshold-bytes0Proactively disconnect a replica lagging by this many bytes (0 disables).
replication-lag-threshold-secs0Proactively disconnect a replica whose last ACK is this old (0 disables).
fullresync-cooldown-secs60Cooldown after a lag-triggered disconnect before another is allowed.
self-fence-on-replica-losstrueReject writes when the primary loses ACK freshness from all replicas.
replica-freshness-timeout-ms3000ACK-freshness window for self-fencing; the build warns if this is below 3 × ack-interval-ms.
replica-write-timeout-ms5000Write timeout when streaming to a replica (0 disables); forces a disconnect when packets are silently dropped.
split-brain-log-enabledtrueLog divergent writes from a demoted primary before resync (logging only).
split-brain-buffer-size10000Recent commands buffered for split-brain detection.
split-brain-buffer-max-mb64Memory cap for the split-brain buffer.

See the Configuration reference for the authoritative, generated list.

When min-replicas-to-write is greater than zero, a write on the primary waits for that many replicas to acknowledge before it returns success. The wait is bounded by min-replicas-timeout-ms. This is a best-effort durability signal, not a hard quorum: if the timeout elapses before enough replicas acknowledge, the write still proceeds and returns with however many acknowledgements it received. Use it to reduce the window of unreplicated writes, not as a guarantee that a write reached N replicas.

Self-fencing is a separate, stricter guard. With self-fence-on-replica-loss enabled (the default), a primary that stops receiving fresh ACKs from all of its replicas within replica-freshness-timeout-ms rejects further writes rather than accepting writes it cannot replicate — the case that would otherwise produce a diverging “zombie” primary during a partition. Keep replica-freshness-timeout-ms at least 3 × ack-interval-ms; the server logs a warning at startup otherwise, because a tighter window causes spurious rejections.

A replica that cannot resume from its saved offset performs a full sync. The primary produces a consistent RocksDB checkpoint and streams it in 64 KB chunks; a SHA256 checksum computed over the payload is sent with the trailing metadata and verified by the replica before the data is accepted. Full sync is memory-bounded by fullsync-max-memory-mb — if servicing the FULLRESYNC would exceed that cap, the request is rejected rather than risking an out-of-memory condition. Checkpoint internals are covered in Persistence & durability.

A replica that is only briefly behind performs a partial sync: it sends PSYNC <replication-id> <offset>, and if the primary still holds the required history it replies CONTINUE and resumes streaming write frames from that offset. The replication ID and offset are persisted in state-file so a replica can attempt partial sync across a restart.

On promotion a new primary begins a new replication history and other replicas re-synchronize against it. FrogDB tracks a secondary replication ID field for compatibility, but the promotion hand-off should be treated qualitatively — do not rely on a specific secondary-ID continuation behavior.

FrogDB does not ship an external failover controller. Promotion happens one of two ways:

  • Raft-coordinated — in cluster mode with auto-failover = true, the Raft leader promotes a replica after a primary is marked failed, choosing among candidates by replica-priority. See Clustering for the control-plane configuration and failure-mode details.
  • ManualCLUSTER FAILOVER promotes a replica on demand.

In both cases the promoted node becomes a primary with a fresh replication history, and surviving replicas reconnect to it via PSYNC.

Query replication state with:

Terminal window
redis-cli INFO replication

A primary reports role:master, connected_slaves, master_replid, master_replid2, master_repl_offset, second_repl_offset, and the repl_backlog_* fields. A replica additionally reports master_host, master_port, and master_link_status.

To measure lag, compare master_repl_offset on the primary with master_repl_offset reported by the replica — both sides expose the offset under the same field name (master_repl_offset); there is no slave_repl_offset field. An offset that falls persistently behind the primary’s is the signal to act on, alongside the primary’s connected_slaves count and any write rejections from self-fencing.

master_link_status reports up once the replica has completed the handshake and is actively streaming from the primary, and down at any other time — including before the initial connection completes, during a resync, and after the link drops (the replica keeps retrying with backoff; up returns once it reconnects and resumes streaming). It’s a connectivity signal, not a data-freshness one: down means no data is currently arriving over the link, but doesn’t by itself say how stale the replica’s data is — master_repl_offset and the offset gap are what answer that. Alert on master_link_status:down alongside the offset gap and the primary-side indicators, not as a standalone signal.

SymptomLikely causeWhat to check
Repeated full resyncsReplica offset falls outside retained history, or lag guards tripReview replication-lag-threshold-bytes / -secs and fullresync-cooldown-secs; check network stability between primary and replica.
Writes rejected on the primarySelf-fencing after loss of replica ACK freshnessConfirm replicas are connected and ACKing; check replica-freshness-timeout-ms relative to ack-interval-ms.
FULLRESYNC rejectedFull-sync payload exceeds fullsync-max-memory-mbRaise fullsync-max-memory-mb, or provision more replica memory.
Replica out of memory during syncDataset exceeds replica capacityProvision the replica with headroom above the primary’s footprint.

The Metrics reference lists the exported Prometheus metrics.