Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

support sticky slave whose slaveof config won't be changed by Redis sentinel #1413

Open
wants to merge 1 commit into from

1 participant

Liu Yubao
Liu Yubao

When a Redis slave has slave-priority -1, it becomes a sticky slave,
Redis sentinel neither elects it to become master, nor sends "slaveof"
command to it after new master is elected.

This is to mirror Redis cluster, suppose we have two datacenters,
DC A has 3 Redis instances that are maintained by Redis sentinel,
DC B has 3 Redis instances that synchronize from DC A with fixed
one-one mapping, aka. B_i slaveof A_i where i is 1, 2 or 3. This
wastes cross datacenter bandwidth because three copies of change
are transferred, but is more robust than chaining B2 and B3 to B1.

Without this feature, Redis sentinel will make all slaves synchronize
from single master sooner or later after multiple master elections,
this will consume big bandwidth of the master.

Notice if for some reason we want to revert the mirror relationship,
these steps must be taken to avoid race condition:
1. send "SLAVEOF NO ONE" to B1, send "SLAVEOF B1_addr B1_port" to B2 and B3
2. send "CONFIG SET SLAVE-PRIORITY 100" to B1, B2 and B3
3. start Redis sentinels for B1, B2 and B3
4. stop Redis sentinels for A1, A2 and A3
5. send "CONFIG SET SLAVE-PRIORITY -1" to A1, A2 and A3
6. send "SLAVEOF B_i_addr B_i_port" to A_i where i is 1, 2 or 3

Liu Yubao Dieken support sticky slave whose slaveof config won't be changed by Redis s…
…entinel

When a Redis slave has slave-priority -1, it becomes a sticky slave,
Redis sentinel neither elects it to become master, nor sends "slaveof"
command to it after new master is elected.

This is to mirror Redis cluster, suppose we have two datacenters,
DC A has 3 Redis instances that are maintained by Redis sentinel,
DC B has 3 Redis instances that synchronize from DC A with fixed
one-one mapping, aka. B_i slaveof A_i where i is 1, 2 or 3. This
wastes cross datacenter bandwidth because three copies of change
are transferred, but is more robust than chaining B2 and B3 to B1.

Without this feature, Redis sentinel will make all slaves synchronize
from single master sooner or later after multiple master elections,
this will consume big bandwidth of the master.

Notice if for some reason we want to revert the mirror relationship,
these steps must be taken to avoid race condition:
    1. send "SLAVEOF NO ONE" to B1, send "SLAVEOF <B1_addr> <B1_port>" to B2 and B3
    2. send "CONFIG SET SLAVE-PRIORITY 100" to B1, B2 and B3
    3. start Redis sentinels for B1, B2 and B3
    4. stop Redis sentinels for A1, A2 and A3
    5. send "CONFIG SET SLAVE-PRIORITY -1" to A1, A2 and A3
    6. send "SLAVEOF <B_i_addr> <B_i_port>" to A_i where i is 1, 2 or 3
f5214ec
Jackie JackieXie168 referenced this pull request from a commit
Etienne Laurin AtnNn Make version more explicit in osx package
Review 1030 by @mglukhovsky
Closes #1413
8ddb042
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 5, 2014
  1. Liu Yubao

    support sticky slave whose slaveof config won't be changed by Redis s…

    Dieken authored Yubao Liu committed
    …entinel
    
    When a Redis slave has slave-priority -1, it becomes a sticky slave,
    Redis sentinel neither elects it to become master, nor sends "slaveof"
    command to it after new master is elected.
    
    This is to mirror Redis cluster, suppose we have two datacenters,
    DC A has 3 Redis instances that are maintained by Redis sentinel,
    DC B has 3 Redis instances that synchronize from DC A with fixed
    one-one mapping, aka. B_i slaveof A_i where i is 1, 2 or 3. This
    wastes cross datacenter bandwidth because three copies of change
    are transferred, but is more robust than chaining B2 and B3 to B1.
    
    Without this feature, Redis sentinel will make all slaves synchronize
    from single master sooner or later after multiple master elections,
    this will consume big bandwidth of the master.
    
    Notice if for some reason we want to revert the mirror relationship,
    these steps must be taken to avoid race condition:
        1. send "SLAVEOF NO ONE" to B1, send "SLAVEOF <B1_addr> <B1_port>" to B2 and B3
        2. send "CONFIG SET SLAVE-PRIORITY 100" to B1, B2 and B3
        3. start Redis sentinels for B1, B2 and B3
        4. stop Redis sentinels for A1, A2 and A3
        5. send "CONFIG SET SLAVE-PRIORITY -1" to A1, A2 and A3
        6. send "SLAVEOF <B_i_addr> <B_i_port>" to A_i where i is 1, 2 or 3
This page is out of date. Refresh to see the latest.
Showing with 26 additions and 4 deletions.
  1. +3 −1 redis.conf
  2. +23 −3 src/sentinel.c
