Skip to content
Lesson 28 of 29

Step 1 of 3 · Reading · ~3 min

Master/Replica Replication

Scripting, Replication & Streams

Why replicate

A single Redis instance is a single point of failure and a single point of read capacity. Replication solves both: one or more replica servers keep a live copy of a master's dataset, so reads can be spread across replicas and a replica can be promoted if the master dies. The mechanism Redis uses to keep replicas in sync is PSYNC — Partial (or full) SYNChronization.

Two ways to catch a replica up

When a replica connects (or reconnects after a network blip), the master has to answer one question: how far behind is this replica, and what's the cheapest way to get it current?

  1. Full resync — the replica has no usable prior state (first connection, or too far behind). The master sends a complete point-in-time snapshot of the dataset (in real Redis, an RDB file), then streams every write that happens after the snapshot was taken.
  2. Partial resync — the replica already has most of the data and just missed a short window of commands (e.g., a brief disconnect). If the master still has those missed commands in its replication backlog, it can just replay that slice instead of re-sending everything.

PSYNC ? -1 is the replica saying "I have nothing, give me everything" (unknown replication ID, unknown offset) — this always triggers full resync. PSYNC <replid> <offset> is the replica saying "I was following replication stream <replid> up to offset <offset>" — if the master recognizes that ID and still has the backlog from that offset onward, it replies +CONTINUE and streams just the gap.

The replication backlog

The backlog is the mechanism that makes partial resync possible at all: it's an append-only record of every write command the master has applied, kept around (in real Redis, as a bounded ring buffer sized by repl-backlog-size) so a recently-disconnected replica can be caught up cheaply instead of re-transferring the whole dataset.

backlog = []   # append every write command, in execution order

def apply_write(cmd):
    execute(cmd)
    backlog.append(cmd)

Reads never touch the backlog — only mutations matter for keeping replicas consistent, since reads produce no state change to propagate.

Role state machine

Your server tracks one of two roles:

  • master (the default) — accepts writes directly, serves PSYNC requests from replicas, and appends to its backlog.
  • replica — declared via REPLICAOF <host> <port>. In real Redis this actually opens a connection to the named master and starts syncing; in this simplified exercise you only need to record the role and target, since we aren't wiring up real inter-process networking here.

REPLICAOF NO ONE reverts a replica back to being its own master — this is exactly the command an operator runs during a manual failover, promoting a replica once the old master is confirmed dead.

ROLE just reports which mode you're in, as a bulk string (master or replica) — this is what tools and health checks poll to figure out where they can safely send writes.

Handshake response shapes

PSYNC ? -1
  -> +FULLRESYNC <replid> 0\r\n
     $<n>\r\n<serialized keyspace>\r\n
     $<n>\r\n<backlog contents>\r\n

PSYNC <replid> <offset>
  -> +CONTINUE\r\n
     $<n>\r\n<backlog entries from offset onward>\r\n

Use the fixed test replid (abc0000...) rather than generating a random one — replication IDs are normally random 40-hex-char strings so two masters never collide, but determinism matters more than realism for testable output here.

Edge cases

  • An offset beyond what the backlog currently holds (replica disconnected too long, entries aged out) should force a fallback to full resync in real Redis — worth thinking about even if this exercise's backlog never truncates.
  • REPLICATION_LOG is a debug aid, not part of the real protocol — it exists here purely so tests (and you) can inspect backlog state without needing a second live connection.
  • Writes issued while a snapshot is being taken must still land in the backlog exactly once — don't double-count a command that happens to occur during the "snapshot" step of a full resync.
Up nextXADD & XREAD — Redis StreamsScripting, Replication & Streams

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…