From cb71dec0c3b1202f85e26cbb80b849a24c6bda02 Mon Sep 17 00:00:00 2001 From: Yuan Wang Date: Thu, 4 Dec 2025 09:24:23 +0800 Subject: [PATCH] Disable RDB compression when diskless replication is used (#14575) Fixes #14538 If the master uses diskless synchronization and the replica uses diskless load, we can disable RDB compression to reduce full sync time. I tested on AWS and found we could reduce time by 20-40%. In terms of implementation, when the replica can use diskless load, the replica will send `replconf rdb-no-compress 1` to master to deliver a RDB without compression. If your network is slow, please disable repl-diskless-load, and maybe even repl-diskless-sync --------- Co-authored-by: Ozan Tezcan --- src/rdb.c | 4 +++ src/replication.c | 42 ++++++++++++++++++++++++++++++- src/server.h | 2 ++ tests/integration/replication.tcl | 1 + 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/rdb.c b/src/rdb.c index 0d1481624..1662b84b8 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -4010,6 +4010,10 @@ int rdbSaveToSlavesSockets(int req, rdbSaveInfo *rsi) { redisSetProcTitle("redis-rdb-to-slaves"); redisSetCpuAffinity(server.bgsave_cpulist); + /* Disable RDB compression if requested. */ + if (req & SLAVE_REQ_RDB_NO_COMPRESS) + server.rdb_compression = 0; + if (req & SLAVE_REQ_SLOTS_SNAPSHOT) { /* Slots snapshot is required */ retval = slotSnapshotSaveRio(req, &rdb, NULL); diff --git a/src/replication.c b/src/replication.c index dcef34569..13e0b79b5 100644 --- a/src/replication.c +++ b/src/replication.c @@ -1461,6 +1461,18 @@ void replconfCommand(client *c) { return; } c->main_ch_client_id = (uint64_t)client_id; + /* Inherit the rdb-no-compress request from the main channel. */ + if (main_ch->slave_req & SLAVE_REQ_RDB_NO_COMPRESS) + c->slave_req |= SLAVE_REQ_RDB_NO_COMPRESS; + } else if (!strcasecmp(c->argv[j]->ptr, "rdb-no-compress")) { + long rdb_no_compress = 0; + if (getRangeLongFromObjectOrReply(c, c->argv[j + 1], 0, 1, &rdb_no_compress, NULL) != C_OK) + return; + if (rdb_no_compress == 1) { + c->slave_req |= SLAVE_REQ_RDB_NO_COMPRESS; + } else { + c->slave_req &= ~SLAVE_REQ_RDB_NO_COMPRESS; + } } else { addReplyErrorFormat(c,"Unrecognized REPLCONF option: %s", (char*)c->argv[j]->ptr); @@ -2908,6 +2920,7 @@ void syncWithMaster(connection *conn) { char tmpfile[256], *err = NULL; int dfd = -1, maxtries = 5; int psync_result; + static int replconf_rdb_no_compress = 0; /* If this event fired after the user turned the instance into a master * with SLAVEOF NO ONE we must just return ASAP. */ @@ -3006,6 +3019,15 @@ void syncWithMaster(connection *conn) { if (err) goto write_error; } + /* If we are not going to save the RDB to disk, request that RDB + * compression be disabled, which speeds up RDB delivery. */ + replconf_rdb_no_compress = 0; + if (useDisklessLoad()) { + replconf_rdb_no_compress = 1; + err = sendCommand(conn, "REPLCONF", "rdb-no-compress", "1", NULL); + if (err) goto write_error; + } + /* Inform the master of our (slave) capabilities. * * EOF: supports EOF-style RDB transfer for diskless replication. @@ -3056,7 +3078,7 @@ void syncWithMaster(connection *conn) { } if (server.repl_state == REPL_STATE_RECEIVE_IP_REPLY && !server.slave_announce_ip) - server.repl_state = REPL_STATE_RECEIVE_CAPA_REPLY; + server.repl_state = REPL_STATE_RECEIVE_COMP_REPLY; /* Receive REPLCONF ip-address reply. */ if (server.repl_state == REPL_STATE_RECEIVE_IP_REPLY) { @@ -3069,6 +3091,24 @@ void syncWithMaster(connection *conn) { "REPLCONF ip-address: %s", err); } sdsfree(err); + server.repl_state = REPL_STATE_RECEIVE_COMP_REPLY; + return; + } + + if (server.repl_state == REPL_STATE_RECEIVE_COMP_REPLY && !replconf_rdb_no_compress) + server.repl_state = REPL_STATE_RECEIVE_CAPA_REPLY; + + /* Receive REPLCONF rdb-no-compress reply. */ + if (server.repl_state == REPL_STATE_RECEIVE_COMP_REPLY) { + err = receiveSynchronousResponse(conn); + if (err == NULL) goto no_response_error; + /* Ignore the error if any, not all the Redis versions support + * REPLCONF rdb-no-compress. */ + if (err[0] == '-') { + serverLog(LL_NOTICE,"(Non critical) Master does not understand " + "REPLCONF rdb-no-compress: %s", err); + } + sdsfree(err); server.repl_state = REPL_STATE_RECEIVE_CAPA_REPLY; return; } diff --git a/src/server.h b/src/server.h index 365d4eb95..d3e7740f9 100644 --- a/src/server.h +++ b/src/server.h @@ -516,6 +516,7 @@ typedef enum { REPL_STATE_RECEIVE_AUTH_REPLY, /* Wait for AUTH reply */ REPL_STATE_RECEIVE_PORT_REPLY, /* Wait for REPLCONF reply */ REPL_STATE_RECEIVE_IP_REPLY, /* Wait for REPLCONF reply */ + REPL_STATE_RECEIVE_COMP_REPLY, /* Wait for REPLCONF reply */ REPL_STATE_RECEIVE_CAPA_REPLY, /* Wait for REPLCONF reply */ REPL_STATE_SEND_PSYNC, /* Send PSYNC */ REPL_STATE_RECEIVE_PSYNC_REPLY, /* Wait for PSYNC reply */ @@ -581,6 +582,7 @@ typedef enum { #define SLAVE_REQ_RDB_EXCLUDE_FUNCTIONS (1 << 1) /* Exclude functions from RDB */ #define SLAVE_REQ_SLOTS_SNAPSHOT (1 << 2) /* Only slots snapshot is required */ #define SLAVE_REQ_RDB_CHANNEL (1 << 3) /* Use rdb channel replication, transfer RDB background */ +#define SLAVE_REQ_RDB_NO_COMPRESS (1 << 4) /* Don't enable RDB compression */ /* Mask of all bits in the slave requirements bitfield that represent non-standard (filtered) RDB requirements */ #define SLAVE_REQ_RDB_MASK (SLAVE_REQ_RDB_EXCLUDE_DATA | SLAVE_REQ_RDB_EXCLUDE_FUNCTIONS | SLAVE_REQ_SLOTS_SNAPSHOT) diff --git a/tests/integration/replication.tcl b/tests/integration/replication.tcl index 1569369e1..964f7a5dc 100644 --- a/tests/integration/replication.tcl +++ b/tests/integration/replication.tcl @@ -916,6 +916,7 @@ start_server {tags {"repl external:skip tsan:skip"} overrides {save ""}} { # so that the whole rdb generation process is bound to that set loglines [count_log_lines -2] [lindex $replicas 0] config set repl-diskless-load swapdb + [lindex $replicas 1] config set repl-diskless-load swapdb [lindex $replicas 0] config set key-load-delay 100 ;# 20k keys and 100 microseconds sleep means at least 2 seconds [lindex $replicas 0] replicaof $master_host $master_port [lindex $replicas 1] replicaof $master_host $master_port