4 redis.conf
View
@@ -296,7 +296,9 @@ repl-disable-tcp-nodelay no
#
# However a special priority of 0 marks the slave as not able to perform the
# role of master, so a slave with priority of 0 will never be selected by
-# Redis Sentinel for promotion.
+# Redis Sentinel for promotion. Moreover, -1 marks a sticky slave whose slaveof
+# config won't be changed by Redis sentinel, this feature can be used to
+# mirror a Redis sentinel managed cluster.
#
# By default the priority is 100.
slave-priority 100
26 src/sentinel.c
View
@@ -325,6 +325,8 @@ sentinelRedisInstance *sentinelSelectSlave(sentinelRedisInstance *master);
void sentinelScheduleScriptExecution(char *path, ...);
void sentinelStartFailover(sentinelRedisInstance *master);
void sentinelDiscardReplyCallback(redisAsyncContext *c, void *reply, void *privdata);
+int sentinelIsElectableSlave(sentinelRedisInstance *ri);
+int sentinelIsStickySlave(sentinelRedisInstance *ri);
int sentinelSendSlaveOf(sentinelRedisInstance *ri, char *host, int port);
char *sentinelVoteLeader(sentinelRedisInstance *master, uint64_t req_epoch, char *req_runid, uint64_t *leader_epoch);
void sentinelFlushConfig(void);
@@ -1213,6 +1215,7 @@ int sentinelResetMasterAndChangeAddress(sentinelRedisInstance *master, char *ip,
sentinelRedisInstance *slave = dictGetVal(de);
if (sentinelAddrIsEqual(slave->addr,newaddr)) continue;
+ if (sentinelIsStickySlave(slave)) continue;
slaves = zrealloc(slaves,sizeof(sentinelAddr*)*(numslaves+1));
slaves[numslaves++] = createSentinelAddr(slave->addr->ip,
slave->addr->port);
@@ -1839,7 +1842,8 @@ void sentinelRefreshInstanceInfo(sentinelRedisInstance *ri, const char *info) {
* going forward, to receive new configs if any. */
mstime_t wait_time = SENTINEL_PUBLISH_PERIOD*4;
- if (sentinelMasterLooksSane(ri->master) &&
+ if (!sentinelIsStickySlave(ri) &&
+ sentinelMasterLooksSane(ri->master) &&
sentinelRedisInstanceNoDownFor(ri,wait_time) &&
mstime() - ri->role_reported_time > wait_time)
{
@@ -1854,7 +1858,7 @@ void sentinelRefreshInstanceInfo(sentinelRedisInstance *ri, const char *info) {
/* Handle slaves replicating to a different master address. */
if ((ri->flags & SRI_SLAVE) && !sentinel.tilt &&
- role == SRI_SLAVE &&
+ role == SRI_SLAVE && !sentinelIsStickySlave(ri) &&
(ri->slave_master_port != ri->master->addr->port ||
strcasecmp(ri->slave_master_host,ri->master->addr->ip)))
{
@@ -3045,6 +3049,16 @@ char *sentinelGetLeader(sentinelRedisInstance *master, uint64_t epoch) {
return winner;
}
+inline int sentinelIsElectableSlave(sentinelRedisInstance *ri) {
+ return ri->slave_priority != 0 && ri->slave_priority != -1;
+}
+
+/* Sticky slave always follows manually configured master, not affected
+ * by sentinel, this is to mirror Redis cluster. */
+inline int sentinelIsStickySlave(sentinelRedisInstance *ri) {
+ return ri->slave_priority == -1;
+}
+
/* Send SLAVEOF to the specified instance, always followed by a
* CONFIG REWRITE command in order to store the new configuration on disk
* when possible (that is, if the Redis instance is recent enough to support
@@ -3199,7 +3213,7 @@ sentinelRedisInstance *sentinelSelectSlave(sentinelRedisInstance *master) {
if (slave->flags & (SRI_S_DOWN|SRI_O_DOWN|SRI_DISCONNECTED)) continue;
if (mstime() - slave->last_avail_time > SENTINEL_PING_PERIOD*5) continue;
- if (slave->slave_priority == 0) continue;
+ if (!sentinelIsElectableSlave(slave)) continue;
/* If the master is in SDOWN state we get INFO for slaves every second.
* Otherwise we get it with the usual period so we need to account for
@@ -3329,6 +3343,7 @@ void sentinelFailoverDetectEnd(sentinelRedisInstance *master) {
if (slave->flags & (SRI_PROMOTED|SRI_RECONF_DONE)) continue;
if (slave->flags & SRI_S_DOWN) continue;
+ if (sentinelIsStickySlave(slave)) continue;
not_reconfigured++;
}
dictReleaseIterator(di);
@@ -3358,6 +3373,9 @@ void sentinelFailoverDetectEnd(sentinelRedisInstance *master) {
sentinelRedisInstance *slave = dictGetVal(de);
int retval;
+ if (sentinelIsStickySlave(slave))
+ continue;
+
if (slave->flags &
(SRI_RECONF_DONE|SRI_RECONF_SENT|SRI_DISCONNECTED)) continue;
@@ -3396,6 +3414,8 @@ void sentinelFailoverReconfNextSlave(sentinelRedisInstance *master) {
sentinelRedisInstance *slave = dictGetVal(de);
int retval;
+ if (sentinelIsStickySlave(slave)) continue;
+
/* Skip the promoted slave, and already configured slaves. */
if (slave->flags & (SRI_PROMOTED|SRI_RECONF_DONE)) continue;
Something went wrong with that request. Please try again.