How Redis Master‑Slave Replication Works: Handshake, Sync, and Code Walkthrough
Redis, the high‑performance open‑source key‑value store, uses a master‑slave replication mechanism that ensures data redundancy, read/write separation, fault recovery, and high‑availability; this article explains its handshake process, synchronization phases, replication states, and key source‑code functions in detail.
Redis is an open‑source key‑value storage system that can serve as a database, cache, or messaging component.
Created by Salvatore Sanfilippo (antirez) in 2009, Redis quickly became popular due to its high performance and rich feature set, making it a common component in high‑concurrency systems.
It provides various data structures such as String, Hash, List, Set, and Sorted Set, and supports distributed deployment with master‑slave replication, Sentinel for high availability, and Cluster for horizontal scaling.
Redis also offers persistence, Lua scripting, modules, Streams, and tracking mechanisms for diverse business scenarios.
Redis is a typical "small and beautiful" program. Its source code is elegant and easy to read, while its functionality covers storage, distribution, and messaging.
The master‑slave replication mechanism is a key concept in Redis.
Master‑slave replication purposes:
Data redundancy : hot backup on slaves protects data against master failures.
Read/write separation : the master handles writes, slaves handle reads, improving throughput.
Fault recovery : if the master fails, a slave can be promoted to continue service.
High‑availability foundation : replication underlies Sentinel and Cluster failover mechanisms.
The replication process is divided into three stages:
Handshake stage : after a successful connection, the slave sends its information (IP, port, etc.) to the master.
Synchronization stage : the slave synchronizes data with the master, achieving consistency before replication.
Replication stage : the master asynchronously propagates write commands to the slave, which executes them.
Redis supports two synchronization modes:
Full sync: the slave sends PSYNC ? -1, the master replies +FULLRESYNC and streams an RDB file.
Partial sync: the slave sends PSYNC replid offset, the master replies +CONTINUE and streams only commands after the given offset; if the offset is missing, the master falls back to full sync.
PSYNC command attributes: server.master_repl_offset: current replication offset. server.replid: 40‑hex‑digit identifier (master’s ID on master, master’s ID stored on slave). server.replid2: previous master ID (used on master). server.repl_backlog: replication backlog buffer for partial sync.
The replication is initiated by the slave using the REPLICAOF command (alias of SLAVEOF since Redis 5): REPLICAOF <masterip> <masterport> or by setting replicaof in the configuration file.
Tip: From Redis 5 onward, SLAVEOF has the alias REPLICAOF ; both commands behave identically.
The slave processes the command via replicaofCommand:
(1) REPLICAOF NO ONE converts the server to a master, breaking any existing replication.
(2) Calls replicationSetMaster to establish the master‑slave relationship.
When the configuration contains replicaof, the server’s repl_state is set to REPL_STATE_CONNECT during startup.
The serverCron event loop handles the REPL_STATE_CONNECT state:
int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
...
if (server.repl_state == REPL_STATE_CONNECT) {
if (connectWithMaster() == C_OK) {
serverLog(LL_NOTICE,"MASTER <-> REPLICA sync started");
}
}
...
} connectWithMastercreates a socket (or TLS connection) and attempts to connect to the master:
int connectWithMaster(void) {
server.repl_transfer_s = server.tls_replication ? connCreateTLS() : connCreateSocket();
if (connConnect(server.repl_transfer_s, server.masterhost, server.masterport,
NET_FIRST_BIND_ADDR, syncWithMaster) == C_ERR) {
return C_ERR;
}
server.repl_transfer_lastio = server.unixtime;
server.repl_state = REPL_STATE_CONNECTING;
return C_OK;
}After a successful connection, the slave invokes syncWithMaster to start the handshake:
void syncWithMaster(connection *conn) {
char tmpfile[256], *err = NULL;
int dfd = -1, maxtries = 5;
int psync_result;
...
if (server.repl_state == REPL_STATE_CONNECTING) {
connSetReadHandler(conn, syncWithMaster);
connSetWriteHandler(conn, NULL);
server.repl_state = REPL_STATE_RECEIVE_PONG;
err = sendSynchronousCommand(SYNC_CMD_WRITE, conn, "PING", NULL);
if (err) goto write_error;
return;
}
if (server.repl_state != REPL_STATE_RECEIVE_PSYNC) {
goto error;
}
...
}During the handshake the slave sends information (e.g., REPLCONF commands) that the master records and that Sentinel later reads via INFO.
Replication states on the slave include:
REPL_STATE_NONE – no replication.
REPL_STATE_CONNECT – waiting to connect.
REPL_STATE_CONNECTING – connection in progress.
REPL_STATE_TRANSFER – receiving RDB data.
REPL_STATE_CONNECTED – replication established.
Network traffic can be captured with tcpdump to observe the handshake: tcpdump tcp -i lo -nn port 6000 -T RESP The captured RESP output shows the exchange of PING, AUTH, and REPLCONF commands between master and slave.
In summary, Redis’s master‑slave handshake involves the slave initiating a connection, sending its identity, performing a full or partial synchronization via PSYNC, and then receiving asynchronous command streams from the master, providing data redundancy, read/write separation, and a foundation for high‑availability mechanisms.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
