Compare commits

...
4 Commits
Author SHA1 Message Date
antirez c1d10e8bb7 No-sync: some info in the example redis.conf comments. 2015-02-13 08:57:15 +01:00
antirez ede98af9da No-sync: fixed missing conditional in syncCommand(). 2015-02-13 08:57:15 +01:00
antirez de6f74838a No-sync: avoid master to be marked as PRE-PSYNC.
replicationCreateMasterClient() will mark it as such if we don't set a
fake initial replication offset.
2015-02-13 08:57:15 +01:00
antirez abbfbcf161 Experimental no-sync replication mode. 2015-02-13 08:57:15 +01:00
6 changed files with 97 additions and 3 deletions
+32
View File
@@ -300,6 +300,38 @@ repl-diskless-sync-delay 5
#
# repl-ping-slave-period 10
# WARNING: This feature is experimental, just an evaluation draft.
#
# No-sync replication is a special, inconistent, mode of operation for slaves
# that is sometimes useful in caching scenarios.
#
# In this setup slaves, when connecting to masters, don't ask for the pre
# existing state of the key space, so no synchronization with the current
# master data is performed at all. However the slaves will get all the new
# stream of writes receiving the master, starting from the moment the slave
# connects.
#
# This means that:
# 1) There is no consistency between master and slaves operating in this mode.
# 2) It is possible that keys with an expire in the master will never expire
# in the slave (because the slave may miss the EXPIRE command).
# 3) Keys updated with non-idempotent commands may end with different values.
#
# However if your workload is about idempotent updates (for example using
# just the SET command), and no-sync slaves are configured in order to evict
# data on their own using maxmemory and a suitable policy, there are certain
# advantages:
#
# 1) Slaves are always available (assuming they are configured to serve stale
# data), since reconnecting with the master has no cost.
# 2) Masters don't have to persist on disk and/or stream an RDB file to the
# slaves, slaves are just accepted ASAP and put online.
#
# To enable, simply set repl-no-sync to yes. By default this feature is
# disabled.
#
# repl-no-sync no
# The following option sets the replication timeout for:
#
# 1) Bulk transfer I/O during SYNC, from the point of view of slave.
+4
View File
@@ -276,6 +276,10 @@ void loadServerConfigFromString(char *config) {
if ((server.repl_diskless_sync = yesnotoi(argv[1])) == -1) {
err = "argument must be 'yes' or 'no'"; goto loaderr;
}
} else if (!strcasecmp(argv[0],"repl-no-sync") && argc==2) {
if ((server.repl_no_sync = yesnotoi(argv[1])) == -1) {
err = "argument must be 'yes' or 'no'"; goto loaderr;
}
} else if (!strcasecmp(argv[0],"repl-diskless-sync-delay") && argc==2) {
server.repl_diskless_sync_delay = atoi(argv[1]);
if (server.repl_diskless_sync_delay < 0) {
+4 -1
View File
@@ -673,7 +673,10 @@ void freeClient(redisClient *c) {
*
* Note that before doing this we make sure that the client is not in
* some unexpected state, by checking its flags. */
if (server.master && c->flags & REDIS_MASTER) {
if (server.master &&
c->flags & REDIS_MASTER &&
server.repl_no_sync == 0)
{
redisLog(REDIS_WARNING,"Connection with master lost.");
if (!(c->flags & (REDIS_CLOSE_AFTER_REPLY|
REDIS_CLOSE_ASAP|
+1
View File
@@ -1496,6 +1496,7 @@ void initServerConfig(void) {
server.repl_disable_tcp_nodelay = REDIS_DEFAULT_REPL_DISABLE_TCP_NODELAY;
server.repl_diskless_sync = REDIS_DEFAULT_REPL_DISKLESS_SYNC;
server.repl_diskless_sync_delay = REDIS_DEFAULT_REPL_DISKLESS_SYNC_DELAY;
server.repl_no_sync = REDIS_DEFAULT_REPL_NO_SYNC;
server.slave_priority = REDIS_DEFAULT_SLAVE_PRIORITY;
server.master_repl_offset = 0;
+3
View File
@@ -119,6 +119,7 @@ typedef long long mstime_t; /* millisecond time type. */
#define REDIS_DEFAULT_RDB_FILENAME "dump.rdb"
#define REDIS_DEFAULT_REPL_DISKLESS_SYNC 0
#define REDIS_DEFAULT_REPL_DISKLESS_SYNC_DELAY 5
#define REDIS_DEFAULT_REPL_NO_SYNC 0
#define REDIS_DEFAULT_SLAVE_SERVE_STALE_DATA 1
#define REDIS_DEFAULT_SLAVE_READ_ONLY 1
#define REDIS_DEFAULT_REPL_DISABLE_TCP_NODELAY 0
@@ -258,6 +259,7 @@ typedef long long mstime_t; /* millisecond time type. */
#define REDIS_READONLY (1<<17) /* Cluster client is in read-only state. */
#define REDIS_PUBSUB (1<<18) /* Client is in Pub/Sub mode. */
#define REDIS_PREVENT_PROP (1<<19) /* Don't propagate to AOF / Slaves. */
#define REDIS_SLAVE_NO_SYNC (1<<20) /* Result of: REPLCONF use-sync 0. */
/* Client block type (btype field in client structure)
* if REDIS_BLOCKED flag is set. */
@@ -853,6 +855,7 @@ struct redisServer {
int slave_priority; /* Reported in INFO and used by Sentinel. */
char repl_master_runid[REDIS_RUN_ID_SIZE+1]; /* Master run id for PSYNC. */
long long repl_master_initial_offset; /* Master PSYNC offset. */
int repl_no_sync; /* Streaming replication, no SYNC. */
/* Replication script cache. */
dict *repl_scriptcache_dict; /* SHA1 all slaves are aware of. */
list *repl_scriptcache_fifo; /* First in, first out LRU eviction. */
+53 -2
View File
@@ -480,6 +480,9 @@ void syncCommand(redisClient *c) {
return;
}
/* Accept the slave ASAP if it requested no-sync mode. */
if (c->flags & REDIS_SLAVE_NO_SYNC) goto attach_slave;
redisLog(REDIS_NOTICE,"Slave %s asks for synchronization",
replicationGetSlaveName(c));
@@ -571,6 +574,8 @@ void syncCommand(redisClient *c) {
}
}
attach_slave:
if (server.repl_disable_tcp_nodelay)
anetDisableTcpNoDelay(NULL, c->fd); /* Non critical if it fails. */
c->repldbfd = -1;
@@ -579,6 +584,18 @@ void syncCommand(redisClient *c) {
listAddNodeTail(server.slaves,c);
if (listLength(server.slaves) == 1 && server.repl_backlog == NULL)
createReplicationBacklog();
/* Put the slave fully online right now if it is a no-sync one. */
if (c->flags & REDIS_SLAVE_NO_SYNC) {
char buf[128];
int buflen;
/* Inform the slave with +NOTNEEDED that the request was accepted. */
buflen = snprintf(buf,sizeof(buf),"+NOTNEEDED\r\n");
if (write(c->fd,buf,buflen) != buflen) freeClientAsync(c);
aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
putSlaveOnline(c);
}
return;
}
@@ -613,6 +630,18 @@ void replconfCommand(redisClient *c) {
&port,NULL) != REDIS_OK))
return;
c->slave_listening_port = port;
} else if (!strcasecmp(c->argv[j]->ptr,"use-sync")) {
/* REPLCONF USE-SYNC is used in order for the slave to request
* synchronization-less replication, the master will just send
* new data without trying to synchronize the slave. */
long long val;
if ((getLongLongFromObject(c->argv[j+1], &val) != REDIS_OK))
return;
if (val)
c->flags &= ~REDIS_SLAVE_NO_SYNC;
else
c->flags |= REDIS_SLAVE_NO_SYNC;
} else if (!strcasecmp(c->argv[j]->ptr,"ack")) {
/* REPLCONF ACK is used by slave to inform the master the amount
* of replication stream that it processed so far. It is an
@@ -1140,7 +1169,7 @@ int slaveTryPartialResynchronization(int fd) {
* client structure representing the master into server.master. */
server.repl_master_initial_offset = -1;
if (server.cached_master) {
if (server.cached_master && server.repl_no_sync == 0) {
psync_runid = server.cached_master->replrunid;
snprintf(psync_offset,sizeof(psync_offset),"%lld", server.cached_master->reploff+1);
redisLog(REDIS_NOTICE,"Trying a partial resynchronization (request %s:%s).", psync_runid, psync_offset);
@@ -1186,6 +1215,15 @@ int slaveTryPartialResynchronization(int fd) {
return PSYNC_FULLRESYNC;
}
if (!strncmp(reply,"+NOTNEEDED",10)) {
/* No-sync replication. */
redisLog(REDIS_NOTICE, "No-sync slave accepted without SYNC phase.");
sdsfree(reply);
server.repl_master_initial_offset = 0;
replicationCreateMasterClient(fd);
return PSYNC_CONTINUE;
}
if (!strncmp(reply,"+CONTINUE",9)) {
/* Partial resync was accepted, set the replication state accordingly */
redisLog(REDIS_NOTICE,
@@ -1292,7 +1330,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
}
/* AUTH with the master if required. */
if(server.masterauth) {
if (server.masterauth) {
err = sendSynchronousCommand(fd,"AUTH",server.masterauth,NULL);
if (err[0] == '-') {
redisLog(REDIS_WARNING,"Unable to AUTH to MASTER: %s",err);
@@ -1302,6 +1340,18 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
sdsfree(err);
}
/* Inform the master we don't want to synchronize if we are using
* repl-no-sync mode. */
if (server.repl_no_sync) {
err = sendSynchronousCommand(fd,"REPLCONF","use-sync","0",NULL);
if (err[0] == '-') {
redisLog(REDIS_WARNING,"Unable to enable no-sync mode: %s",err);
sdsfree(err);
goto error;
}
sdsfree(err);
}
/* Set the slave port, so that Master's INFO command can list the
* slave listening port correctly. */
{
@@ -1698,6 +1748,7 @@ void refreshGoodSlavesCount(void) {
time_t lag = server.unixtime - slave->repl_ack_time;
if (slave->replstate == REDIS_REPL_ONLINE &&
!(slave->flags & REDIS_SLAVE_NO_SYNC) &&
lag <= server.repl_min_slaves_max_lag) good++;
}
server.repl_good_slaves_count = good;