1 /* Redis Sentinel implementation 2 * 3 * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * * Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * * Neither the name of Redis nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without 16 * specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "redis.h" 32 #include "hiredis.h" 33 #include "async.h" 34 35 #include <ctype.h> 36 #include <arpa/inet.h> 37 #include <sys/socket.h> 38 #include <sys/wait.h> 39 #include <fcntl.h> 40 41 extern char **environ; 42 43 #define REDIS_SENTINEL_PORT 26379 44 45 /* ======================== Sentinel global state =========================== */ 46 47 /* Address object, used to describe an ip:port pair. */ 48 typedef struct sentinelAddr { 49 char *ip; 50 int port; 51 } sentinelAddr; 52 53 /* A Sentinel Redis Instance object is monitoring. */ 54 #define SRI_MASTER (1<<0) 55 #define SRI_SLAVE (1<<1) 56 #define SRI_SENTINEL (1<<2) 57 #define SRI_DISCONNECTED (1<<3) 58 #define SRI_S_DOWN (1<<4) /* Subjectively down (no quorum). */ 59 #define SRI_O_DOWN (1<<5) /* Objectively down (confirmed by others). */ 60 #define SRI_MASTER_DOWN (1<<6) /* A Sentinel with this flag set thinks that 61 its master is down. */ 62 #define SRI_FAILOVER_IN_PROGRESS (1<<7) /* Failover is in progress for 63 this master. */ 64 #define SRI_PROMOTED (1<<8) /* Slave selected for promotion. */ 65 #define SRI_RECONF_SENT (1<<9) /* SLAVEOF <newmaster> sent. */ 66 #define SRI_RECONF_INPROG (1<<10) /* Slave synchronization in progress. */ 67 #define SRI_RECONF_DONE (1<<11) /* Slave synchronized with new master. */ 68 #define SRI_FORCE_FAILOVER (1<<12) /* Force failover with master up. */ 69 #define SRI_SCRIPT_KILL_SENT (1<<13) /* SCRIPT KILL already sent on -BUSY */ 70 71 /* Note: times are in milliseconds. */ 72 #define SENTINEL_INFO_PERIOD 10000 73 #define SENTINEL_PING_PERIOD 1000 74 #define SENTINEL_ASK_PERIOD 1000 75 #define SENTINEL_PUBLISH_PERIOD 2000 76 #define SENTINEL_DEFAULT_DOWN_AFTER 30000 77 #define SENTINEL_HELLO_CHANNEL "__sentinel__:hello" 78 #define SENTINEL_TILT_TRIGGER 2000 79 #define SENTINEL_TILT_PERIOD (SENTINEL_PING_PERIOD*30) 80 #define SENTINEL_DEFAULT_SLAVE_PRIORITY 100 81 #define SENTINEL_SLAVE_RECONF_TIMEOUT 10000 82 #define SENTINEL_DEFAULT_PARALLEL_SYNCS 1 83 #define SENTINEL_MIN_LINK_RECONNECT_PERIOD 15000 84 #define SENTINEL_DEFAULT_FAILOVER_TIMEOUT (60*3*1000) 85 #define SENTINEL_MAX_PENDING_COMMANDS 100 86 #define SENTINEL_ELECTION_TIMEOUT 10000 87 #define SENTINEL_MAX_DESYNC 1000 88 89 /* Failover machine different states. */ 90 #define SENTINEL_FAILOVER_STATE_NONE 0 /* No failover in progress. */ 91 #define SENTINEL_FAILOVER_STATE_WAIT_START 1 /* Wait for failover_start_time*/ 92 #define SENTINEL_FAILOVER_STATE_SELECT_SLAVE 2 /* Select slave to promote */ 93 #define SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE 3 /* Slave -> Master */ 94 #define SENTINEL_FAILOVER_STATE_WAIT_PROMOTION 4 /* Wait slave to change role */ 95 #define SENTINEL_FAILOVER_STATE_RECONF_SLAVES 5 /* SLAVEOF newmaster */ 96 #define SENTINEL_FAILOVER_STATE_UPDATE_CONFIG 6 /* Monitor promoted slave. */ 97 98 #define SENTINEL_MASTER_LINK_STATUS_UP 0 99 #define SENTINEL_MASTER_LINK_STATUS_DOWN 1 100 101 /* Generic flags that can be used with different functions. 102 * They use higher bits to avoid colliding with the function specific 103 * flags. */ 104 #define SENTINEL_NO_FLAGS 0 105 #define SENTINEL_GENERATE_EVENT (1<<16) 106 #define SENTINEL_LEADER (1<<17) 107 #define SENTINEL_OBSERVER (1<<18) 108 109 /* Script execution flags and limits. */ 110 #define SENTINEL_SCRIPT_NONE 0 111 #define SENTINEL_SCRIPT_RUNNING 1 112 #define SENTINEL_SCRIPT_MAX_QUEUE 256 113 #define SENTINEL_SCRIPT_MAX_RUNNING 16 114 #define SENTINEL_SCRIPT_MAX_RUNTIME 60000 /* 60 seconds max exec time. */ 115 #define SENTINEL_SCRIPT_MAX_RETRY 10 116 #define SENTINEL_SCRIPT_RETRY_DELAY 30000 /* 30 seconds between retries. */ 117 118 typedef struct sentinelRedisInstance { 119 int flags; /* See SRI_... defines */ 120 char *name; /* Master name from the point of view of this sentinel. */ 121 char *runid; /* run ID of this instance. */ 122 uint64_t config_epoch; /* Configuration epoch. */ 123 sentinelAddr *addr; /* Master host. */ 124 redisAsyncContext *cc; /* Hiredis context for commands. */ 125 redisAsyncContext *pc; /* Hiredis context for Pub / Sub. */ 126 int pending_commands; /* Number of commands sent waiting for a reply. */ 127 mstime_t cc_conn_time; /* cc connection time. */ 128 mstime_t pc_conn_time; /* pc connection time. */ 129 mstime_t pc_last_activity; /* Last time we received any message. */ 130 mstime_t last_avail_time; /* Last time the instance replied to ping with 131 a reply we consider valid. */ 132 mstime_t last_ping_time; /* Last time a pending ping was sent in the 133 context of the current command connection 134 with the instance. 0 if still not sent or 135 if pong already received. */ 136 mstime_t last_pong_time; /* Last time the instance replied to ping, 137 whatever the reply was. That's used to check 138 if the link is idle and must be reconnected. */ 139 mstime_t last_pub_time; /* Last time we sent hello via Pub/Sub. */ 140 mstime_t last_hello_time; /* Only used if SRI_SENTINEL is set. Last time 141 we received a hello from this Sentinel 142 via Pub/Sub. */ 143 mstime_t last_master_down_reply_time; /* Time of last reply to 144 SENTINEL is-master-down command. */ 145 mstime_t s_down_since_time; /* Subjectively down since time. */ 146 mstime_t o_down_since_time; /* Objectively down since time. */ 147 mstime_t down_after_period; /* Consider it down after that period. */ 148 mstime_t info_refresh; /* Time at which we received INFO output from it. */ 149 150 /* Role and the first time we observed it. 151 * This is useful in order to delay replacing what the instance reports 152 * with our own configuration. We need to always wait some time in order 153 * to give a chance to the leader to report the new configuration before 154 * we do silly things. */ 155 int role_reported; 156 mstime_t role_reported_time; 157 mstime_t slave_conf_change_time; /* Last time slave master addr changed. */ 158 159 /* Master specific. */ 160 dict *sentinels; /* Other sentinels monitoring the same master. */ 161 dict *slaves; /* Slaves for this master instance. */ 162 int quorum; /* Number of sentinels that need to agree on failure. */ 163 int parallel_syncs; /* How many slaves to reconfigure at same time. */ 164 char *auth_pass; /* Password to use for AUTH against master & slaves. */ 165 166 /* Slave specific. */ 167 mstime_t master_link_down_time; /* Slave replication link down time. */ 168 int slave_priority; /* Slave priority according to its INFO output. */ 169 mstime_t slave_reconf_sent_time; /* Time at which we sent SLAVE OF <new> */ 170 struct sentinelRedisInstance *master; /* Master instance if it's slave. */ 171 char *slave_master_host; /* Master host as reported by INFO */ 172 int slave_master_port; /* Master port as reported by INFO */ 173 int slave_master_link_status; /* Master link status as reported by INFO */ 174 unsigned long long slave_repl_offset; /* Slave replication offset. */ 175 /* Failover */ 176 char *leader; /* If this is a master instance, this is the runid of 177 the Sentinel that should perform the failover. If 178 this is a Sentinel, this is the runid of the Sentinel 179 that this Sentinel voted as leader. */ 180 uint64_t leader_epoch; /* Epoch of the 'leader' field. */ 181 uint64_t failover_epoch; /* Epoch of the currently started failover. */ 182 int failover_state; /* See SENTINEL_FAILOVER_STATE_* defines. */ 183 mstime_t failover_state_change_time; 184 mstime_t failover_start_time; /* Last failover attempt start time. */ 185 mstime_t failover_timeout; /* Max time to refresh failover state. */ 186 mstime_t failover_delay_logged; /* For what failover_start_time value we 187 logged the failover delay. */ 188 struct sentinelRedisInstance *promoted_slave; /* Promoted slave instance. */ 189 /* Scripts executed to notify admin or reconfigure clients: when they 190 * are set to NULL no script is executed. */ 191 char *notification_script; 192 char *client_reconfig_script; 193 } sentinelRedisInstance; 194 195 /* Main state. */ 196 struct sentinelState { 197 uint64_t current_epoch; /* Current epoch. */ 198 dict *masters; /* Dictionary of master sentinelRedisInstances. 199 Key is the instance name, value is the 200 sentinelRedisInstance structure pointer. */ 201 int tilt; /* Are we in TILT mode? */ 202 int running_scripts; /* Number of scripts in execution right now. */ 203 mstime_t tilt_start_time; /* When TITL started. */ 204 mstime_t previous_time; /* Last time we ran the time handler. */ 205 list *scripts_queue; /* Queue of user scripts to execute. */ 206 } sentinel; 207 208 /* A script execution job. */ 209 typedef struct sentinelScriptJob { 210 int flags; /* Script job flags: SENTINEL_SCRIPT_* */ 211 int retry_num; /* Number of times we tried to execute it. */ 212 char **argv; /* Arguments to call the script. */ 213 mstime_t start_time; /* Script execution time if the script is running, 214 otherwise 0 if we are allowed to retry the 215 execution at any time. If the script is not 216 running and it's not 0, it means: do not run 217 before the specified time. */ 218 pid_t pid; /* Script execution pid. */ 219 } sentinelScriptJob; 220 221 /* ======================= hiredis ae.c adapters ============================= 222 * Note: this implementation is taken from hiredis/adapters/ae.h, however 223 * we have our modified copy for Sentinel in order to use our allocator 224 * and to have full control over how the adapter works. */ 225 226 typedef struct redisAeEvents { 227 redisAsyncContext *context; 228 aeEventLoop *loop; 229 int fd; 230 int reading, writing; 231 } redisAeEvents; 232 233 static void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) { 234 ((void)el); ((void)fd); ((void)mask); 235 236 redisAeEvents *e = (redisAeEvents*)privdata; 237 redisAsyncHandleRead(e->context); 238 } 239 240 static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) { 241 ((void)el); ((void)fd); ((void)mask); 242 243 redisAeEvents *e = (redisAeEvents*)privdata; 244 redisAsyncHandleWrite(e->context); 245 } 246 247 static void redisAeAddRead(void *privdata) { 248 redisAeEvents *e = (redisAeEvents*)privdata; 249 aeEventLoop *loop = e->loop; 250 if (!e->reading) { 251 e->reading = 1; 252 aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e); 253 } 254 } 255 256 static void redisAeDelRead(void *privdata) { 257 redisAeEvents *e = (redisAeEvents*)privdata; 258 aeEventLoop *loop = e->loop; 259 if (e->reading) { 260 e->reading = 0; 261 aeDeleteFileEvent(loop,e->fd,AE_READABLE); 262 } 263 } 264 265 static void redisAeAddWrite(void *privdata) { 266 redisAeEvents *e = (redisAeEvents*)privdata; 267 aeEventLoop *loop = e->loop; 268 if (!e->writing) { 269 e->writing = 1; 270 aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redisAeWriteEvent,e); 271 } 272 } 273 274 static void redisAeDelWrite(void *privdata) { 275 redisAeEvents *e = (redisAeEvents*)privdata; 276 aeEventLoop *loop = e->loop; 277 if (e->writing) { 278 e->writing = 0; 279 aeDeleteFileEvent(loop,e->fd,AE_WRITABLE); 280 } 281 } 282 283 static void redisAeCleanup(void *privdata) { 284 redisAeEvents *e = (redisAeEvents*)privdata; 285 redisAeDelRead(privdata); 286 redisAeDelWrite(privdata); 287 zfree(e); 288 } 289 290 static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) { 291 redisContext *c = &(ac->c); 292 redisAeEvents *e; 293 294 /* Nothing should be attached when something is already attached */ 295 if (ac->ev.data != NULL) 296 return REDIS_ERR; 297 298 /* Create container for context and r/w events */ 299 e = (redisAeEvents*)zmalloc(sizeof(*e)); 300 e->context = ac; 301 e->loop = loop; 302 e->fd = c->fd; 303 e->reading = e->writing = 0; 304 305 /* Register functions to start/stop listening for events */ 306 ac->ev.addRead = redisAeAddRead; 307 ac->ev.delRead = redisAeDelRead; 308 ac->ev.addWrite = redisAeAddWrite; 309 ac->ev.delWrite = redisAeDelWrite; 310 ac->ev.cleanup = redisAeCleanup; 311 ac->ev.data = e; 312 313 return REDIS_OK; 314 } 315 316 /* ============================= Prototypes ================================= */ 317 318 void sentinelLinkEstablishedCallback(const redisAsyncContext *c, int status); 319 void sentinelDisconnectCallback(const redisAsyncContext *c, int status); 320 void sentinelReceiveHelloMessages(redisAsyncContext *c, void *reply, void *privdata); 321 sentinelRedisInstance *sentinelGetMasterByName(char *name); 322 char *sentinelGetSubjectiveLeader(sentinelRedisInstance *master); 323 char *sentinelGetObjectiveLeader(sentinelRedisInstance *master); 324 int yesnotoi(char *s); 325 void sentinelDisconnectInstanceFromContext(const redisAsyncContext *c); 326 void sentinelKillLink(sentinelRedisInstance *ri, redisAsyncContext *c); 327 const char *sentinelRedisInstanceTypeStr(sentinelRedisInstance *ri); 328 void sentinelAbortFailover(sentinelRedisInstance *ri); 329 void sentinelEvent(int level, char *type, sentinelRedisInstance *ri, const char *fmt, ...); 330 sentinelRedisInstance *sentinelSelectSlave(sentinelRedisInstance *master); 331 void sentinelScheduleScriptExecution(char *path, ...); 332 void sentinelStartFailover(sentinelRedisInstance *master); 333 void sentinelDiscardReplyCallback(redisAsyncContext *c, void *reply, void *privdata); 334 int sentinelSendSlaveOf(sentinelRedisInstance *ri, char *host, int port); 335 char *sentinelVoteLeader(sentinelRedisInstance *master, uint64_t req_epoch, char *req_runid, uint64_t *leader_epoch); 336 void sentinelFlushConfig(void); 337 void sentinelGenerateInitialMonitorEvents(void); 338 int sentinelSendPing(sentinelRedisInstance *ri); 339 int sentinelForceHelloUpdateForMaster(sentinelRedisInstance *master); 340 341 /* ========================= Dictionary types =============================== */ 342 343 unsigned int dictSdsHash(const void *key); 344 int dictSdsKeyCompare(void *privdata, const void *key1, const void *key2); 345 void releaseSentinelRedisInstance(sentinelRedisInstance *ri); 346 347 void dictInstancesValDestructor (void *privdata, void *obj) { 348 releaseSentinelRedisInstance(obj); 349 } 350 351 /* Instance name (sds) -> instance (sentinelRedisInstance pointer) 352 * 353 * also used for: sentinelRedisInstance->sentinels dictionary that maps 354 * sentinels ip:port to last seen time in Pub/Sub hello message. */ 355 dictType instancesDictType = { 356 dictSdsHash, /* hash function */ 357 NULL, /* key dup */ 358 NULL, /* val dup */ 359 dictSdsKeyCompare, /* key compare */ 360 NULL, /* key destructor */ 361 dictInstancesValDestructor /* val destructor */ 362 }; 363 364 /* Instance runid (sds) -> votes (long casted to void*) 365 * 366 * This is useful into sentinelGetObjectiveLeader() function in order to 367 * count the votes and understand who is the leader. */ 368 dictType leaderVotesDictType = { 369 dictSdsHash, /* hash function */ 370 NULL, /* key dup */ 371 NULL, /* val dup */ 372 dictSdsKeyCompare, /* key compare */ 373 NULL, /* key destructor */ 374 NULL /* val destructor */ 375 }; 376 377 /* =========================== Initialization =============================== */ 378 379 void sentinelCommand(redisClient *c); 380 void sentinelInfoCommand(redisClient *c); 381 void sentinelSetCommand(redisClient *c); 382 void sentinelPublishCommand(redisClient *c); 383 384 struct redisCommand sentinelcmds[] = { 385 {"ping",pingCommand,1,"",0,NULL,0,0,0,0,0}, 386 {"sentinel",sentinelCommand,-2,"",0,NULL,0,0,0,0,0}, 387 {"subscribe",subscribeCommand,-2,"",0,NULL,0,0,0,0,0}, 388 {"unsubscribe",unsubscribeCommand,-1,"",0,NULL,0,0,0,0,0}, 389 {"psubscribe",psubscribeCommand,-2,"",0,NULL,0,0,0,0,0}, 390 {"punsubscribe",punsubscribeCommand,-1,"",0,NULL,0,0,0,0,0}, 391 {"publish",sentinelPublishCommand,3,"",0,NULL,0,0,0,0,0}, 392 {"info",sentinelInfoCommand,-1,"",0,NULL,0,0,0,0,0}, 393 {"shutdown",shutdownCommand,-1,"",0,NULL,0,0,0,0,0} 394 }; 395 396 /* This function overwrites a few normal Redis config default with Sentinel 397 * specific defaults. */ 398 void initSentinelConfig(void) { 399 server.port = REDIS_SENTINEL_PORT; 400 } 401 402 /* Perform the Sentinel mode initialization. */ 403 void initSentinel(void) { 404 int j; 405 406 /* Remove usual Redis commands from the command table, then just add 407 * the SENTINEL command. */ 408 dictEmpty(server.commands,NULL); 409 for (j = 0; j < sizeof(sentinelcmds)/sizeof(sentinelcmds[0]); j++) { 410 int retval; 411 struct redisCommand *cmd = sentinelcmds+j; 412 413 retval = dictAdd(server.commands, sdsnew(cmd->name), cmd); 414 redisAssert(retval == DICT_OK); 415 } 416 417 /* Initialize various data structures. */ 418 sentinel.current_epoch = 0; 419 sentinel.masters = dictCreate(&instancesDictType,NULL); 420 sentinel.tilt = 0; 421 sentinel.tilt_start_time = 0; 422 sentinel.previous_time = mstime(); 423 sentinel.running_scripts = 0; 424 sentinel.scripts_queue = listCreate(); 425 } 426 427 /* This function gets called when the server is in Sentinel mode, started, 428 * loaded the configuration, and is ready for normal operations. */ 429 void sentinelIsRunning(void) { 430 redisLog(REDIS_WARNING,"Sentinel runid is %s", server.runid); 431 432 if (server.configfile == NULL) { 433 redisLog(REDIS_WARNING, 434 "Sentinel started without a config file. Exiting..."); 435 exit(1); 436 } else if (access(server.configfile,W_OK) == -1) { 437 redisLog(REDIS_WARNING, 438 "Sentinel config file %s is not writable: %s. Exiting...", 439 server.configfile,strerror(errno)); 440 exit(1); 441 } 442 443 /* We want to generate a +monitor event for every configured master 444 * at startup. */ 445 sentinelGenerateInitialMonitorEvents(); 446 } 447 448 /* ============================== sentinelAddr ============================== */ 449 450 /* Create a sentinelAddr object and return it on success. 451 * On error NULL is returned and errno is set to: 452 * ENOENT: Can't resolve the hostname. 453 * EINVAL: Invalid port number. 454 */ 455 sentinelAddr *createSentinelAddr(char *hostname, int port) { 456 char buf[32]; 457 sentinelAddr *sa; 458 459 if (port <= 0 || port > 65535) { 460 errno = EINVAL; 461 return NULL; 462 } 463 if (anetResolve(NULL,hostname,buf,sizeof(buf)) == ANET_ERR) { 464 errno = ENOENT; 465 return NULL; 466 } 467 sa = zmalloc(sizeof(*sa)); 468 sa->ip = sdsnew(buf); 469 sa->port = port; 470 return sa; 471 } 472 473 /* Return a duplicate of the source address. */ 474 sentinelAddr *dupSentinelAddr(sentinelAddr *src) { 475 sentinelAddr *sa; 476 477 sa = zmalloc(sizeof(*sa)); 478 sa->ip = sdsnew(src->ip); 479 sa->port = src->port; 480 return sa; 481 } 482 483 /* Free a Sentinel address. Can't fail. */ 484 void releaseSentinelAddr(sentinelAddr *sa) { 485 sdsfree(sa->ip); 486 zfree(sa); 487 } 488 489 /* Return non-zero if two addresses are equal. */ 490 int sentinelAddrIsEqual(sentinelAddr *a, sentinelAddr *b) { 491 return a->port == b->port && !strcasecmp(a->ip,b->ip); 492 } 493 494 /* =========================== Events notification ========================== */ 495 496 /* Send an event to log, pub/sub, user notification script. 497 * 498 * 'level' is the log level for logging. Only REDIS_WARNING events will trigger 499 * the execution of the user notification script. 500 * 501 * 'type' is the message type, also used as a pub/sub channel name. 502 * 503 * 'ri', is the redis instance target of this event if applicable, and is 504 * used to obtain the path of the notification script to execute. 505 * 506 * The remaining arguments are printf-alike. 507 * If the format specifier starts with the two characters "%@" then ri is 508 * not NULL, and the message is prefixed with an instance identifier in the 509 * following format: 510 * 511 * <instance type> <instance name> <ip> <port> 512 * 513 * If the instance type is not master, than the additional string is 514 * added to specify the originating master: 515 * 516 * @ <master name> <master ip> <master port> 517 * 518 * Any other specifier after "%@" is processed by printf itself. 519 */ 520 void sentinelEvent(int level, char *type, sentinelRedisInstance *ri, 521 const char *fmt, ...) { 522 va_list ap; 523 char msg[REDIS_MAX_LOGMSG_LEN]; 524 robj *channel, *payload; 525 526 /* Handle %@ */ 527 if (fmt[0] == '%' && fmt[1] == '@') { 528 sentinelRedisInstance *master = (ri->flags & SRI_MASTER) ? 529 NULL : ri->master; 530 531 if (master) { 532 snprintf(msg, sizeof(msg), "%s %s %s %d @ %s %s %d", 533 sentinelRedisInstanceTypeStr(ri), 534 ri->name, ri->addr->ip, ri->addr->port, 535 master->name, master->addr->ip, master->addr->port); 536 } else { 537 snprintf(msg, sizeof(msg), "%s %s %s %d", 538 sentinelRedisInstanceTypeStr(ri), 539 ri->name, ri->addr->ip, ri->addr->port); 540 } 541 fmt += 2; 542 } else { 543 msg[0] = '\0'; 544 } 545 546 /* Use vsprintf for the rest of the formatting if any. */ 547 if (fmt[0] != '\0') { 548 va_start(ap, fmt); 549 vsnprintf(msg+strlen(msg), sizeof(msg)-strlen(msg), fmt, ap); 550 va_end(ap); 551 } 552 553 /* Log the message if the log level allows it to be logged. */ 554 if (level >= server.verbosity) 555 redisLog(level,"%s %s",type,msg); 556 557 /* Publish the message via Pub/Sub if it's not a debugging one. */ 558 if (level != REDIS_DEBUG) { 559 channel = createStringObject(type,strlen(type)); 560 payload = createStringObject(msg,strlen(msg)); 561 pubsubPublishMessage(channel,payload); 562 decrRefCount(channel); 563 decrRefCount(payload); 564 } 565 566 /* Call the notification script if applicable. */ 567 if (level == REDIS_WARNING && ri != NULL) { 568 sentinelRedisInstance *master = (ri->flags & SRI_MASTER) ? 569 ri : ri->master; 570 if (master->notification_script) { 571 sentinelScheduleScriptExecution(master->notification_script, 572 type,msg,NULL); 573 } 574 } 575 } 576 577 /* This function is called only at startup and is used to generate a 578 * +monitor event for every configured master. The same events are also 579 * generated when a master to monitor is added at runtime via the 580 * SENTINEL MONITOR command. */ 581 void sentinelGenerateInitialMonitorEvents(void) { 582 dictIterator *di; 583 dictEntry *de; 584 585 di = dictGetIterator(sentinel.masters); 586 while((de = dictNext(di)) != NULL) { 587 sentinelRedisInstance *ri = dictGetVal(de); 588 sentinelEvent(REDIS_WARNING,"+monitor",ri,"%@ quorum %d",ri->quorum); 589 } 590 dictReleaseIterator(di); 591 } 592 593 /* ============================ script execution ============================ */ 594 595 /* Release a script job structure and all the associated data. */ 596 void sentinelReleaseScriptJob(sentinelScriptJob *sj) { 597 int j = 0; 598 599 while(sj->argv[j]) sdsfree(sj->argv[j++]); 600 zfree(sj->argv); 601 zfree(sj); 602 } 603 604 #define SENTINEL_SCRIPT_MAX_ARGS 16 605 void sentinelScheduleScriptExecution(char *path, ...) { 606 va_list ap; 607 char *argv[SENTINEL_SCRIPT_MAX_ARGS+1]; 608 int argc = 1; 609 sentinelScriptJob *sj; 610 611 va_start(ap, path); 612 while(argc < SENTINEL_SCRIPT_MAX_ARGS) { 613 argv[argc] = va_arg(ap,char*); 614 if (!argv[argc]) break; 615 argv[argc] = sdsnew(argv[argc]); /* Copy the string. */ 616 argc++; 617 } 618 va_end(ap); 619 argv[0] = sdsnew(path); 620 621 sj = zmalloc(sizeof(*sj)); 622 sj->flags = SENTINEL_SCRIPT_NONE; 623 sj->retry_num = 0; 624 sj->argv = zmalloc(sizeof(char*)*(argc+1)); 625 sj->start_time = 0; 626 sj->pid = 0; 627 memcpy(sj->argv,argv,sizeof(char*)*(argc+1)); 628 629 listAddNodeTail(sentinel.scripts_queue,sj); 630 631 /* Remove the oldest non running script if we already hit the limit. */ 632 if (listLength(sentinel.scripts_queue) > SENTINEL_SCRIPT_MAX_QUEUE) { 633 listNode *ln; 634 listIter li; 635 636 listRewind(sentinel.scripts_queue,&li); 637 while ((ln = listNext(&li)) != NULL) { 638 sj = ln->value; 639 640 if (sj->flags & SENTINEL_SCRIPT_RUNNING) continue; 641 /* The first node is the oldest as we add on tail. */ 642 listDelNode(sentinel.scripts_queue,ln); 643 sentinelReleaseScriptJob(sj); 644 break; 645 } 646 redisAssert(listLength(sentinel.scripts_queue) <= 647 SENTINEL_SCRIPT_MAX_QUEUE); 648 } 649 } 650 651 /* Lookup a script in the scripts queue via pid, and returns the list node 652 * (so that we can easily remove it from the queue if needed). */ 653 listNode *sentinelGetScriptListNodeByPid(pid_t pid) { 654 listNode *ln; 655 listIter li; 656 657 listRewind(sentinel.scripts_queue,&li); 658 while ((ln = listNext(&li)) != NULL) { 659 sentinelScriptJob *sj = ln->value; 660 661 if ((sj->flags & SENTINEL_SCRIPT_RUNNING) && sj->pid == pid) 662 return ln; 663 } 664 return NULL; 665 } 666 667 /* Run pending scripts if we are not already at max number of running 668 * scripts. */ 669 void sentinelRunPendingScripts(void) { 670 listNode *ln; 671 listIter li; 672 mstime_t now = mstime(); 673 674 /* Find jobs that are not running and run them, from the top to the 675 * tail of the queue, so we run older jobs first. */ 676 listRewind(sentinel.scripts_queue,&li); 677 while (sentinel.running_scripts < SENTINEL_SCRIPT_MAX_RUNNING && 678 (ln = listNext(&li)) != NULL) 679 { 680 sentinelScriptJob *sj = ln->value; 681 pid_t pid; 682 683 /* Skip if already running. */ 684 if (sj->flags & SENTINEL_SCRIPT_RUNNING) continue; 685 686 /* Skip if it's a retry, but not enough time has elapsed. */ 687 if (sj->start_time && sj->start_time > now) continue; 688 689 sj->flags |= SENTINEL_SCRIPT_RUNNING; 690 sj->start_time = mstime(); 691 sj->retry_num++; 692 pid = fork(); 693 694 if (pid == -1) { 695 /* Parent (fork error). 696 * We report fork errors as signal 99, in order to unify the 697 * reporting with other kind of errors. */ 698 sentinelEvent(REDIS_WARNING,"-script-error",NULL, 699 "%s %d %d", sj->argv[0], 99, 0); 700 sj->flags &= ~SENTINEL_SCRIPT_RUNNING; 701 sj->pid = 0; 702 } else if (pid == 0) { 703 /* Child */ 704 execve(sj->argv[0],sj->argv,environ); 705 /* If we are here an error occurred. */ 706 _exit(2); /* Don't retry execution. */ 707 } else { 708 sentinel.running_scripts++; 709 sj->pid = pid; 710 sentinelEvent(REDIS_DEBUG,"+script-child",NULL,"%ld",(long)pid); 711 } 712 } 713 } 714 715 /* How much to delay the execution of a script that we need to retry after 716 * an error? 717 * 718 * We double the retry delay for every further retry we do. So for instance 719 * if RETRY_DELAY is set to 30 seconds and the max number of retries is 10 720 * starting from the second attempt to execute the script the delays are: 721 * 30 sec, 60 sec, 2 min, 4 min, 8 min, 16 min, 32 min, 64 min, 128 min. */ 722 mstime_t sentinelScriptRetryDelay(int retry_num) { 723 mstime_t delay = SENTINEL_SCRIPT_RETRY_DELAY; 724 725 while (retry_num-- > 1) delay *= 2; 726 return delay; 727 } 728 729 /* Check for scripts that terminated, and remove them from the queue if the 730 * script terminated successfully. If instead the script was terminated by 731 * a signal, or returned exit code "1", it is scheduled to run again if 732 * the max number of retries did not already elapsed. */ 733 void sentinelCollectTerminatedScripts(void) { 734 int statloc; 735 pid_t pid; 736 737 while ((pid = wait3(&statloc,WNOHANG,NULL)) > 0) { 738 int exitcode = WEXITSTATUS(statloc); 739 int bysignal = 0; 740 listNode *ln; 741 sentinelScriptJob *sj; 742 743 if (WIFSIGNALED(statloc)) bysignal = WTERMSIG(statloc); 744 sentinelEvent(REDIS_DEBUG,"-script-child",NULL,"%ld %d %d", 745 (long)pid, exitcode, bysignal); 746 747 ln = sentinelGetScriptListNodeByPid(pid); 748 if (ln == NULL) { 749 redisLog(REDIS_WARNING,"wait3() returned a pid (%ld) we can't find in our scripts execution queue!", (long)pid); 750 continue; 751 } 752 sj = ln->value; 753 754 /* If the script was terminated by a signal or returns an 755 * exit code of "1" (that means: please retry), we reschedule it 756 * if the max number of retries is not already reached. */ 757 if ((bysignal || exitcode == 1) && 758 sj->retry_num != SENTINEL_SCRIPT_MAX_RETRY) 759 { 760 sj->flags &= ~SENTINEL_SCRIPT_RUNNING; 761 sj->pid = 0; 762 sj->start_time = mstime() + 763 sentinelScriptRetryDelay(sj->retry_num); 764 } else { 765 /* Otherwise let's remove the script, but log the event if the 766 * execution did not terminated in the best of the ways. */ 767 if (bysignal || exitcode != 0) { 768 sentinelEvent(REDIS_WARNING,"-script-error",NULL, 769 "%s %d %d", sj->argv[0], bysignal, exitcode); 770 } 771 listDelNode(sentinel.scripts_queue,ln); 772 sentinelReleaseScriptJob(sj); 773 sentinel.running_scripts--; 774 } 775 } 776 } 777 778 /* Kill scripts in timeout, they'll be collected by the 779 * sentinelCollectTerminatedScripts() function. */ 780 void sentinelKillTimedoutScripts(void) { 781 listNode *ln; 782 listIter li; 783 mstime_t now = mstime(); 784 785 listRewind(sentinel.scripts_queue,&li); 786 while ((ln = listNext(&li)) != NULL) { 787 sentinelScriptJob *sj = ln->value; 788 789 if (sj->flags & SENTINEL_SCRIPT_RUNNING && 790 (now - sj->start_time) > SENTINEL_SCRIPT_MAX_RUNTIME) 791 { 792 sentinelEvent(REDIS_WARNING,"-script-timeout",NULL,"%s %ld", 793 sj->argv[0], (long)sj->pid); 794 kill(sj->pid,SIGKILL); 795 } 796 } 797 } 798 799 /* Implements SENTINEL PENDING-SCRIPTS command. */ 800 void sentinelPendingScriptsCommand(redisClient *c) { 801 listNode *ln; 802 listIter li; 803 804 addReplyMultiBulkLen(c,listLength(sentinel.scripts_queue)); 805 listRewind(sentinel.scripts_queue,&li); 806 while ((ln = listNext(&li)) != NULL) { 807 sentinelScriptJob *sj = ln->value; 808 int j = 0; 809 810 addReplyMultiBulkLen(c,10); 811 812 addReplyBulkCString(c,"argv"); 813 while (sj->argv[j]) j++; 814 addReplyMultiBulkLen(c,j); 815 j = 0; 816 while (sj->argv[j]) addReplyBulkCString(c,sj->argv[j++]); 817 818 addReplyBulkCString(c,"flags"); 819 addReplyBulkCString(c, 820 (sj->flags & SENTINEL_SCRIPT_RUNNING) ? "running" : "scheduled"); 821 822 addReplyBulkCString(c,"pid"); 823 addReplyBulkLongLong(c,sj->pid); 824 825 if (sj->flags & SENTINEL_SCRIPT_RUNNING) { 826 addReplyBulkCString(c,"run-time"); 827 addReplyBulkLongLong(c,mstime() - sj->start_time); 828 } else { 829 mstime_t delay = sj->start_time ? (sj->start_time-mstime()) : 0; 830 if (delay < 0) delay = 0; 831 addReplyBulkCString(c,"run-delay"); 832 addReplyBulkLongLong(c,delay); 833 } 834 835 addReplyBulkCString(c,"retry-num"); 836 addReplyBulkLongLong(c,sj->retry_num); 837 } 838 } 839 840 /* This function calls, if any, the client reconfiguration script with the 841 * following parameters: 842 * 843 * <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port> 844 * 845 * It is called every time a failover is performed. 846 * 847 * <state> is currently always "failover". 848 * <role> is either "leader" or "observer". 849 * 850 * from/to fields are respectively master -> promoted slave addresses for 851 * "start" and "end". */ 852 void sentinelCallClientReconfScript(sentinelRedisInstance *master, int role, char *state, sentinelAddr *from, sentinelAddr *to) { 853 char fromport[32], toport[32]; 854 855 if (master->client_reconfig_script == NULL) return; 856 ll2string(fromport,sizeof(fromport),from->port); 857 ll2string(toport,sizeof(toport),to->port); 858 sentinelScheduleScriptExecution(master->client_reconfig_script, 859 master->name, 860 (role == SENTINEL_LEADER) ? "leader" : "observer", 861 state, from->ip, fromport, to->ip, toport, NULL); 862 } 863 864 /* ========================== sentinelRedisInstance ========================= */ 865 866 /* Create a redis instance, the following fields must be populated by the 867 * caller if needed: 868 * runid: set to NULL but will be populated once INFO output is received. 869 * info_refresh: is set to 0 to mean that we never received INFO so far. 870 * 871 * If SRI_MASTER is set into initial flags the instance is added to 872 * sentinel.masters table. 873 * 874 * if SRI_SLAVE or SRI_SENTINEL is set then 'master' must be not NULL and the 875 * instance is added into master->slaves or master->sentinels table. 876 * 877 * If the instance is a slave or sentinel, the name parameter is ignored and 878 * is created automatically as hostname:port. 879 * 880 * The function fails if hostname can't be resolved or port is out of range. 881 * When this happens NULL is returned and errno is set accordingly to the 882 * createSentinelAddr() function. 883 * 884 * The function may also fail and return NULL with errno set to EBUSY if 885 * a master or slave with the same name already exists. */ 886 sentinelRedisInstance *createSentinelRedisInstance(char *name, int flags, char *hostname, int port, int quorum, sentinelRedisInstance *master) { 887 sentinelRedisInstance *ri; 888 sentinelAddr *addr; 889 dict *table = NULL; 890 char slavename[128], *sdsname; 891 892 redisAssert(flags & (SRI_MASTER|SRI_SLAVE|SRI_SENTINEL)); 893 redisAssert((flags & SRI_MASTER) || master != NULL); 894 895 /* Check address validity. */ 896 addr = createSentinelAddr(hostname,port); 897 if (addr == NULL) return NULL; 898 899 /* For slaves and sentinel we use ip:port as name. */ 900 if (flags & (SRI_SLAVE|SRI_SENTINEL)) { 901 snprintf(slavename,sizeof(slavename), 902 strchr(hostname,':') ? "[%s]:%d" : "%s:%d", 903 hostname,port); 904 name = slavename; 905 } 906 907 /* Make sure the entry is not duplicated. This may happen when the same 908 * name for a master is used multiple times inside the configuration or 909 * if we try to add multiple times a slave or sentinel with same ip/port 910 * to a master. */ 911 if (flags & SRI_MASTER) table = sentinel.masters; 912 else if (flags & SRI_SLAVE) table = master->slaves; 913 else if (flags & SRI_SENTINEL) table = master->sentinels; 914 sdsname = sdsnew(name); 915 if (dictFind(table,sdsname)) { 916 sdsfree(sdsname); 917 errno = EBUSY; 918 return NULL; 919 } 920 921 /* Create the instance object. */ 922 ri = zmalloc(sizeof(*ri)); 923 /* Note that all the instances are started in the disconnected state, 924 * the event loop will take care of connecting them. */ 925 ri->flags = flags | SRI_DISCONNECTED; 926 ri->name = sdsname; 927 ri->runid = NULL; 928 ri->config_epoch = 0; 929 ri->addr = addr; 930 ri->cc = NULL; 931 ri->pc = NULL; 932 ri->pending_commands = 0; 933 ri->cc_conn_time = 0; 934 ri->pc_conn_time = 0; 935 ri->pc_last_activity = 0; 936 /* We set the last_ping_time to "now" even if we actually don't have yet 937 * a connection with the node, nor we sent a ping. 938 * This is useful to detect a timeout in case we'll not be able to connect 939 * with the node at all. */ 940 ri->last_ping_time = mstime(); 941 ri->last_avail_time = mstime(); 942 ri->last_pong_time = mstime(); 943 ri->last_pub_time = mstime(); 944 ri->last_hello_time = mstime(); 945 ri->last_master_down_reply_time = mstime(); 946 ri->s_down_since_time = 0; 947 ri->o_down_since_time = 0; 948 ri->down_after_period = master ? master->down_after_period : 949 SENTINEL_DEFAULT_DOWN_AFTER; 950 ri->master_link_down_time = 0; 951 ri->auth_pass = NULL; 952 ri->slave_priority = SENTINEL_DEFAULT_SLAVE_PRIORITY; 953 ri->slave_reconf_sent_time = 0; 954 ri->slave_master_host = NULL; 955 ri->slave_master_port = 0; 956 ri->slave_master_link_status = SENTINEL_MASTER_LINK_STATUS_DOWN; 957 ri->slave_repl_offset = 0; 958 ri->sentinels = dictCreate(&instancesDictType,NULL); 959 ri->quorum = quorum; 960 ri->parallel_syncs = SENTINEL_DEFAULT_PARALLEL_SYNCS; 961 ri->master = master; 962 ri->slaves = dictCreate(&instancesDictType,NULL); 963 ri->info_refresh = 0; 964 965 /* Failover state. */ 966 ri->leader = NULL; 967 ri->leader_epoch = 0; 968 ri->failover_epoch = 0; 969 ri->failover_state = SENTINEL_FAILOVER_STATE_NONE; 970 ri->failover_state_change_time = 0; 971 ri->failover_start_time = 0; 972 ri->failover_timeout = SENTINEL_DEFAULT_FAILOVER_TIMEOUT; 973 ri->failover_delay_logged = 0; 974 ri->promoted_slave = NULL; 975 ri->notification_script = NULL; 976 ri->client_reconfig_script = NULL; 977 978 /* Role */ 979 ri->role_reported = ri->flags & (SRI_MASTER|SRI_SLAVE); 980 ri->role_reported_time = mstime(); 981 ri->slave_conf_change_time = mstime(); 982 983 /* Add into the right table. */ 984 dictAdd(table, ri->name, ri); 985 return ri; 986 } 987 988 /* Release this instance and all its slaves, sentinels, hiredis connections. 989 * This function does not take care of unlinking the instance from the main 990 * masters table (if it is a master) or from its master sentinels/slaves table 991 * if it is a slave or sentinel. */ 992 void releaseSentinelRedisInstance(sentinelRedisInstance *ri) { 993 /* Release all its slaves or sentinels if any. */ 994 dictRelease(ri->sentinels); 995 dictRelease(ri->slaves); 996 997 /* Release hiredis connections. */ 998 if (ri->cc) sentinelKillLink(ri,ri->cc); 999 if (ri->pc) sentinelKillLink(ri,ri->pc); 1000 1001 /* Free other resources. */ 1002 sdsfree(ri->name); 1003 sdsfree(ri->runid); 1004 sdsfree(ri->notification_script); 1005 sdsfree(ri->client_reconfig_script); 1006 sdsfree(ri->slave_master_host); 1007 sdsfree(ri->leader); 1008 sdsfree(ri->auth_pass); 1009 releaseSentinelAddr(ri->addr); 1010 1011 /* Clear state into the master if needed. */ 1012 if ((ri->flags & SRI_SLAVE) && (ri->flags & SRI_PROMOTED) && ri->master) 1013 ri->master->promoted_slave = NULL; 1014 1015 zfree(ri); 1016 } 1017 1018 /* Lookup a slave in a master Redis instance, by ip and port. */ 1019 sentinelRedisInstance *sentinelRedisInstanceLookupSlave( 1020 sentinelRedisInstance *ri, char *ip, int port) 1021 { 1022 sds key; 1023 sentinelRedisInstance *slave; 1024 1025 redisAssert(ri->flags & SRI_MASTER); 1026 key = sdscatprintf(sdsempty(), 1027 strchr(ip,':') ? "[%s]:%d" : "%s:%d", 1028 ip,port); 1029 slave = dictFetchValue(ri->slaves,key); 1030 sdsfree(key); 1031 return slave; 1032 } 1033 1034 /* Return the name of the type of the instance as a string. */ 1035 const char *sentinelRedisInstanceTypeStr(sentinelRedisInstance *ri) { 1036 if (ri->flags & SRI_MASTER) return "master"; 1037 else if (ri->flags & SRI_SLAVE) return "slave"; 1038 else if (ri->flags & SRI_SENTINEL) return "sentinel"; 1039 else return "unknown"; 1040 } 1041 1042 /* This function removes all the instances found in the dictionary of 1043 * sentinels in the specified 'master', having either: 1044 * 1045 * 1) The same ip/port as specified. 1046 * 2) The same runid. 1047 * 1048 * "1" and "2" don't need to verify at the same time, just one is enough. 1049 * If "runid" is NULL it is not checked. 1050 * Similarly if "ip" is NULL it is not checked. 1051 * 1052 * This function is useful because every time we add a new Sentinel into 1053 * a master's Sentinels dictionary, we want to be very sure about not 1054 * having duplicated instances for any reason. This is important because 1055 * other sentinels are needed to reach ODOWN quorum, and later to get 1056 * voted for a given configuration epoch in order to perform the failover. 1057 * 1058 * The function returns the number of Sentinels removed. */ 1059 int removeMatchingSentinelsFromMaster(sentinelRedisInstance *master, char *ip, int port, char *runid) { 1060 dictIterator *di; 1061 dictEntry *de; 1062 int removed = 0; 1063 1064 di = dictGetSafeIterator(master->sentinels); 1065 while((de = dictNext(di)) != NULL) { 1066 sentinelRedisInstance *ri = dictGetVal(de); 1067 1068 if ((ri->runid && runid && strcmp(ri->runid,runid) == 0) || 1069 (ip && strcmp(ri->addr->ip,ip) == 0 && port == ri->addr->port)) 1070 { 1071 dictDelete(master->sentinels,ri->name); 1072 removed++; 1073 } 1074 } 1075 dictReleaseIterator(di); 1076 return removed; 1077 } 1078 1079 /* Search an instance with the same runid, ip and port into a dictionary 1080 * of instances. Return NULL if not found, otherwise return the instance 1081 * pointer. 1082 * 1083 * runid or ip can be NULL. In such a case the search is performed only 1084 * by the non-NULL field. */ 1085 sentinelRedisInstance *getSentinelRedisInstanceByAddrAndRunID(dict *instances, char *ip, int port, char *runid) { 1086 dictIterator *di; 1087 dictEntry *de; 1088 sentinelRedisInstance *instance = NULL; 1089 1090 redisAssert(ip || runid); /* User must pass at least one search param. */ 1091 di = dictGetIterator(instances); 1092 while((de = dictNext(di)) != NULL) { 1093 sentinelRedisInstance *ri = dictGetVal(de); 1094 1095 if (runid && !ri->runid) continue; 1096 if ((runid == NULL || strcmp(ri->runid, runid) == 0) && 1097 (ip == NULL || (strcmp(ri->addr->ip, ip) == 0 && 1098 ri->addr->port == port))) 1099 { 1100 instance = ri; 1101 break; 1102 } 1103 } 1104 dictReleaseIterator(di); 1105 return instance; 1106 } 1107 1108 /* Master lookup by name */ 1109 sentinelRedisInstance *sentinelGetMasterByName(char *name) { 1110 sentinelRedisInstance *ri; 1111 sds sdsname = sdsnew(name); 1112 1113 ri = dictFetchValue(sentinel.masters,sdsname); 1114 sdsfree(sdsname); 1115 return ri; 1116 } 1117 1118 /* Add the specified flags to all the instances in the specified dictionary. */ 1119 void sentinelAddFlagsToDictOfRedisInstances(dict *instances, int flags) { 1120 dictIterator *di; 1121 dictEntry *de; 1122 1123 di = dictGetIterator(instances); 1124 while((de = dictNext(di)) != NULL) { 1125 sentinelRedisInstance *ri = dictGetVal(de); 1126 ri->flags |= flags; 1127 } 1128 dictReleaseIterator(di); 1129 } 1130 1131 /* Remove the specified flags to all the instances in the specified 1132 * dictionary. */ 1133 void sentinelDelFlagsToDictOfRedisInstances(dict *instances, int flags) { 1134 dictIterator *di; 1135 dictEntry *de; 1136 1137 di = dictGetIterator(instances); 1138 while((de = dictNext(di)) != NULL) { 1139 sentinelRedisInstance *ri = dictGetVal(de); 1140 ri->flags &= ~flags; 1141 } 1142 dictReleaseIterator(di); 1143 } 1144 1145 /* Reset the state of a monitored master: 1146 * 1) Remove all slaves. 1147 * 2) Remove all sentinels. 1148 * 3) Remove most of the flags resulting from runtime operations. 1149 * 4) Reset timers to their default value. 1150 * 5) In the process of doing this undo the failover if in progress. 1151 * 6) Disconnect the connections with the master (will reconnect automatically). 1152 */ 1153 1154 #define SENTINEL_RESET_NO_SENTINELS (1<<0) 1155 void sentinelResetMaster(sentinelRedisInstance *ri, int flags) { 1156 redisAssert(ri->flags & SRI_MASTER); 1157 dictRelease(ri->slaves); 1158 ri->slaves = dictCreate(&instancesDictType,NULL); 1159 if (!(flags & SENTINEL_RESET_NO_SENTINELS)) { 1160 dictRelease(ri->sentinels); 1161 ri->sentinels = dictCreate(&instancesDictType,NULL); 1162 } 1163 if (ri->cc) sentinelKillLink(ri,ri->cc); 1164 if (ri->pc) sentinelKillLink(ri,ri->pc); 1165 ri->flags &= SRI_MASTER|SRI_DISCONNECTED; 1166 if (ri->leader) { 1167 sdsfree(ri->leader); 1168 ri->leader = NULL; 1169 } 1170 ri->failover_state = SENTINEL_FAILOVER_STATE_NONE; 1171 ri->failover_state_change_time = 0; 1172 ri->failover_start_time = 0; 1173 ri->promoted_slave = NULL; 1174 sdsfree(ri->runid); 1175 sdsfree(ri->slave_master_host); 1176 ri->runid = NULL; 1177 ri->slave_master_host = NULL; 1178 ri->last_ping_time = mstime(); 1179 ri->last_avail_time = mstime(); 1180 ri->last_pong_time = mstime(); 1181 ri->role_reported_time = mstime(); 1182 ri->role_reported = SRI_MASTER; 1183 if (flags & SENTINEL_GENERATE_EVENT) 1184 sentinelEvent(REDIS_WARNING,"+reset-master",ri,"%@"); 1185 } 1186 1187 /* Call sentinelResetMaster() on every master with a name matching the specified 1188 * pattern. */ 1189 int sentinelResetMastersByPattern(char *pattern, int flags) { 1190 dictIterator *di; 1191 dictEntry *de; 1192 int reset = 0; 1193 1194 di = dictGetIterator(sentinel.masters); 1195 while((de = dictNext(di)) != NULL) { 1196 sentinelRedisInstance *ri = dictGetVal(de); 1197 1198 if (ri->name) { 1199 if (stringmatch(pattern,ri->name,0)) { 1200 sentinelResetMaster(ri,flags); 1201 reset++; 1202 } 1203 } 1204 } 1205 dictReleaseIterator(di); 1206 return reset; 1207 } 1208 1209 /* Reset the specified master with sentinelResetMaster(), and also change 1210 * the ip:port address, but take the name of the instance unmodified. 1211 * 1212 * This is used to handle the +switch-master event. 1213 * 1214 * The function returns REDIS_ERR if the address can't be resolved for some 1215 * reason. Otherwise REDIS_OK is returned. */ 1216 int sentinelResetMasterAndChangeAddress(sentinelRedisInstance *master, char *ip, int port) { 1217 sentinelAddr *oldaddr, *newaddr; 1218 sentinelAddr **slaves = NULL; 1219 int numslaves = 0, j; 1220 dictIterator *di; 1221 dictEntry *de; 1222 1223 newaddr = createSentinelAddr(ip,port); 1224 if (newaddr == NULL) return REDIS_ERR; 1225 1226 /* Make a list of slaves to add back after the reset. 1227 * Don't include the one having the address we are switching to. */ 1228 di = dictGetIterator(master->slaves); 1229 while((de = dictNext(di)) != NULL) { 1230 sentinelRedisInstance *slave = dictGetVal(de); 1231 1232 if (sentinelAddrIsEqual(slave->addr,newaddr)) continue; 1233 slaves = zrealloc(slaves,sizeof(sentinelAddr*)*(numslaves+1)); 1234 slaves[numslaves++] = createSentinelAddr(slave->addr->ip, 1235 slave->addr->port); 1236 } 1237 dictReleaseIterator(di); 1238 1239 /* If we are switching to a different address, include the old address 1240 * as a slave as well, so that we'll be able to sense / reconfigure 1241 * the old master. */ 1242 if (!sentinelAddrIsEqual(newaddr,master->addr)) { 1243 slaves = zrealloc(slaves,sizeof(sentinelAddr*)*(numslaves+1)); 1244 slaves[numslaves++] = createSentinelAddr(master->addr->ip, 1245 master->addr->port); 1246 } 1247 1248 /* Reset and switch address. */ 1249 sentinelResetMaster(master,SENTINEL_RESET_NO_SENTINELS); 1250 oldaddr = master->addr; 1251 master->addr = newaddr; 1252 master->o_down_since_time = 0; 1253 master->s_down_since_time = 0; 1254 1255 /* Add slaves back. */ 1256 for (j = 0; j < numslaves; j++) { 1257 sentinelRedisInstance *slave; 1258 1259 slave = createSentinelRedisInstance(NULL,SRI_SLAVE,slaves[j]->ip, 1260 slaves[j]->port, master->quorum, master); 1261 releaseSentinelAddr(slaves[j]); 1262 if (slave) { 1263 sentinelEvent(REDIS_NOTICE,"+slave",slave,"%@"); 1264 sentinelFlushConfig(); 1265 } 1266 } 1267 zfree(slaves); 1268 1269 /* Release the old address at the end so we are safe even if the function 1270 * gets the master->addr->ip and master->addr->port as arguments. */ 1271 releaseSentinelAddr(oldaddr); 1272 sentinelFlushConfig(); 1273 return REDIS_OK; 1274 } 1275 1276 /* Return non-zero if there was no SDOWN or ODOWN error associated to this 1277 * instance in the latest 'ms' milliseconds. */ 1278 int sentinelRedisInstanceNoDownFor(sentinelRedisInstance *ri, mstime_t ms) { 1279 mstime_t most_recent; 1280 1281 most_recent = ri->s_down_since_time; 1282 if (ri->o_down_since_time > most_recent) 1283 most_recent = ri->o_down_since_time; 1284 return most_recent == 0 || (mstime() - most_recent) > ms; 1285 } 1286 1287 /* Return the current master address, that is, its address or the address 1288 * of the promoted slave if already operational. */ 1289 sentinelAddr *sentinelGetCurrentMasterAddress(sentinelRedisInstance *master) { 1290 /* If we are failing over the master, and the state is already 1291 * SENTINEL_FAILOVER_STATE_RECONF_SLAVES or greater, it means that we 1292 * already have the new configuration epoch in the master, and the 1293 * slave acknowledged the configuration switch. Advertise the new 1294 * address. */ 1295 if ((master->flags & SRI_FAILOVER_IN_PROGRESS) && 1296 master->promoted_slave && 1297 master->failover_state >= SENTINEL_FAILOVER_STATE_RECONF_SLAVES) 1298 { 1299 return master->promoted_slave->addr; 1300 } else { 1301 return master->addr; 1302 } 1303 } 1304 1305 /* This function sets the down_after_period field value in 'master' to all 1306 * the slaves and sentinel instances connected to this master. */ 1307 void sentinelPropagateDownAfterPeriod(sentinelRedisInstance *master) { 1308 dictIterator *di; 1309 dictEntry *de; 1310 int j; 1311 dict *d[] = {master->slaves, master->sentinels, NULL}; 1312 1313 for (j = 0; d[j]; j++) { 1314 di = dictGetIterator(d[j]); 1315 while((de = dictNext(di)) != NULL) { 1316 sentinelRedisInstance *ri = dictGetVal(de); 1317 ri->down_after_period = master->down_after_period; 1318 } 1319 dictReleaseIterator(di); 1320 } 1321 } 1322 1323 /* ============================ Config handling ============================= */ 1324 char *sentinelHandleConfiguration(char **argv, int argc) { 1325 sentinelRedisInstance *ri; 1326 1327 if (!strcasecmp(argv[0],"monitor") && argc == 5) { 1328 /* monitor <name> <host> <port> <quorum> */ 1329 int quorum = atoi(argv[4]); 1330 1331 if (quorum <= 0) return "Quorum must be 1 or greater."; 1332 if (createSentinelRedisInstance(argv[1],SRI_MASTER,argv[2], 1333 atoi(argv[3]),quorum,NULL) == NULL) 1334 { 1335 switch(errno) { 1336 case EBUSY: return "Duplicated master name."; 1337 case ENOENT: return "Can't resolve master instance hostname."; 1338 case EINVAL: return "Invalid port number"; 1339 } 1340 } 1341 } else if (!strcasecmp(argv[0],"down-after-milliseconds") && argc == 3) { 1342 /* down-after-milliseconds <name> <milliseconds> */ 1343 ri = sentinelGetMasterByName(argv[1]); 1344 if (!ri) return "No such master with specified name."; 1345 ri->down_after_period = atoi(argv[2]); 1346 if (ri->down_after_period <= 0) 1347 return "negative or zero time parameter."; 1348 sentinelPropagateDownAfterPeriod(ri); 1349 } else if (!strcasecmp(argv[0],"failover-timeout") && argc == 3) { 1350 /* failover-timeout <name> <milliseconds> */ 1351 ri = sentinelGetMasterByName(argv[1]); 1352 if (!ri) return "No such master with specified name."; 1353 ri->failover_timeout = atoi(argv[2]); 1354 if (ri->failover_timeout <= 0) 1355 return "negative or zero time parameter."; 1356 } else if (!strcasecmp(argv[0],"parallel-syncs") && argc == 3) { 1357 /* parallel-syncs <name> <milliseconds> */ 1358 ri = sentinelGetMasterByName(argv[1]); 1359 if (!ri) return "No such master with specified name."; 1360 ri->parallel_syncs = atoi(argv[2]); 1361 } else if (!strcasecmp(argv[0],"notification-script") && argc == 3) { 1362 /* notification-script <name> <path> */ 1363 ri = sentinelGetMasterByName(argv[1]); 1364 if (!ri) return "No such master with specified name."; 1365 if (access(argv[2],X_OK) == -1) 1366 return "Notification script seems non existing or non executable."; 1367 ri->notification_script = sdsnew(argv[2]); 1368 } else if (!strcasecmp(argv[0],"client-reconfig-script") && argc == 3) { 1369 /* client-reconfig-script <name> <path> */ 1370 ri = sentinelGetMasterByName(argv[1]); 1371 if (!ri) return "No such master with specified name."; 1372 if (access(argv[2],X_OK) == -1) 1373 return "Client reconfiguration script seems non existing or " 1374 "non executable."; 1375 ri->client_reconfig_script = sdsnew(argv[2]); 1376 } else if (!strcasecmp(argv[0],"auth-pass") && argc == 3) { 1377 /* auth-pass <name> <password> */ 1378 ri = sentinelGetMasterByName(argv[1]); 1379 if (!ri) return "No such master with specified name."; 1380 ri->auth_pass = sdsnew(argv[2]); 1381 } else if (!strcasecmp(argv[0],"current-epoch") && argc == 2) { 1382 /* current-epoch <epoch> */ 1383 unsigned long long current_epoch = strtoull(argv[1],NULL,10); 1384 if (current_epoch > sentinel.current_epoch) 1385 sentinel.current_epoch = current_epoch; 1386 } else if (!strcasecmp(argv[0],"config-epoch") && argc == 3) { 1387 /* config-epoch <name> <epoch> */ 1388 ri = sentinelGetMasterByName(argv[1]); 1389 if (!ri) return "No such master with specified name."; 1390 ri->config_epoch = strtoull(argv[2],NULL,10); 1391 /* The following update of current_epoch is not really useful as 1392 * now the current epoch is persisted on the config file, but 1393 * we leave this check here for redundancy. */ 1394 if (ri->config_epoch > sentinel.current_epoch) 1395 sentinel.current_epoch = ri->config_epoch; 1396 } else if (!strcasecmp(argv[0],"leader-epoch") && argc == 3) { 1397 /* leader-epoch <name> <epoch> */ 1398 ri = sentinelGetMasterByName(argv[1]); 1399 if (!ri) return "No such master with specified name."; 1400 ri->leader_epoch = strtoull(argv[2],NULL,10); 1401 } else if (!strcasecmp(argv[0],"known-slave") && argc == 4) { 1402 sentinelRedisInstance *slave; 1403 1404 /* known-slave <name> <ip> <port> */ 1405 ri = sentinelGetMasterByName(argv[1]); 1406 if (!ri) return "No such master with specified name."; 1407 if ((slave = createSentinelRedisInstance(NULL,SRI_SLAVE,argv[2], 1408 atoi(argv[3]), ri->quorum, ri)) == NULL) 1409 { 1410 return "Wrong hostname or port for slave."; 1411 } 1412 } else if (!strcasecmp(argv[0],"known-sentinel") && 1413 (argc == 4 || argc == 5)) { 1414 sentinelRedisInstance *si; 1415 1416 /* known-sentinel <name> <ip> <port> [runid] */ 1417 ri = sentinelGetMasterByName(argv[1]); 1418 if (!ri) return "No such master with specified name."; 1419 if ((si = createSentinelRedisInstance(NULL,SRI_SENTINEL,argv[2], 1420 atoi(argv[3]), ri->quorum, ri)) == NULL) 1421 { 1422 return "Wrong hostname or port for sentinel."; 1423 } 1424 if (argc == 5) si->runid = sdsnew(argv[4]); 1425 } else { 1426 return "Unrecognized sentinel configuration statement."; 1427 } 1428 return NULL; 1429 } 1430 1431 /* Implements CONFIG REWRITE for "sentinel" option. 1432 * This is used not just to rewrite the configuration given by the user 1433 * (the configured masters) but also in order to retain the state of 1434 * Sentinel across restarts: config epoch of masters, associated slaves 1435 * and sentinel instances, and so forth. */ 1436 void rewriteConfigSentinelOption(struct rewriteConfigState *state) { 1437 dictIterator *di, *di2; 1438 dictEntry *de; 1439 sds line; 1440 1441 /* For every master emit a "sentinel monitor" config entry. */ 1442 di = dictGetIterator(sentinel.masters); 1443 while((de = dictNext(di)) != NULL) { 1444 sentinelRedisInstance *master, *ri; 1445 sentinelAddr *master_addr; 1446 1447 /* sentinel monitor */ 1448 master = dictGetVal(de); 1449 master_addr = sentinelGetCurrentMasterAddress(master); 1450 line = sdscatprintf(sdsempty(),"sentinel monitor %s %s %d %d", 1451 master->name, master_addr->ip, master_addr->port, 1452 master->quorum); 1453 rewriteConfigRewriteLine(state,"sentinel",line,1); 1454 1455 /* sentinel down-after-milliseconds */ 1456 if (master->down_after_period != SENTINEL_DEFAULT_DOWN_AFTER) { 1457 line = sdscatprintf(sdsempty(), 1458 "sentinel down-after-milliseconds %s %ld", 1459 master->name, (long) master->down_after_period); 1460 rewriteConfigRewriteLine(state,"sentinel",line,1); 1461 } 1462 1463 /* sentinel failover-timeout */ 1464 if (master->failover_timeout != SENTINEL_DEFAULT_FAILOVER_TIMEOUT) { 1465 line = sdscatprintf(sdsempty(), 1466 "sentinel failover-timeout %s %ld", 1467 master->name, (long) master->failover_timeout); 1468 rewriteConfigRewriteLine(state,"sentinel",line,1); 1469 } 1470 1471 /* sentinel parallel-syncs */ 1472 if (master->parallel_syncs != SENTINEL_DEFAULT_PARALLEL_SYNCS) { 1473 line = sdscatprintf(sdsempty(), 1474 "sentinel parallel-syncs %s %d", 1475 master->name, master->parallel_syncs); 1476 rewriteConfigRewriteLine(state,"sentinel",line,1); 1477 } 1478 1479 /* sentinel notification-script */ 1480 if (master->notification_script) { 1481 line = sdscatprintf(sdsempty(), 1482 "sentinel notification-script %s %s", 1483 master->name, master->notification_script); 1484 rewriteConfigRewriteLine(state,"sentinel",line,1); 1485 } 1486 1487 /* sentinel client-reconfig-script */ 1488 if (master->client_reconfig_script) { 1489 line = sdscatprintf(sdsempty(), 1490 "sentinel client-reconfig-script %s %s", 1491 master->name, master->client_reconfig_script); 1492 rewriteConfigRewriteLine(state,"sentinel",line,1); 1493 } 1494 1495 /* sentinel auth-pass */ 1496 if (master->auth_pass) { 1497 line = sdscatprintf(sdsempty(), 1498 "sentinel auth-pass %s %s", 1499 master->name, master->auth_pass); 1500 rewriteConfigRewriteLine(state,"sentinel",line,1); 1501 } 1502 1503 /* sentinel config-epoch */ 1504 line = sdscatprintf(sdsempty(), 1505 "sentinel config-epoch %s %llu", 1506 master->name, (unsigned long long) master->config_epoch); 1507 rewriteConfigRewriteLine(state,"sentinel",line,1); 1508 1509 /* sentinel leader-epoch */ 1510 line = sdscatprintf(sdsempty(), 1511 "sentinel leader-epoch %s %llu", 1512 master->name, (unsigned long long) master->leader_epoch); 1513 rewriteConfigRewriteLine(state,"sentinel",line,1); 1514 1515 /* sentinel known-slave */ 1516 di2 = dictGetIterator(master->slaves); 1517 while((de = dictNext(di2)) != NULL) { 1518 sentinelAddr *slave_addr; 1519 1520 ri = dictGetVal(de); 1521 slave_addr = ri->addr; 1522 1523 /* If master_addr (obtained using sentinelGetCurrentMasterAddress() 1524 * so it may be the address of the promoted slave) is equal to this 1525 * slave's address, a failover is in progress and the slave was 1526 * already successfully promoted. So as the address of this slave 1527 * we use the old master address instead. */ 1528 if (sentinelAddrIsEqual(slave_addr,master_addr)) 1529 slave_addr = master->addr; 1530 line = sdscatprintf(sdsempty(), 1531 "sentinel known-slave %s %s %d", 1532 master->name, ri->addr->ip, ri->addr->port); 1533 rewriteConfigRewriteLine(state,"sentinel",line,1); 1534 } 1535 dictReleaseIterator(di2); 1536 1537 /* sentinel known-sentinel */ 1538 di2 = dictGetIterator(master->sentinels); 1539 while((de = dictNext(di2)) != NULL) { 1540 ri = dictGetVal(de); 1541 line = sdscatprintf(sdsempty(), 1542 "sentinel known-sentinel %s %s %d%s%s", 1543 master->name, ri->addr->ip, ri->addr->port, 1544 ri->runid ? " " : "", 1545 ri->runid ? ri->runid : ""); 1546 rewriteConfigRewriteLine(state,"sentinel",line,1); 1547 } 1548 dictReleaseIterator(di2); 1549 } 1550 1551 /* sentinel current-epoch is a global state valid for all the masters. */ 1552 line = sdscatprintf(sdsempty(), 1553 "sentinel current-epoch %llu", (unsigned long long) sentinel.current_epoch); 1554 rewriteConfigRewriteLine(state,"sentinel",line,1); 1555 1556 dictReleaseIterator(di); 1557 } 1558 1559 /* This function uses the config rewriting Redis engine in order to persist 1560 * the state of the Sentinel in the current configuration file. 1561 * 1562 * Before returning the function calls fsync() against the generated 1563 * configuration file to make sure changes are committed to disk. 1564 * 1565 * On failure the function logs a warning on the Redis log. */ 1566 void sentinelFlushConfig(void) { 1567 int fd = -1; 1568 int saved_hz = server.hz; 1569 int rewrite_status; 1570 1571 server.hz = REDIS_DEFAULT_HZ; 1572 rewrite_status = rewriteConfig(server.configfile); 1573 server.hz = saved_hz; 1574 1575 if (rewrite_status == -1) goto werr; 1576 if ((fd = open(server.configfile,O_RDONLY)) == -1) goto werr; 1577 if (fsync(fd) == -1) goto werr; 1578 if (close(fd) == EOF) goto werr; 1579 return; 1580 1581 werr: 1582 if (fd != -1) close(fd); 1583 redisLog(REDIS_WARNING,"WARNING: Sentinel was not able to save the new configuration on disk!!!: %s", strerror(errno)); 1584 } 1585 1586 /* ====================== hiredis connection handling ======================= */ 1587 1588 /* Completely disconnect a hiredis link from an instance. */ 1589 void sentinelKillLink(sentinelRedisInstance *ri, redisAsyncContext *c) { 1590 if (ri->cc == c) { 1591 ri->cc = NULL; 1592 ri->pending_commands = 0; 1593 } 1594 if (ri->pc == c) ri->pc = NULL; 1595 c->data = NULL; 1596 ri->flags |= SRI_DISCONNECTED; 1597 redisAsyncFree(c); 1598 } 1599 1600 /* This function takes a hiredis context that is in an error condition 1601 * and make sure to mark the instance as disconnected performing the 1602 * cleanup needed. 1603 * 1604 * Note: we don't free the hiredis context as hiredis will do it for us 1605 * for async connections. */ 1606 void sentinelDisconnectInstanceFromContext(const redisAsyncContext *c) { 1607 sentinelRedisInstance *ri = c->data; 1608 int pubsub; 1609 1610 if (ri == NULL) return; /* The instance no longer exists. */ 1611 1612 pubsub = (ri->pc == c); 1613 sentinelEvent(REDIS_DEBUG, pubsub ? "-pubsub-link" : "-cmd-link", ri, 1614 "%@ #%s", c->errstr); 1615 if (pubsub) 1616 ri->pc = NULL; 1617 else 1618 ri->cc = NULL; 1619 ri->flags |= SRI_DISCONNECTED; 1620 } 1621 1622 void sentinelLinkEstablishedCallback(const redisAsyncContext *c, int status) { 1623 if (status != REDIS_OK) { 1624 sentinelDisconnectInstanceFromContext(c); 1625 } else { 1626 sentinelRedisInstance *ri = c->data; 1627 int pubsub = (ri->pc == c); 1628 1629 sentinelEvent(REDIS_DEBUG, pubsub ? "+pubsub-link" : "+cmd-link", ri, 1630 "%@"); 1631 } 1632 } 1633 1634 void sentinelDisconnectCallback(const redisAsyncContext *c, int status) { 1635 sentinelDisconnectInstanceFromContext(c); 1636 } 1637 1638 /* Send the AUTH command with the specified master password if needed. 1639 * Note that for slaves the password set for the master is used. 1640 * 1641 * We don't check at all if the command was successfully transmitted 1642 * to the instance as if it fails Sentinel will detect the instance down, 1643 * will disconnect and reconnect the link and so forth. */ 1644 void sentinelSendAuthIfNeeded(sentinelRedisInstance *ri, redisAsyncContext *c) { 1645 char *auth_pass = (ri->flags & SRI_MASTER) ? ri->auth_pass : 1646 ri->master->auth_pass; 1647 1648 if (auth_pass) { 1649 if (redisAsyncCommand(c, sentinelDiscardReplyCallback, NULL, "AUTH %s", 1650 auth_pass) == REDIS_OK) ri->pending_commands++; 1651 } 1652 } 1653 1654 /* Use CLIENT SETNAME to name the connection in the Redis instance as 1655 * sentinel-<first_8_chars_of_runid>-<connection_type> 1656 * The connection type is "cmd" or "pubsub" as specified by 'type'. 1657 * 1658 * This makes it possible to list all the sentinel instances connected 1659 * to a Redis servewr with CLIENT LIST, grepping for a specific name format. */ 1660 void sentinelSetClientName(sentinelRedisInstance *ri, redisAsyncContext *c, char *type) { 1661 char name[64]; 1662 1663 snprintf(name,sizeof(name),"sentinel-%.8s-%s",server.runid,type); 1664 if (redisAsyncCommand(c, sentinelDiscardReplyCallback, NULL, 1665 "CLIENT SETNAME %s", name) == REDIS_OK) 1666 { 1667 ri->pending_commands++; 1668 } 1669 } 1670 1671 /* Create the async connections for the specified instance if the instance 1672 * is disconnected. Note that the SRI_DISCONNECTED flag is set even if just 1673 * one of the two links (commands and pub/sub) is missing. */ 1674 void sentinelReconnectInstance(sentinelRedisInstance *ri) { 1675 if (!(ri->flags & SRI_DISCONNECTED)) return; 1676 1677 /* Commands connection. */ 1678 if (ri->cc == NULL) { 1679 ri->cc = redisAsyncConnect(ri->addr->ip,ri->addr->port); 1680 if (ri->cc->err) { 1681 sentinelEvent(REDIS_DEBUG,"-cmd-link-reconnection",ri,"%@ #%s", 1682 ri->cc->errstr); 1683 sentinelKillLink(ri,ri->cc); 1684 } else { 1685 ri->cc_conn_time = mstime(); 1686 ri->cc->data = ri; 1687 redisAeAttach(server.el,ri->cc); 1688 redisAsyncSetConnectCallback(ri->cc, 1689 sentinelLinkEstablishedCallback); 1690 redisAsyncSetDisconnectCallback(ri->cc, 1691 sentinelDisconnectCallback); 1692 sentinelSendAuthIfNeeded(ri,ri->cc); 1693 sentinelSetClientName(ri,ri->cc,"cmd"); 1694 1695 /* Send a PING ASAP when reconnecting. */ 1696 sentinelSendPing(ri); 1697 } 1698 } 1699 /* Pub / Sub */ 1700 if ((ri->flags & (SRI_MASTER|SRI_SLAVE)) && ri->pc == NULL) { 1701 ri->pc = redisAsyncConnect(ri->addr->ip,ri->addr->port); 1702 if (ri->pc->err) { 1703 sentinelEvent(REDIS_DEBUG,"-pubsub-link-reconnection",ri,"%@ #%s", 1704 ri->pc->errstr); 1705 sentinelKillLink(ri,ri->pc); 1706 } else { 1707 int retval; 1708 1709 ri->pc_conn_time = mstime(); 1710 ri->pc->data = ri; 1711 redisAeAttach(server.el,ri->pc); 1712 redisAsyncSetConnectCallback(ri->pc, 1713 sentinelLinkEstablishedCallback); 1714 redisAsyncSetDisconnectCallback(ri->pc, 1715 sentinelDisconnectCallback); 1716 sentinelSendAuthIfNeeded(ri,ri->pc); 1717 sentinelSetClientName(ri,ri->pc,"pubsub"); 1718 /* Now we subscribe to the Sentinels "Hello" channel. */ 1719 retval = redisAsyncCommand(ri->pc, 1720 sentinelReceiveHelloMessages, NULL, "SUBSCRIBE %s", 1721 SENTINEL_HELLO_CHANNEL); 1722 if (retval != REDIS_OK) { 1723 /* If we can't subscribe, the Pub/Sub connection is useless 1724 * and we can simply disconnect it and try again. */ 1725 sentinelKillLink(ri,ri->pc); 1726 return; 1727 } 1728 } 1729 } 1730 /* Clear the DISCONNECTED flags only if we have both the connections 1731 * (or just the commands connection if this is a sentinel instance). */ 1732 if (ri->cc && (ri->flags & SRI_SENTINEL || ri->pc)) 1733 ri->flags &= ~SRI_DISCONNECTED; 1734 } 1735 1736 /* ======================== Redis instances pinging ======================== */ 1737 1738 /* Return true if master looks "sane", that is: 1739 * 1) It is actually a master in the current configuration. 1740 * 2) It reports itself as a master. 1741 * 3) It is not SDOWN or ODOWN. 1742 * 4) We obtained last INFO no more than two times the INFO period time ago. */ 1743 int sentinelMasterLooksSane(sentinelRedisInstance *master) { 1744 return 1745 master->flags & SRI_MASTER && 1746 master->role_reported == SRI_MASTER && 1747 (master->flags & (SRI_S_DOWN|SRI_O_DOWN)) == 0 && 1748 (mstime() - master->info_refresh) < SENTINEL_INFO_PERIOD*2; 1749 } 1750 1751 /* Process the INFO output from masters. */ 1752 void sentinelRefreshInstanceInfo(sentinelRedisInstance *ri, const char *info) { 1753 sds *lines; 1754 int numlines, j; 1755 int role = 0; 1756 1757 /* The following fields must be reset to a given value in the case they 1758 * are not found at all in the INFO output. */ 1759 ri->master_link_down_time = 0; 1760 1761 /* Process line by line. */ 1762 lines = sdssplitlen(info,strlen(info),"\r\n",2,&numlines); 1763 for (j = 0; j < numlines; j++) { 1764 sentinelRedisInstance *slave; 1765 sds l = lines[j]; 1766 1767 /* run_id:<40 hex chars>*/ 1768 if (sdslen(l) >= 47 && !memcmp(l,"run_id:",7)) { 1769 if (ri->runid == NULL) { 1770 ri->runid = sdsnewlen(l+7,40); 1771 } else { 1772 if (strncmp(ri->runid,l+7,40) != 0) { 1773 sentinelEvent(REDIS_NOTICE,"+reboot",ri,"%@"); 1774 sdsfree(ri->runid); 1775 ri->runid = sdsnewlen(l+7,40); 1776 } 1777 } 1778 } 1779 1780 /* old versions: slave0:<ip>,<port>,<state> 1781 * new versions: slave0:ip=127.0.0.1,port=9999,... */ 1782 if ((ri->flags & SRI_MASTER) && 1783 sdslen(l) >= 7 && 1784 !memcmp(l,"slave",5) && isdigit(l[5])) 1785 { 1786 char *ip, *port, *end; 1787 1788 if (strstr(l,"ip=") == NULL) { 1789 /* Old format. */ 1790 ip = strchr(l,':'); if (!ip) continue; 1791 ip++; /* Now ip points to start of ip address. */ 1792 port = strchr(ip,','); if (!port) continue; 1793 *port = '\0'; /* nul term for easy access. */ 1794 port++; /* Now port points to start of port number. */ 1795 end = strchr(port,','); if (!end) continue; 1796 *end = '\0'; /* nul term for easy access. */ 1797 } else { 1798 /* New format. */ 1799 ip = strstr(l,"ip="); if (!ip) continue; 1800 ip += 3; /* Now ip points to start of ip address. */ 1801 port = strstr(l,"port="); if (!port) continue; 1802 port += 5; /* Now port points to start of port number. */ 1803 /* Nul term both fields for easy access. */ 1804 end = strchr(ip,','); if (end) *end = '\0'; 1805 end = strchr(port,','); if (end) *end = '\0'; 1806 } 1807 1808 /* Check if we already have this slave into our table, 1809 * otherwise add it. */ 1810 if (sentinelRedisInstanceLookupSlave(ri,ip,atoi(port)) == NULL) { 1811 if ((slave = createSentinelRedisInstance(NULL,SRI_SLAVE,ip, 1812 atoi(port), ri->quorum, ri)) != NULL) 1813 { 1814 sentinelEvent(REDIS_NOTICE,"+slave",slave,"%@"); 1815 } 1816 } 1817 } 1818 1819 /* master_link_down_since_seconds:<seconds> */ 1820 if (sdslen(l) >= 32 && 1821 !memcmp(l,"master_link_down_since_seconds",30)) 1822 { 1823 ri->master_link_down_time = strtoll(l+31,NULL,10)*1000; 1824 } 1825 1826 /* role:<role> */ 1827 if (!memcmp(l,"role:master",11)) role = SRI_MASTER; 1828 else if (!memcmp(l,"role:slave",10)) role = SRI_SLAVE; 1829 1830 if (role == SRI_SLAVE) { 1831 /* master_host:<host> */ 1832 if (sdslen(l) >= 12 && !memcmp(l,"master_host:",12)) { 1833 if (ri->slave_master_host == NULL || 1834 strcasecmp(l+12,ri->slave_master_host)) 1835 { 1836 sdsfree(ri->slave_master_host); 1837 ri->slave_master_host = sdsnew(l+12); 1838 ri->slave_conf_change_time = mstime(); 1839 } 1840 } 1841 1842 /* master_port:<port> */ 1843 if (sdslen(l) >= 12 && !memcmp(l,"master_port:",12)) { 1844 int slave_master_port = atoi(l+12); 1845 1846 if (ri->slave_master_port != slave_master_port) { 1847 ri->slave_master_port = slave_master_port; 1848 ri->slave_conf_change_time = mstime(); 1849 } 1850 } 1851 1852 /* master_link_status:<status> */ 1853 if (sdslen(l) >= 19 && !memcmp(l,"master_link_status:",19)) { 1854 ri->slave_master_link_status = 1855 (strcasecmp(l+19,"up") == 0) ? 1856 SENTINEL_MASTER_LINK_STATUS_UP : 1857 SENTINEL_MASTER_LINK_STATUS_DOWN; 1858 } 1859 1860 /* slave_priority:<priority> */ 1861 if (sdslen(l) >= 15 && !memcmp(l,"slave_priority:",15)) 1862 ri->slave_priority = atoi(l+15); 1863 1864 /* slave_repl_offset:<offset> */ 1865 if (sdslen(l) >= 18 && !memcmp(l,"slave_repl_offset:",18)) 1866 ri->slave_repl_offset = strtoull(l+18,NULL,10); 1867 } 1868 } 1869 ri->info_refresh = mstime(); 1870 sdsfreesplitres(lines,numlines); 1871 1872 /* ---------------------------- Acting half ----------------------------- 1873 * Some things will not happen if sentinel.tilt is true, but some will 1874 * still be processed. */ 1875 1876 /* Remember when the role changed. */ 1877 if (role != ri->role_reported) { 1878 ri->role_reported_time = mstime(); 1879 ri->role_reported = role; 1880 if (role == SRI_SLAVE) ri->slave_conf_change_time = mstime(); 1881 /* Log the event with +role-change if the new role is coherent or 1882 * with -role-change if there is a mismatch with the current config. */ 1883 sentinelEvent(REDIS_VERBOSE, 1884 ((ri->flags & (SRI_MASTER|SRI_SLAVE)) == role) ? 1885 "+role-change" : "-role-change", 1886 ri, "%@ new reported role is %s", 1887 role == SRI_MASTER ? "master" : "slave", 1888 ri->flags & SRI_MASTER ? "master" : "slave"); 1889 } 1890 1891 /* None of the following conditions are processed when in tilt mode, so 1892 * return asap. */ 1893 if (sentinel.tilt) return; 1894 1895 /* Handle master -> slave role switch. */ 1896 if ((ri->flags & SRI_MASTER) && role == SRI_SLAVE) { 1897 /* Nothing to do, but masters claiming to be slaves are 1898 * considered to be unreachable by Sentinel, so eventually 1899 * a failover will be triggered. */ 1900 } 1901 1902 /* Handle slave -> master role switch. */ 1903 if ((ri->flags & SRI_SLAVE) && role == SRI_MASTER) { 1904 /* If this is a promoted slave we can change state to the 1905 * failover state machine. */ 1906 if ((ri->flags & SRI_PROMOTED) && 1907 (ri->master->flags & SRI_FAILOVER_IN_PROGRESS) && 1908 (ri->master->failover_state == 1909 SENTINEL_FAILOVER_STATE_WAIT_PROMOTION)) 1910 { 1911 /* Now that we are sure the slave was reconfigured as a master 1912 * set the master configuration epoch to the epoch we won the 1913 * election to perform this failover. This will force the other 1914 * Sentinels to update their config (assuming there is not 1915 * a newer one already available). */ 1916 ri->master->config_epoch = ri->master->failover_epoch; 1917 ri->master->failover_state = SENTINEL_FAILOVER_STATE_RECONF_SLAVES; 1918 ri->master->failover_state_change_time = mstime(); 1919 sentinelFlushConfig(); 1920 sentinelEvent(REDIS_WARNING,"+promoted-slave",ri,"%@"); 1921 sentinelEvent(REDIS_WARNING,"+failover-state-reconf-slaves", 1922 ri->master,"%@"); 1923 sentinelCallClientReconfScript(ri->master,SENTINEL_LEADER, 1924 "start",ri->master->addr,ri->addr); 1925 sentinelForceHelloUpdateForMaster(ri->master); 1926 } else { 1927 /* A slave turned into a master. We want to force our view and 1928 * reconfigure as slave. Wait some time after the change before 1929 * going forward, to receive new configs if any. */ 1930 mstime_t wait_time = SENTINEL_PUBLISH_PERIOD*4; 1931 1932 if (!(ri->flags & SRI_PROMOTED) && 1933 sentinelMasterLooksSane(ri->master) && 1934 sentinelRedisInstanceNoDownFor(ri,wait_time) && 1935 mstime() - ri->role_reported_time > wait_time) 1936 { 1937 int retval = sentinelSendSlaveOf(ri, 1938 ri->master->addr->ip, 1939 ri->master->addr->port); 1940 if (retval == REDIS_OK) 1941 sentinelEvent(REDIS_NOTICE,"+convert-to-slave",ri,"%@"); 1942 } 1943 } 1944 } 1945 1946 /* Handle slaves replicating to a different master address. */ 1947 if ((ri->flags & SRI_SLAVE) && 1948 role == SRI_SLAVE && 1949 (ri->slave_master_port != ri->master->addr->port || 1950 strcasecmp(ri->slave_master_host,ri->master->addr->ip))) 1951 { 1952 mstime_t wait_time = ri->master->failover_timeout; 1953 1954 /* Make sure the master is sane before reconfiguring this instance 1955 * into a slave. */ 1956 if (sentinelMasterLooksSane(ri->master) && 1957 sentinelRedisInstanceNoDownFor(ri,wait_time) && 1958 mstime() - ri->slave_conf_change_time > wait_time) 1959 { 1960 int retval = sentinelSendSlaveOf(ri, 1961 ri->master->addr->ip, 1962 ri->master->addr->port); 1963 if (retval == REDIS_OK) 1964 sentinelEvent(REDIS_NOTICE,"+fix-slave-config",ri,"%@"); 1965 } 1966 } 1967 1968 /* Detect if the slave that is in the process of being reconfigured 1969 * changed state. */ 1970 if ((ri->flags & SRI_SLAVE) && role == SRI_SLAVE && 1971 (ri->flags & (SRI_RECONF_SENT|SRI_RECONF_INPROG))) 1972 { 1973 /* SRI_RECONF_SENT -> SRI_RECONF_INPROG. */ 1974 if ((ri->flags & SRI_RECONF_SENT) && 1975 ri->slave_master_host && 1976 strcmp(ri->slave_master_host, 1977 ri->master->promoted_slave->addr->ip) == 0 && 1978 ri->slave_master_port == ri->master->promoted_slave->addr->port) 1979 { 1980 ri->flags &= ~SRI_RECONF_SENT; 1981 ri->flags |= SRI_RECONF_INPROG; 1982 sentinelEvent(REDIS_NOTICE,"+slave-reconf-inprog",ri,"%@"); 1983 } 1984 1985 /* SRI_RECONF_INPROG -> SRI_RECONF_DONE */ 1986 if ((ri->flags & SRI_RECONF_INPROG) && 1987 ri->slave_master_link_status == SENTINEL_MASTER_LINK_STATUS_UP) 1988 { 1989 ri->flags &= ~SRI_RECONF_INPROG; 1990 ri->flags |= SRI_RECONF_DONE; 1991 sentinelEvent(REDIS_NOTICE,"+slave-reconf-done",ri,"%@"); 1992 } 1993 } 1994 } 1995 1996 void sentinelInfoReplyCallback(redisAsyncContext *c, void *reply, void *privdata) { 1997 sentinelRedisInstance *ri = c->data; 1998 redisReply *r; 1999 2000 if (ri) ri->pending_commands--; 2001 if (!reply || !ri) return; 2002 r = reply; 2003 2004 if (r->type == REDIS_REPLY_STRING) { 2005 sentinelRefreshInstanceInfo(ri,r->str); 2006 } 2007 } 2008 2009 /* Just discard the reply. We use this when we are not monitoring the return 2010 * value of the command but its effects directly. */ 2011 void sentinelDiscardReplyCallback(redisAsyncContext *c, void *reply, void *privdata) { 2012 sentinelRedisInstance *ri = c->data; 2013 2014 if (ri) ri->pending_commands--; 2015 } 2016 2017 void sentinelPingReplyCallback(redisAsyncContext *c, void *reply, void *privdata) { 2018 sentinelRedisInstance *ri = c->data; 2019 redisReply *r; 2020 2021 if (ri) ri->pending_commands--; 2022 if (!reply || !ri) return; 2023 r = reply; 2024 2025 if (r->type == REDIS_REPLY_STATUS || 2026 r->type == REDIS_REPLY_ERROR) { 2027 /* Update the "instance available" field only if this is an 2028 * acceptable reply. */ 2029 if (strncmp(r->str,"PONG",4) == 0 || 2030 strncmp(r->str,"LOADING",7) == 0 || 2031 strncmp(r->str,"MASTERDOWN",10) == 0) 2032 { 2033 ri->last_avail_time = mstime(); 2034 ri->last_ping_time = 0; /* Flag the pong as received. */ 2035 } else { 2036 /* Send a SCRIPT KILL command if the instance appears to be 2037 * down because of a busy script. */ 2038 if (strncmp(r->str,"BUSY",4) == 0 && 2039 (ri->flags & SRI_S_DOWN) && 2040 !(ri->flags & SRI_SCRIPT_KILL_SENT)) 2041 { 2042 if (redisAsyncCommand(ri->cc, 2043 sentinelDiscardReplyCallback, NULL, 2044 "SCRIPT KILL") == REDIS_OK) 2045 ri->pending_commands++; 2046 ri->flags |= SRI_SCRIPT_KILL_SENT; 2047 } 2048 } 2049 } 2050 ri->last_pong_time = mstime(); 2051 } 2052 2053 /* This is called when we get the reply about the PUBLISH command we send 2054 * to the master to advertise this sentinel. */ 2055 void sentinelPublishReplyCallback(redisAsyncContext *c, void *reply, void *privdata) { 2056 sentinelRedisInstance *ri = c->data; 2057 redisReply *r; 2058 2059 if (ri) ri->pending_commands--; 2060 if (!reply || !ri) return; 2061 r = reply; 2062 2063 /* Only update pub_time if we actually published our message. Otherwise 2064 * we'll retry again in 100 milliseconds. */ 2065 if (r->type != REDIS_REPLY_ERROR) 2066 ri->last_pub_time = mstime(); 2067 } 2068 2069 /* Process an hello message received via Pub/Sub in master or slave instance, 2070 * or sent directly to this sentinel via the (fake) PUBLISH command of Sentinel. 2071 * 2072 * If the master name specified in the message is not known, the message is 2073 * discareded. */ 2074 void sentinelProcessHelloMessage(char *hello, int hello_len) { 2075 /* Format is composed of 8 tokens: 2076 * 0=ip,1=port,2=runid,3=current_epoch,4=master_name, 2077 * 5=master_ip,6=master_port,7=master_config_epoch. */ 2078 int numtokens, port, removed, master_port; 2079 uint64_t current_epoch, master_config_epoch; 2080 char **token = sdssplitlen(hello, hello_len, ",", 1, &numtokens); 2081 sentinelRedisInstance *si, *master; 2082 2083 if (numtokens == 8) { 2084 /* Obtain a reference to the master this hello message is about */ 2085 master = sentinelGetMasterByName(token[4]); 2086 if (!master) goto cleanup; /* Unknown master, skip the message. */ 2087 2088 /* First, try to see if we already have this sentinel. */ 2089 port = atoi(token[1]); 2090 master_port = atoi(token[6]); 2091 si = getSentinelRedisInstanceByAddrAndRunID( 2092 master->sentinels,token[0],port,token[2]); 2093 current_epoch = strtoull(token[3],NULL,10); 2094 master_config_epoch = strtoull(token[7],NULL,10); 2095 2096 if (!si) { 2097 /* If not, remove all the sentinels that have the same runid 2098 * OR the same ip/port, because it's either a restart or a 2099 * network topology change. */ 2100 removed = removeMatchingSentinelsFromMaster(master,token[0],port, 2101 token[2]); 2102 if (removed) { 2103 sentinelEvent(REDIS_NOTICE,"-dup-sentinel",master, 2104 "%@ #duplicate of %s:%d or %s", 2105 token[0],port,token[2]); 2106 } 2107 2108 /* Add the new sentinel. */ 2109 si = createSentinelRedisInstance(NULL,SRI_SENTINEL, 2110 token[0],port,master->quorum,master); 2111 if (si) { 2112 sentinelEvent(REDIS_NOTICE,"+sentinel",si,"%@"); 2113 /* The runid is NULL after a new instance creation and 2114 * for Sentinels we don't have a later chance to fill it, 2115 * so do it now. */ 2116 si->runid = sdsnew(token[2]); 2117 sentinelFlushConfig(); 2118 } 2119 } 2120 2121 /* Update local current_epoch if received current_epoch is greater.*/ 2122 if (current_epoch > sentinel.current_epoch) { 2123 sentinel.current_epoch = current_epoch; 2124 sentinelFlushConfig(); 2125 sentinelEvent(REDIS_WARNING,"+new-epoch",master,"%llu", 2126 (unsigned long long) sentinel.current_epoch); 2127 } 2128 2129 /* Update master info if received configuration is newer. */ 2130 if (master->config_epoch < master_config_epoch) { 2131 master->config_epoch = master_config_epoch; 2132 if (master_port != master->addr->port || 2133 strcmp(master->addr->ip, token[5])) 2134 { 2135 sentinelAddr *old_addr; 2136 2137 sentinelEvent(REDIS_WARNING,"+config-update-from",si,"%@"); 2138 sentinelEvent(REDIS_WARNING,"+switch-master", 2139 master,"%s %s %d %s %d", 2140 master->name, 2141 master->addr->ip, master->addr->port, 2142 token[5], master_port); 2143 2144 old_addr = dupSentinelAddr(master->addr); 2145 sentinelResetMasterAndChangeAddress(master, token[5], master_port); 2146 sentinelCallClientReconfScript(master, 2147 SENTINEL_OBSERVER,"start", 2148 old_addr,master->addr); 2149 releaseSentinelAddr(old_addr); 2150 } 2151 } 2152 2153 /* Update the state of the Sentinel. */ 2154 if (si) si->last_hello_time = mstime(); 2155 } 2156 2157 cleanup: 2158 sdsfreesplitres(token,numtokens); 2159 } 2160 2161 2162 /* This is our Pub/Sub callback for the Hello channel. It's useful in order 2163 * to discover other sentinels attached at the same master. */ 2164 void sentinelReceiveHelloMessages(redisAsyncContext *c, void *reply, void *privdata) { 2165 sentinelRedisInstance *ri = c->data; 2166 redisReply *r; 2167 2168 if (!reply || !ri) return; 2169 r = reply; 2170 2171 /* Update the last activity in the pubsub channel. Note that since we 2172 * receive our messages as well this timestamp can be used to detect 2173 * if the link is probably disconnected even if it seems otherwise. */ 2174 ri->pc_last_activity = mstime(); 2175 2176 /* Sanity check in the reply we expect, so that the code that follows 2177 * can avoid to check for details. */ 2178 if (r->type != REDIS_REPLY_ARRAY || 2179 r->elements != 3 || 2180 r->element[0]->type != REDIS_REPLY_STRING || 2181 r->element[1]->type != REDIS_REPLY_STRING || 2182 r->element[2]->type != REDIS_REPLY_STRING || 2183 strcmp(r->element[0]->str,"message") != 0) return; 2184 2185 /* We are not interested in meeting ourselves */ 2186 if (strstr(r->element[2]->str,server.runid) != NULL) return; 2187 2188 sentinelProcessHelloMessage(r->element[2]->str, r->element[2]->len); 2189 } 2190 2191 /* Send an "Hello" message via Pub/Sub to the specified 'ri' Redis 2192 * instance in order to broadcast the current configuraiton for this 2193 * master, and to advertise the existence of this Sentinel at the same time. 2194 * 2195 * The message has the following format: 2196 * 2197 * sentinel_ip,sentinel_port,sentinel_runid,current_epoch, 2198 * master_name,master_ip,master_port,master_config_epoch. 2199 * 2200 * Returns REDIS_OK if the PUBLISH was queued correctly, otherwise 2201 * REDIS_ERR is returned. */ 2202 int sentinelSendHello(sentinelRedisInstance *ri) { 2203 char ip[REDIS_IP_STR_LEN]; 2204 char payload[REDIS_IP_STR_LEN+1024]; 2205 int retval; 2206 sentinelRedisInstance *master = (ri->flags & SRI_MASTER) ? ri : ri->master; 2207 sentinelAddr *master_addr = sentinelGetCurrentMasterAddress(master); 2208 2209 /* Try to obtain our own IP address. */ 2210 if (anetSockName(ri->cc->c.fd,ip,sizeof(ip),NULL) == -1) return REDIS_ERR; 2211 if (ri->flags & SRI_DISCONNECTED) return REDIS_ERR; 2212 2213 /* Format and send the Hello message. */ 2214 snprintf(payload,sizeof(payload), 2215 "%s,%d,%s,%llu," /* Info about this sentinel. */ 2216 "%s,%s,%d,%llu", /* Info about current master. */ 2217 ip, server.port, server.runid, 2218 (unsigned long long) sentinel.current_epoch, 2219 /* --- */ 2220 master->name,master_addr->ip,master_addr->port, 2221 (unsigned long long) master->config_epoch); 2222 retval = redisAsyncCommand(ri->cc, 2223 sentinelPublishReplyCallback, NULL, "PUBLISH %s %s", 2224 SENTINEL_HELLO_CHANNEL,payload); 2225 if (retval != REDIS_OK) return REDIS_ERR; 2226 ri->pending_commands++; 2227 return REDIS_OK; 2228 } 2229 2230 /* Reset last_pub_time in all the instances in the specified dictionary 2231 * in order to force the delivery of an Hello update ASAP. */ 2232 void sentinelForceHelloUpdateDictOfRedisInstances(dict *instances) { 2233 dictIterator *di; 2234 dictEntry *de; 2235 2236 di = dictGetSafeIterator(instances); 2237 while((de = dictNext(di)) != NULL) { 2238 sentinelRedisInstance *ri = dictGetVal(de); 2239 if (ri->last_pub_time >= (SENTINEL_PUBLISH_PERIOD+1)) 2240 ri->last_pub_time -= (SENTINEL_PUBLISH_PERIOD+1); 2241 } 2242 dictReleaseIterator(di); 2243 } 2244 2245 /* This function forces the delivery of an "Hello" message (see 2246 * sentinelSendHello() top comment for further information) to all the Redis 2247 * and Sentinel instances related to the specified 'master'. 2248 * 2249 * It is technically not needed since we send an update to every instance 2250 * with a period of SENTINEL_PUBLISH_PERIOD milliseconds, however when a 2251 * Sentinel upgrades a configuration it is a good idea to deliever an update 2252 * to the other Sentinels ASAP. */ 2253 int sentinelForceHelloUpdateForMaster(sentinelRedisInstance *master) { 2254 if (!(master->flags & SRI_MASTER)) return REDIS_ERR; 2255 if (master->last_pub_time >= (SENTINEL_PUBLISH_PERIOD+1)) 2256 master->last_pub_time -= (SENTINEL_PUBLISH_PERIOD+1); 2257 sentinelForceHelloUpdateDictOfRedisInstances(master->sentinels); 2258 sentinelForceHelloUpdateDictOfRedisInstances(master->slaves); 2259 return REDIS_OK; 2260 } 2261 2262 /* Send a PING to the specified instance and refresh the last_ping_time 2263 * if it is zero (that is, if we received a pong for the previous ping). 2264 * 2265 * On error zero is returned, and we can't consider the PING command 2266 * queued in the connection. */ 2267 int sentinelSendPing(sentinelRedisInstance *ri) { 2268 int retval = redisAsyncCommand(ri->cc, 2269 sentinelPingReplyCallback, NULL, "PING"); 2270 if (retval == REDIS_OK) { 2271 ri->pending_commands++; 2272 /* We update the ping time only if we received the pong for 2273 * the previous ping, otherwise we are technically waiting 2274 * since the first ping that did not received a reply. */ 2275 if (ri->last_ping_time == 0) ri->last_ping_time = mstime(); 2276 return 1; 2277 } else { 2278 return 0; 2279 } 2280 } 2281 2282 /* Send periodic PING, INFO, and PUBLISH to the Hello channel to 2283 * the specified master or slave instance. */ 2284 void sentinelSendPeriodicCommands(sentinelRedisInstance *ri) { 2285 mstime_t now = mstime(); 2286 mstime_t info_period, ping_period; 2287 int retval; 2288 2289 /* Return ASAP if we have already a PING or INFO already pending, or 2290 * in the case the instance is not properly connected. */ 2291 if (ri->flags & SRI_DISCONNECTED) return; 2292 2293 /* For INFO, PING, PUBLISH that are not critical commands to send we 2294 * also have a limit of SENTINEL_MAX_PENDING_COMMANDS. We don't 2295 * want to use a lot of memory just because a link is not working 2296 * properly (note that anyway there is a redundant protection about this, 2297 * that is, the link will be disconnected and reconnected if a long 2298 * timeout condition is detected. */ 2299 if (ri->pending_commands >= SENTINEL_MAX_PENDING_COMMANDS) return; 2300 2301 /* If this is a slave of a master in O_DOWN condition we start sending 2302 * it INFO every second, instead of the usual SENTINEL_INFO_PERIOD 2303 * period. In this state we want to closely monitor slaves in case they 2304 * are turned into masters by another Sentinel, or by the sysadmin. */ 2305 if ((ri->flags & SRI_SLAVE) && 2306 (ri->master->flags & (SRI_O_DOWN|SRI_FAILOVER_IN_PROGRESS))) { 2307 info_period = 1000; 2308 } else { 2309 info_period = SENTINEL_INFO_PERIOD; 2310 } 2311 2312 /* We ping instances every time the last received pong is older than 2313 * the configured 'down-after-milliseconds' time, but every second 2314 * anyway if 'down-after-milliseconds' is greater than 1 second. */ 2315 ping_period = ri->down_after_period; 2316 if (ping_period > SENTINEL_PING_PERIOD) ping_period = SENTINEL_PING_PERIOD; 2317 2318 if ((ri->flags & SRI_SENTINEL) == 0 && 2319 (ri->info_refresh == 0 || 2320 (now - ri->info_refresh) > info_period)) 2321 { 2322 /* Send INFO to masters and slaves, not sentinels. */ 2323 retval = redisAsyncCommand(ri->cc, 2324 sentinelInfoReplyCallback, NULL, "INFO"); 2325 if (retval == REDIS_OK) ri->pending_commands++; 2326 } else if ((now - ri->last_pong_time) > ping_period) { 2327 /* Send PING to all the three kinds of instances. */ 2328 sentinelSendPing(ri); 2329 } else if ((now - ri->last_pub_time) > SENTINEL_PUBLISH_PERIOD) { 2330 /* PUBLISH hello messages to all the three kinds of instances. */ 2331 sentinelSendHello(ri); 2332 } 2333 } 2334 2335 /* =========================== SENTINEL command ============================= */ 2336 2337 const char *sentinelFailoverStateStr(int state) { 2338 switch(state) { 2339 case SENTINEL_FAILOVER_STATE_NONE: return "none"; 2340 case SENTINEL_FAILOVER_STATE_WAIT_START: return "wait_start"; 2341 case SENTINEL_FAILOVER_STATE_SELECT_SLAVE: return "select_slave"; 2342 case SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE: return "send_slaveof_noone"; 2343 case SENTINEL_FAILOVER_STATE_WAIT_PROMOTION: return "wait_promotion"; 2344 case SENTINEL_FAILOVER_STATE_RECONF_SLAVES: return "reconf_slaves"; 2345 case SENTINEL_FAILOVER_STATE_UPDATE_CONFIG: return "update_config"; 2346 default: return "unknown"; 2347 } 2348 } 2349 2350 /* Redis instance to Redis protocol representation. */ 2351 void addReplySentinelRedisInstance(redisClient *c, sentinelRedisInstance *ri) { 2352 char *flags = sdsempty(); 2353 void *mbl; 2354 int fields = 0; 2355 2356 mbl = addDeferredMultiBulkLength(c); 2357 2358 addReplyBulkCString(c,"name"); 2359 addReplyBulkCString(c,ri->name); 2360 fields++; 2361 2362 addReplyBulkCString(c,"ip"); 2363 addReplyBulkCString(c,ri->addr->ip); 2364 fields++; 2365 2366 addReplyBulkCString(c,"port"); 2367 addReplyBulkLongLong(c,ri->addr->port); 2368 fields++; 2369 2370 addReplyBulkCString(c,"runid"); 2371 addReplyBulkCString(c,ri->runid ? ri->runid : ""); 2372 fields++; 2373 2374 addReplyBulkCString(c,"flags"); 2375 if (ri->flags & SRI_S_DOWN) flags = sdscat(flags,"s_down,"); 2376 if (ri->flags & SRI_O_DOWN) flags = sdscat(flags,"o_down,"); 2377 if (ri->flags & SRI_MASTER) flags = sdscat(flags,"master,"); 2378 if (ri->flags & SRI_SLAVE) flags = sdscat(flags,"slave,"); 2379 if (ri->flags & SRI_SENTINEL) flags = sdscat(flags,"sentinel,"); 2380 if (ri->flags & SRI_DISCONNECTED) flags = sdscat(flags,"disconnected,"); 2381 if (ri->flags & SRI_MASTER_DOWN) flags = sdscat(flags,"master_down,"); 2382 if (ri->flags & SRI_FAILOVER_IN_PROGRESS) 2383 flags = sdscat(flags,"failover_in_progress,"); 2384 if (ri->flags & SRI_PROMOTED) flags = sdscat(flags,"promoted,"); 2385 if (ri->flags & SRI_RECONF_SENT) flags = sdscat(flags,"reconf_sent,"); 2386 if (ri->flags & SRI_RECONF_INPROG) flags = sdscat(flags,"reconf_inprog,"); 2387 if (ri->flags & SRI_RECONF_DONE) flags = sdscat(flags,"reconf_done,"); 2388 2389 if (sdslen(flags) != 0) sdsrange(flags,0,-2); /* remove last "," */ 2390 addReplyBulkCString(c,flags); 2391 sdsfree(flags); 2392 fields++; 2393 2394 addReplyBulkCString(c,"pending-commands"); 2395 addReplyBulkLongLong(c,ri->pending_commands); 2396 fields++; 2397 2398 if (ri->flags & SRI_FAILOVER_IN_PROGRESS) { 2399 addReplyBulkCString(c,"failover-state"); 2400 addReplyBulkCString(c,(char*)sentinelFailoverStateStr(ri->failover_state)); 2401 fields++; 2402 } 2403 2404 addReplyBulkCString(c,"last-ping-sent"); 2405 addReplyBulkLongLong(c, 2406 ri->last_ping_time ? (mstime() - ri->last_ping_time) : 0); 2407 fields++; 2408 2409 addReplyBulkCString(c,"last-ok-ping-reply"); 2410 addReplyBulkLongLong(c,mstime() - ri->last_avail_time); 2411 fields++; 2412 2413 addReplyBulkCString(c,"last-ping-reply"); 2414 addReplyBulkLongLong(c,mstime() - ri->last_pong_time); 2415 fields++; 2416 2417 if (ri->flags & SRI_S_DOWN) { 2418 addReplyBulkCString(c,"s-down-time"); 2419 addReplyBulkLongLong(c,mstime()-ri->s_down_since_time); 2420 fields++; 2421 } 2422 2423 if (ri->flags & SRI_O_DOWN) { 2424 addReplyBulkCString(c,"o-down-time"); 2425 addReplyBulkLongLong(c,mstime()-ri->o_down_since_time); 2426 fields++; 2427 } 2428 2429 addReplyBulkCString(c,"down-after-milliseconds"); 2430 addReplyBulkLongLong(c,ri->down_after_period); 2431 fields++; 2432 2433 /* Masters and Slaves */ 2434 if (ri->flags & (SRI_MASTER|SRI_SLAVE)) { 2435 addReplyBulkCString(c,"info-refresh"); 2436 addReplyBulkLongLong(c,mstime() - ri->info_refresh); 2437 fields++; 2438 2439 addReplyBulkCString(c,"role-reported"); 2440 addReplyBulkCString(c, (ri->role_reported == SRI_MASTER) ? "master" : 2441 "slave"); 2442 fields++; 2443 2444 addReplyBulkCString(c,"role-reported-time"); 2445 addReplyBulkLongLong(c,mstime() - ri->role_reported_time); 2446 fields++; 2447 } 2448 2449 /* Only masters */ 2450 if (ri->flags & SRI_MASTER) { 2451 addReplyBulkCString(c,"config-epoch"); 2452 addReplyBulkLongLong(c,ri->config_epoch); 2453 fields++; 2454 2455 addReplyBulkCString(c,"num-slaves"); 2456 addReplyBulkLongLong(c,dictSize(ri->slaves)); 2457 fields++; 2458 2459 addReplyBulkCString(c,"num-other-sentinels"); 2460 addReplyBulkLongLong(c,dictSize(ri->sentinels)); 2461 fields++; 2462 2463 addReplyBulkCString(c,"quorum"); 2464 addReplyBulkLongLong(c,ri->quorum); 2465 fields++; 2466 2467 addReplyBulkCString(c,"failover-timeout"); 2468 addReplyBulkLongLong(c,ri->failover_timeout); 2469 fields++; 2470 2471 addReplyBulkCString(c,"parallel-syncs"); 2472 addReplyBulkLongLong(c,ri->parallel_syncs); 2473 fields++; 2474 2475 if (ri->notification_script) { 2476 addReplyBulkCString(c,"notification-script"); 2477 addReplyBulkCString(c,ri->notification_script); 2478 fields++; 2479 } 2480 2481 if (ri->client_reconfig_script) { 2482 addReplyBulkCString(c,"client-reconfig-script"); 2483 addReplyBulkCString(c,ri->client_reconfig_script); 2484 fields++; 2485 } 2486 } 2487 2488 /* Only slaves */ 2489 if (ri->flags & SRI_SLAVE) { 2490 addReplyBulkCString(c,"master-link-down-time"); 2491 addReplyBulkLongLong(c,ri->master_link_down_time); 2492 fields++; 2493 2494 addReplyBulkCString(c,"master-link-status"); 2495 addReplyBulkCString(c, 2496 (ri->slave_master_link_status == SENTINEL_MASTER_LINK_STATUS_UP) ? 2497 "ok" : "err"); 2498 fields++; 2499 2500 addReplyBulkCString(c,"master-host"); 2501 addReplyBulkCString(c, 2502 ri->slave_master_host ? ri->slave_master_host : "?"); 2503 fields++; 2504 2505 addReplyBulkCString(c,"master-port"); 2506 addReplyBulkLongLong(c,ri->slave_master_port); 2507 fields++; 2508 2509 addReplyBulkCString(c,"slave-priority"); 2510 addReplyBulkLongLong(c,ri->slave_priority); 2511 fields++; 2512 2513 addReplyBulkCString(c,"slave-repl-offset"); 2514 addReplyBulkLongLong(c,ri->slave_repl_offset); 2515 fields++; 2516 } 2517 2518 /* Only sentinels */ 2519 if (ri->flags & SRI_SENTINEL) { 2520 addReplyBulkCString(c,"last-hello-message"); 2521 addReplyBulkLongLong(c,mstime() - ri->last_hello_time); 2522 fields++; 2523 2524 addReplyBulkCString(c,"voted-leader"); 2525 addReplyBulkCString(c,ri->leader ? ri->leader : "?"); 2526 fields++; 2527 2528 addReplyBulkCString(c,"voted-leader-epoch"); 2529 addReplyBulkLongLong(c,ri->leader_epoch); 2530 fields++; 2531 } 2532 2533 setDeferredMultiBulkLength(c,mbl,fields*2); 2534 } 2535 2536 /* Output a number of instances contained inside a dictionary as 2537 * Redis protocol. */ 2538 void addReplyDictOfRedisInstances(redisClient *c, dict *instances) { 2539 dictIterator *di; 2540 dictEntry *de; 2541 2542 di = dictGetIterator(instances); 2543 addReplyMultiBulkLen(c,dictSize(instances)); 2544 while((de = dictNext(di)) != NULL) { 2545 sentinelRedisInstance *ri = dictGetVal(de); 2546 2547 addReplySentinelRedisInstance(c,ri); 2548 } 2549 dictReleaseIterator(di); 2550 } 2551 2552 /* Lookup the named master into sentinel.masters. 2553 * If the master is not found reply to the client with an error and returns 2554 * NULL. */ 2555 sentinelRedisInstance *sentinelGetMasterByNameOrReplyError(redisClient *c, 2556 robj *name) 2557 { 2558 sentinelRedisInstance *ri; 2559 2560 ri = dictFetchValue(sentinel.masters,c->argv[2]->ptr); 2561 if (!ri) { 2562 addReplyError(c,"No such master with that name"); 2563 return NULL; 2564 } 2565 return ri; 2566 } 2567 2568 void sentinelCommand(redisClient *c) { 2569 if (!strcasecmp(c->argv[1]->ptr,"masters")) { 2570 /* SENTINEL MASTERS */ 2571 if (c->argc != 2) goto numargserr; 2572 addReplyDictOfRedisInstances(c,sentinel.masters); 2573 } else if (!strcasecmp(c->argv[1]->ptr,"master")) { 2574 /* SENTINEL MASTER <name> */ 2575 sentinelRedisInstance *ri; 2576 2577 if (c->argc != 3) goto numargserr; 2578 if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2])) 2579 == NULL) return; 2580 addReplySentinelRedisInstance(c,ri); 2581 } else if (!strcasecmp(c->argv[1]->ptr,"slaves")) { 2582 /* SENTINEL SLAVES <master-name> */ 2583 sentinelRedisInstance *ri; 2584 2585 if (c->argc != 3) goto numargserr; 2586 if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2])) == NULL) 2587 return; 2588 addReplyDictOfRedisInstances(c,ri->slaves); 2589 } else if (!strcasecmp(c->argv[1]->ptr,"sentinels")) { 2590 /* SENTINEL SENTINELS <master-name> */ 2591 sentinelRedisInstance *ri; 2592 2593 if (c->argc != 3) goto numargserr; 2594 if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2])) == NULL) 2595 return; 2596 addReplyDictOfRedisInstances(c,ri->sentinels); 2597 } else if (!strcasecmp(c->argv[1]->ptr,"is-master-down-by-addr")) { 2598 /* SENTINEL IS-MASTER-DOWN-BY-ADDR <ip> <port> <current-epoch> <runid>*/ 2599 sentinelRedisInstance *ri; 2600 long long req_epoch; 2601 uint64_t leader_epoch = 0; 2602 char *leader = NULL; 2603 long port; 2604 int isdown = 0; 2605 2606 if (c->argc != 6) goto numargserr; 2607 if (getLongFromObjectOrReply(c,c->argv[3],&port,NULL) != REDIS_OK || 2608 getLongLongFromObjectOrReply(c,c->argv[4],&req_epoch,NULL) 2609 != REDIS_OK) 2610 return; 2611 ri = getSentinelRedisInstanceByAddrAndRunID(sentinel.masters, 2612 c->argv[2]->ptr,port,NULL); 2613 2614 /* It exists? Is actually a master? Is subjectively down? It's down. 2615 * Note: if we are in tilt mode we always reply with "0". */ 2616 if (!sentinel.tilt && ri && (ri->flags & SRI_S_DOWN) && 2617 (ri->flags & SRI_MASTER)) 2618 isdown = 1; 2619 2620 /* Vote for the master (or fetch the previous vote) if the request 2621 * includes a runid, otherwise the sender is not seeking for a vote. */ 2622 if (ri && ri->flags & SRI_MASTER && strcasecmp(c->argv[5]->ptr,"*")) { 2623 leader = sentinelVoteLeader(ri,(uint64_t)req_epoch, 2624 c->argv[5]->ptr, 2625 &leader_epoch); 2626 } 2627 2628 /* Reply with a three-elements multi-bulk reply: 2629 * down state, leader, vote epoch. */ 2630 addReplyMultiBulkLen(c,3); 2631 addReply(c, isdown ? shared.cone : shared.czero); 2632 addReplyBulkCString(c, leader ? leader : "*"); 2633 addReplyLongLong(c, (long long)leader_epoch); 2634 if (leader) sdsfree(leader); 2635 } else if (!strcasecmp(c->argv[1]->ptr,"reset")) { 2636 /* SENTINEL RESET <pattern> */ 2637 if (c->argc != 3) goto numargserr; 2638 addReplyLongLong(c,sentinelResetMastersByPattern(c->argv[2]->ptr,SENTINEL_GENERATE_EVENT)); 2639 } else if (!strcasecmp(c->argv[1]->ptr,"get-master-addr-by-name")) { 2640 /* SENTINEL GET-MASTER-ADDR-BY-NAME <master-name> */ 2641 sentinelRedisInstance *ri; 2642 2643 if (c->argc != 3) goto numargserr; 2644 ri = sentinelGetMasterByName(c->argv[2]->ptr); 2645 if (ri == NULL) { 2646 addReply(c,shared.nullmultibulk); 2647 } else { 2648 sentinelAddr *addr = sentinelGetCurrentMasterAddress(ri); 2649 2650 addReplyMultiBulkLen(c,2); 2651 addReplyBulkCString(c,addr->ip); 2652 addReplyBulkLongLong(c,addr->port); 2653 } 2654 } else if (!strcasecmp(c->argv[1]->ptr,"failover")) { 2655 /* SENTINEL FAILOVER <master-name> */ 2656 sentinelRedisInstance *ri; 2657 2658 if (c->argc != 3) goto numargserr; 2659 if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2])) == NULL) 2660 return; 2661 if (ri->flags & SRI_FAILOVER_IN_PROGRESS) { 2662 addReplySds(c,sdsnew("-INPROG Failover already in progress\r\n")); 2663 return; 2664 } 2665 if (sentinelSelectSlave(ri) == NULL) { 2666 addReplySds(c,sdsnew("-NOGOODSLAVE No suitable slave to promote\r\n")); 2667 return; 2668 } 2669 redisLog(REDIS_WARNING,"Executing user requested FAILOVER of '%s'", 2670 ri->name); 2671 sentinelStartFailover(ri); 2672 ri->flags |= SRI_FORCE_FAILOVER; 2673 addReply(c,shared.ok); 2674 } else if (!strcasecmp(c->argv[1]->ptr,"pending-scripts")) { 2675 /* SENTINEL PENDING-SCRIPTS */ 2676 2677 if (c->argc != 2) goto numargserr; 2678 sentinelPendingScriptsCommand(c); 2679 } else if (!strcasecmp(c->argv[1]->ptr,"monitor")) { 2680 /* SENTINEL MONITOR <name> <ip> <port> <quorum> */ 2681 sentinelRedisInstance *ri; 2682 long quorum, port; 2683 char buf[32]; 2684 2685 if (c->argc != 6) goto numargserr; 2686 if (getLongFromObjectOrReply(c,c->argv[5],&quorum,"Invalid quorum") 2687 != REDIS_OK) return; 2688 if (getLongFromObjectOrReply(c,c->argv[4],&port,"Invalid port") 2689 != REDIS_OK) return; 2690 /* Make sure the IP field is actually a valid IP before passing it 2691 * to createSentinelRedisInstance(), otherwise we may trigger a 2692 * DNS lookup at runtime. */ 2693 if (anetResolveIP(NULL,c->argv[3]->ptr,buf,sizeof(buf)) == ANET_ERR) { 2694 addReplyError(c,"Invalid IP address specified"); 2695 return; 2696 } 2697 2698 /* Parameters are valid. Try to create the master instance. */ 2699 ri = createSentinelRedisInstance(c->argv[2]->ptr,SRI_MASTER, 2700 c->argv[3]->ptr,port,quorum,NULL); 2701 if (ri == NULL) { 2702 switch(errno) { 2703 case EBUSY: 2704 addReplyError(c,"Duplicated master name"); 2705 break; 2706 case EINVAL: 2707 addReplyError(c,"Invalid port number"); 2708 break; 2709 default: 2710 addReplyError(c,"Unspecified error adding the instance"); 2711 break; 2712 } 2713 } else { 2714 sentinelFlushConfig(); 2715 sentinelEvent(REDIS_WARNING,"+monitor",ri,"%@ quorum %d",ri->quorum); 2716 addReply(c,shared.ok); 2717 } 2718 } else if (!strcasecmp(c->argv[1]->ptr,"remove")) { 2719 /* SENTINEL REMOVE <name> */ 2720 sentinelRedisInstance *ri; 2721 2722 if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2])) 2723 == NULL) return; 2724 sentinelEvent(REDIS_WARNING,"-monitor",ri,"%@"); 2725 dictDelete(sentinel.masters,c->argv[2]->ptr); 2726 sentinelFlushConfig(); 2727 addReply(c,shared.ok); 2728 } else if (!strcasecmp(c->argv[1]->ptr,"set")) { 2729 if (c->argc < 3 || c->argc % 2 == 0) goto numargserr; 2730 sentinelSetCommand(c); 2731 } else { 2732 addReplyErrorFormat(c,"Unknown sentinel subcommand '%s'", 2733 (char*)c->argv[1]->ptr); 2734 } 2735 return; 2736 2737 numargserr: 2738 addReplyErrorFormat(c,"Wrong number of arguments for 'sentinel %s'", 2739 (char*)c->argv[1]->ptr); 2740 } 2741 2742 /* SENTINEL INFO [section] */ 2743 void sentinelInfoCommand(redisClient *c) { 2744 char *section = c->argc == 2 ? c->argv[1]->ptr : "default"; 2745 sds info = sdsempty(); 2746 int defsections = !strcasecmp(section,"default"); 2747 int sections = 0; 2748 2749 if (c->argc > 2) { 2750 addReply(c,shared.syntaxerr); 2751 return; 2752 } 2753 2754 if (!strcasecmp(section,"server") || defsections) { 2755 if (sections++) info = sdscat(info,"\r\n"); 2756 sds serversection = genRedisInfoString("server"); 2757 info = sdscatlen(info,serversection,sdslen(serversection)); 2758 sdsfree(serversection); 2759 } 2760 2761 if (!strcasecmp(section,"sentinel") || defsections) { 2762 dictIterator *di; 2763 dictEntry *de; 2764 int master_id = 0; 2765 2766 if (sections++) info = sdscat(info,"\r\n"); 2767 info = sdscatprintf(info, 2768 "# Sentinel\r\n" 2769 "sentinel_masters:%lu\r\n" 2770 "sentinel_tilt:%d\r\n" 2771 "sentinel_running_scripts:%d\r\n" 2772 "sentinel_scripts_queue_length:%ld\r\n", 2773 dictSize(sentinel.masters), 2774 sentinel.tilt, 2775 sentinel.running_scripts, 2776 listLength(sentinel.scripts_queue)); 2777 2778 di = dictGetIterator(sentinel.masters); 2779 while((de = dictNext(di)) != NULL) { 2780 sentinelRedisInstance *ri = dictGetVal(de); 2781 char *status = "ok"; 2782 2783 if (ri->flags & SRI_O_DOWN) status = "odown"; 2784 else if (ri->flags & SRI_S_DOWN) status = "sdown"; 2785 info = sdscatprintf(info, 2786 "master%d:name=%s,status=%s,address=%s:%d," 2787 "slaves=%lu,sentinels=%lu\r\n", 2788 master_id++, ri->name, status, 2789 ri->addr->ip, ri->addr->port, 2790 dictSize(ri->slaves), 2791 dictSize(ri->sentinels)+1); 2792 } 2793 dictReleaseIterator(di); 2794 } 2795 2796 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n", 2797 (unsigned long)sdslen(info))); 2798 addReplySds(c,info); 2799 addReply(c,shared.crlf); 2800 } 2801 2802 /* SENTINEL SET <mastername> [<option> <value> ...] */ 2803 void sentinelSetCommand(redisClient *c) { 2804 sentinelRedisInstance *ri; 2805 int j, changes = 0; 2806 char *option, *value; 2807 2808 if ((ri = sentinelGetMasterByNameOrReplyError(c,c->argv[2])) 2809 == NULL) return; 2810 2811 /* Process option - value pairs. */ 2812 for (j = 3; j < c->argc; j += 2) { 2813 option = c->argv[j]->ptr; 2814 value = c->argv[j+1]->ptr; 2815 robj *o = c->argv[j+1]; 2816 long long ll; 2817 2818 if (!strcasecmp(option,"down-after-milliseconds")) { 2819 /* down-after-millisecodns <milliseconds> */ 2820 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll <= 0) 2821 goto badfmt; 2822 ri->down_after_period = ll; 2823 sentinelPropagateDownAfterPeriod(ri); 2824 changes++; 2825 } else if (!strcasecmp(option,"failover-timeout")) { 2826 /* failover-timeout <milliseconds> */ 2827 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll <= 0) 2828 goto badfmt; 2829 ri->failover_timeout = ll; 2830 changes++; 2831 } else if (!strcasecmp(option,"parallel-syncs")) { 2832 /* parallel-syncs <milliseconds> */ 2833 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll <= 0) 2834 goto badfmt; 2835 ri->parallel_syncs = ll; 2836 changes++; 2837 } else if (!strcasecmp(option,"notification-script")) { 2838 /* notification-script <path> */ 2839 if (strlen(value) && access(value,X_OK) == -1) { 2840 addReplyError(c, 2841 "Notification script seems non existing or non executable"); 2842 if (changes) sentinelFlushConfig(); 2843 return; 2844 } 2845 sdsfree(ri->notification_script); 2846 ri->notification_script = strlen(value) ? sdsnew(value) : NULL; 2847 changes++; 2848 } else if (!strcasecmp(option,"client-reconfig-script")) { 2849 /* client-reconfig-script <path> */ 2850 if (strlen(value) && access(value,X_OK) == -1) { 2851 addReplyError(c, 2852 "Client reconfiguration script seems non existing or " 2853 "non executable"); 2854 if (changes) sentinelFlushConfig(); 2855 return; 2856 } 2857 sdsfree(ri->client_reconfig_script); 2858 ri->client_reconfig_script = strlen(value) ? sdsnew(value) : NULL; 2859 changes++; 2860 } else if (!strcasecmp(option,"auth-pass")) { 2861 /* auth-pass <password> */ 2862 sdsfree(ri->auth_pass); 2863 ri->auth_pass = strlen(value) ? sdsnew(value) : NULL; 2864 changes++; 2865 } else if (!strcasecmp(option,"quorum")) { 2866 /* quorum <count> */ 2867 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll <= 0) 2868 goto badfmt; 2869 ri->quorum = ll; 2870 changes++; 2871 } else { 2872 addReplyErrorFormat(c,"Unknown option '%s' for SENTINEL SET", 2873 option); 2874 if (changes) sentinelFlushConfig(); 2875 return; 2876 } 2877 sentinelEvent(REDIS_WARNING,"+set",ri,"%@ %s %s",option,value); 2878 } 2879 2880 if (changes) sentinelFlushConfig(); 2881 addReply(c,shared.ok); 2882 return; 2883 2884 badfmt: /* Bad format errors */ 2885 if (changes) sentinelFlushConfig(); 2886 addReplyErrorFormat(c,"Invalid argument '%s' for SENTINEL SET '%s'", 2887 value, option); 2888 } 2889 2890 /* Our fake PUBLISH command: it is actually useful only to receive hello messages 2891 * from the other sentinel instances, and publishing to a channel other than 2892 * SENTINEL_HELLO_CHANNEL is forbidden. 2893 * 2894 * Because we have a Sentinel PUBLISH, the code to send hello messages is the same 2895 * for all the three kind of instances: masters, slaves, sentinels. */ 2896 void sentinelPublishCommand(redisClient *c) { 2897 if (strcmp(c->argv[1]->ptr,SENTINEL_HELLO_CHANNEL)) { 2898 addReplyError(c, "Only HELLO messages are accepted by Sentinel instances."); 2899 return; 2900 } 2901 sentinelProcessHelloMessage(c->argv[2]->ptr,sdslen(c->argv[2]->ptr)); 2902 addReplyLongLong(c,1); 2903 } 2904 2905 /* ===================== SENTINEL availability checks ======================= */ 2906 2907 /* Is this instance down from our point of view? */ 2908 void sentinelCheckSubjectivelyDown(sentinelRedisInstance *ri) { 2909 mstime_t elapsed = 0; 2910 2911 if (ri->last_ping_time) 2912 elapsed = mstime() - ri->last_ping_time; 2913 2914 /* Check if we are in need for a reconnection of one of the 2915 * links, because we are detecting low activity. 2916 * 2917 * 1) Check if the command link seems connected, was connected not less 2918 * than SENTINEL_MIN_LINK_RECONNECT_PERIOD, but still we have a 2919 * pending ping for more than half the timeout. */ 2920 if (ri->cc && 2921 (mstime() - ri->cc_conn_time) > SENTINEL_MIN_LINK_RECONNECT_PERIOD && 2922 ri->last_ping_time != 0 && /* Ther is a pending ping... */ 2923 /* The pending ping is delayed, and we did not received 2924 * error replies as well. */ 2925 (mstime() - ri->last_ping_time) > (ri->down_after_period/2) && 2926 (mstime() - ri->last_pong_time) > (ri->down_after_period/2)) 2927 { 2928 sentinelKillLink(ri,ri->cc); 2929 } 2930 2931 /* 2) Check if the pubsub link seems connected, was connected not less 2932 * than SENTINEL_MIN_LINK_RECONNECT_PERIOD, but still we have no 2933 * activity in the Pub/Sub channel for more than 2934 * SENTINEL_PUBLISH_PERIOD * 3. 2935 */ 2936 if (ri->pc && 2937 (mstime() - ri->pc_conn_time) > SENTINEL_MIN_LINK_RECONNECT_PERIOD && 2938 (mstime() - ri->pc_last_activity) > (SENTINEL_PUBLISH_PERIOD*3)) 2939 { 2940 sentinelKillLink(ri,ri->pc); 2941 } 2942 2943 /* Update the SDOWN flag. We believe the instance is SDOWN if: 2944 * 2945 * 1) It is not replying. 2946 * 2) We believe it is a master, it reports to be a slave for enough time 2947 * to meet the down_after_period, plus enough time to get two times 2948 * INFO report from the instance. */ 2949 if (elapsed > ri->down_after_period || 2950 (ri->flags & SRI_MASTER && 2951 ri->role_reported == SRI_SLAVE && 2952 mstime() - ri->role_reported_time > 2953 (ri->down_after_period+SENTINEL_INFO_PERIOD*2))) 2954 { 2955 /* Is subjectively down */ 2956 if ((ri->flags & SRI_S_DOWN) == 0) { 2957 sentinelEvent(REDIS_WARNING,"+sdown",ri,"%@"); 2958 ri->s_down_since_time = mstime(); 2959 ri->flags |= SRI_S_DOWN; 2960 } 2961 } else { 2962 /* Is subjectively up */ 2963 if (ri->flags & SRI_S_DOWN) { 2964 sentinelEvent(REDIS_WARNING,"-sdown",ri,"%@"); 2965 ri->flags &= ~(SRI_S_DOWN|SRI_SCRIPT_KILL_SENT); 2966 } 2967 } 2968 } 2969 2970 /* Is this instance down according to the configured quorum? 2971 * 2972 * Note that ODOWN is a weak quorum, it only means that enough Sentinels 2973 * reported in a given time range that the instance was not reachable. 2974 * However messages can be delayed so there are no strong guarantees about 2975 * N instances agreeing at the same time about the down state. */ 2976 void sentinelCheckObjectivelyDown(sentinelRedisInstance *master) { 2977 dictIterator *di; 2978 dictEntry *de; 2979 int quorum = 0, odown = 0; 2980 2981 if (master->flags & SRI_S_DOWN) { 2982 /* Is down for enough sentinels? */ 2983 quorum = 1; /* the current sentinel. */ 2984 /* Count all the other sentinels. */ 2985 di = dictGetIterator(master->sentinels); 2986 while((de = dictNext(di)) != NULL) { 2987 sentinelRedisInstance *ri = dictGetVal(de); 2988 2989 if (ri->flags & SRI_MASTER_DOWN) quorum++; 2990 } 2991 dictReleaseIterator(di); 2992 if (quorum >= master->quorum) odown = 1; 2993 } 2994 2995 /* Set the flag accordingly to the outcome. */ 2996 if (odown) { 2997 if ((master->flags & SRI_O_DOWN) == 0) { 2998 sentinelEvent(REDIS_WARNING,"+odown",master,"%@ #quorum %d/%d", 2999 quorum, master->quorum); 3000 master->flags |= SRI_O_DOWN; 3001 master->o_down_since_time = mstime(); 3002 } 3003 } else { 3004 if (master->flags & SRI_O_DOWN) { 3005 sentinelEvent(REDIS_WARNING,"-odown",master,"%@"); 3006 master->flags &= ~SRI_O_DOWN; 3007 } 3008 } 3009 } 3010 3011 /* Receive the SENTINEL is-master-down-by-addr reply, see the 3012 * sentinelAskMasterStateToOtherSentinels() function for more information. */ 3013 void sentinelReceiveIsMasterDownReply(redisAsyncContext *c, void *reply, void *privdata) { 3014 sentinelRedisInstance *ri = c->data; 3015 redisReply *r; 3016 3017 if (ri) ri->pending_commands--; 3018 if (!reply || !ri) return; 3019 r = reply; 3020 3021 /* Ignore every error or unexpected reply. 3022 * Note that if the command returns an error for any reason we'll 3023 * end clearing the SRI_MASTER_DOWN flag for timeout anyway. */ 3024 if (r->type == REDIS_REPLY_ARRAY && r->elements == 3 && 3025 r->element[0]->type == REDIS_REPLY_INTEGER && 3026 r->element[1]->type == REDIS_REPLY_STRING && 3027 r->element[2]->type == REDIS_REPLY_INTEGER) 3028 { 3029 ri->last_master_down_reply_time = mstime(); 3030 if (r->element[0]->integer == 1) { 3031 ri->flags |= SRI_MASTER_DOWN; 3032 } else { 3033 ri->flags &= ~SRI_MASTER_DOWN; 3034 } 3035 if (strcmp(r->element[1]->str,"*")) { 3036 /* If the runid in the reply is not "*" the Sentinel actually 3037 * replied with a vote. */ 3038 sdsfree(ri->leader); 3039 if (ri->leader_epoch != r->element[2]->integer) 3040 redisLog(REDIS_WARNING, 3041 "%s voted for %s %llu", ri->name, 3042 r->element[1]->str, 3043 (unsigned long long) r->element[2]->integer); 3044 ri->leader = sdsnew(r->element[1]->str); 3045 ri->leader_epoch = r->element[2]->integer; 3046 } 3047 } 3048 } 3049 3050 /* If we think the master is down, we start sending 3051 * SENTINEL IS-MASTER-DOWN-BY-ADDR requests to other sentinels 3052 * in order to get the replies that allow to reach the quorum 3053 * needed to mark the master in ODOWN state and trigger a failover. */ 3054 #define SENTINEL_ASK_FORCED (1<<0) 3055 void sentinelAskMasterStateToOtherSentinels(sentinelRedisInstance *master, int flags) { 3056 dictIterator *di; 3057 dictEntry *de; 3058 3059 di = dictGetIterator(master->sentinels); 3060 while((de = dictNext(di)) != NULL) { 3061 sentinelRedisInstance *ri = dictGetVal(de); 3062 mstime_t elapsed = mstime() - ri->last_master_down_reply_time; 3063 char port[32]; 3064 int retval; 3065 3066 /* If the master state from other sentinel is too old, we clear it. */ 3067 if (elapsed > SENTINEL_ASK_PERIOD*5) { 3068 ri->flags &= ~SRI_MASTER_DOWN; 3069 sdsfree(ri->leader); 3070 ri->leader = NULL; 3071 } 3072 3073 /* Only ask if master is down to other sentinels if: 3074 * 3075 * 1) We believe it is down, or there is a failover in progress. 3076 * 2) Sentinel is connected. 3077 * 3) We did not received the info within SENTINEL_ASK_PERIOD ms. */ 3078 if ((master->flags & SRI_S_DOWN) == 0) continue; 3079 if (ri->flags & SRI_DISCONNECTED) continue; 3080 if (!(flags & SENTINEL_ASK_FORCED) && 3081 mstime() - ri->last_master_down_reply_time < SENTINEL_ASK_PERIOD) 3082 continue; 3083 3084 /* Ask */ 3085 ll2string(port,sizeof(port),master->addr->port); 3086 retval = redisAsyncCommand(ri->cc, 3087 sentinelReceiveIsMasterDownReply, NULL, 3088 "SENTINEL is-master-down-by-addr %s %s %llu %s", 3089 master->addr->ip, port, 3090 sentinel.current_epoch, 3091 (master->failover_state > SENTINEL_FAILOVER_STATE_NONE) ? 3092 server.runid : "*"); 3093 if (retval == REDIS_OK) ri->pending_commands++; 3094 } 3095 dictReleaseIterator(di); 3096 } 3097 3098 /* =============================== FAILOVER ================================= */ 3099 3100 /* Vote for the sentinel with 'req_runid' or return the old vote if already 3101 * voted for the specifed 'req_epoch' or one greater. 3102 * 3103 * If a vote is not available returns NULL, otherwise return the Sentinel 3104 * runid and populate the leader_epoch with the epoch of the vote. */ 3105 char *sentinelVoteLeader(sentinelRedisInstance *master, uint64_t req_epoch, char *req_runid, uint64_t *leader_epoch) { 3106 if (req_epoch > sentinel.current_epoch) { 3107 sentinel.current_epoch = req_epoch; 3108 sentinelFlushConfig(); 3109 sentinelEvent(REDIS_WARNING,"+new-epoch",master,"%llu", 3110 (unsigned long long) sentinel.current_epoch); 3111 } 3112 3113 if (master->leader_epoch < req_epoch && sentinel.current_epoch <= req_epoch) 3114 { 3115 sdsfree(master->leader); 3116 master->leader = sdsnew(req_runid); 3117 master->leader_epoch = sentinel.current_epoch; 3118 sentinelFlushConfig(); 3119 sentinelEvent(REDIS_WARNING,"+vote-for-leader",master,"%s %llu", 3120 master->leader, (unsigned long long) master->leader_epoch); 3121 /* If we did not voted for ourselves, set the master failover start 3122 * time to now, in order to force a delay before we can start a 3123 * failover for the same master. */ 3124 if (strcasecmp(master->leader,server.runid)) 3125 master->failover_start_time = mstime()+rand()%SENTINEL_MAX_DESYNC; 3126 } 3127 3128 *leader_epoch = master->leader_epoch; 3129 return master->leader ? sdsnew(master->leader) : NULL; 3130 } 3131 3132 struct sentinelLeader { 3133 char *runid; 3134 unsigned long votes; 3135 }; 3136 3137 /* Helper function for sentinelGetLeader, increment the counter 3138 * relative to the specified runid. */ 3139 int sentinelLeaderIncr(dict *counters, char *runid) { 3140 dictEntry *de = dictFind(counters,runid); 3141 uint64_t oldval; 3142 3143 if (de) { 3144 oldval = dictGetUnsignedIntegerVal(de); 3145 dictSetUnsignedIntegerVal(de,oldval+1); 3146 return oldval+1; 3147 } else { 3148 de = dictAddRaw(counters,runid); 3149 redisAssert(de != NULL); 3150 dictSetUnsignedIntegerVal(de,1); 3151 return 1; 3152 } 3153 } 3154 3155 /* Scan all the Sentinels attached to this master to check if there 3156 * is a leader for the specified epoch. 3157 * 3158 * To be a leader for a given epoch, we should have the majorify of 3159 * the Sentinels we know that reported the same instance as 3160 * leader for the same epoch. */ 3161 char *sentinelGetLeader(sentinelRedisInstance *master, uint64_t epoch) { 3162 dict *counters; 3163 dictIterator *di; 3164 dictEntry *de; 3165 unsigned int voters = 0, voters_quorum; 3166 char *myvote; 3167 char *winner = NULL; 3168 uint64_t leader_epoch; 3169 uint64_t max_votes = 0; 3170 3171 redisAssert(master->flags & (SRI_O_DOWN|SRI_FAILOVER_IN_PROGRESS)); 3172 counters = dictCreate(&leaderVotesDictType,NULL); 3173 3174 /* Count other sentinels votes */ 3175 di = dictGetIterator(master->sentinels); 3176 while((de = dictNext(di)) != NULL) { 3177 sentinelRedisInstance *ri = dictGetVal(de); 3178 if (ri->leader != NULL && ri->leader_epoch == sentinel.current_epoch) 3179 sentinelLeaderIncr(counters,ri->leader); 3180 voters++; 3181 } 3182 dictReleaseIterator(di); 3183 3184 /* Check what's the winner. For the winner to win, it needs two conditions: 3185 * 1) Absolute majority between voters (50% + 1). 3186 * 2) And anyway at least master->quorum votes. */ 3187 di = dictGetIterator(counters); 3188 while((de = dictNext(di)) != NULL) { 3189 uint64_t votes = dictGetUnsignedIntegerVal(de); 3190 3191 if (votes > max_votes) { 3192 max_votes = votes; 3193 winner = dictGetKey(de); 3194 } 3195 } 3196 dictReleaseIterator(di); 3197 3198 /* Count this Sentinel vote: 3199 * if this Sentinel did not voted yet, either vote for the most 3200 * common voted sentinel, or for itself if no vote exists at all. */ 3201 if (winner) 3202 myvote = sentinelVoteLeader(master,epoch,winner,&leader_epoch); 3203 else 3204 myvote = sentinelVoteLeader(master,epoch,server.runid,&leader_epoch); 3205 3206 if (myvote && leader_epoch == epoch) { 3207 uint64_t votes = sentinelLeaderIncr(counters,myvote); 3208 3209 if (votes > max_votes) { 3210 max_votes = votes; 3211 winner = myvote; 3212 } 3213 } 3214 voters++; /* Anyway, count me as one of the voters. */ 3215 3216 voters_quorum = voters/2+1; 3217 if (winner && (max_votes < voters_quorum || max_votes < master->quorum)) 3218 winner = NULL; 3219 3220 winner = winner ? sdsnew(winner) : NULL; 3221 sdsfree(myvote); 3222 dictRelease(counters); 3223 return winner; 3224 } 3225 3226 /* Send SLAVEOF to the specified instance, always followed by a 3227 * CONFIG REWRITE command in order to store the new configuration on disk 3228 * when possible (that is, if the Redis instance is recent enough to support 3229 * config rewriting, and if the server was started with a configuration file). 3230 * 3231 * If Host is NULL the function sends "SLAVEOF NO ONE". 3232 * 3233 * The command returns REDIS_OK if the SLAVEOF command was accepted for 3234 * (later) delivery otherwise REDIS_ERR. The command replies are just 3235 * discarded. */ 3236 int sentinelSendSlaveOf(sentinelRedisInstance *ri, char *host, int port) { 3237 char portstr[32]; 3238 int retval; 3239 3240 ll2string(portstr,sizeof(portstr),port); 3241 3242 /* If host is NULL we send SLAVEOF NO ONE that will turn the instance 3243 * into a master. */ 3244 if (host == NULL) { 3245 host = "NO"; 3246 memcpy(portstr,"ONE",4); 3247 } 3248 3249 /* In order to send SLAVEOF in a safe way, we send a transaction performing 3250 * the following tasks: 3251 * 1) Reconfigure the instance according to the specified host/port params. 3252 * 2) Rewrite the configuraiton. 3253 * 3) Disconnect all clients (but this one sending the commnad) in order 3254 * to trigger the ask-master-on-reconnection protocol for connected 3255 * clients. 3256 * 3257 * Note that we don't check the replies returned by commands, since we 3258 * will observe instead the effects in the next INFO output. */ 3259 retval = redisAsyncCommand(ri->cc, 3260 sentinelDiscardReplyCallback, NULL, "MULTI"); 3261 if (retval == REDIS_ERR) return retval; 3262 ri->pending_commands++; 3263 3264 retval = redisAsyncCommand(ri->cc, 3265 sentinelDiscardReplyCallback, NULL, "SLAVEOF %s %s", host, portstr); 3266 if (retval == REDIS_ERR) return retval; 3267 ri->pending_commands++; 3268 3269 retval = redisAsyncCommand(ri->cc, 3270 sentinelDiscardReplyCallback, NULL, "CONFIG REWRITE"); 3271 if (retval == REDIS_ERR) return retval; 3272 ri->pending_commands++; 3273 3274 /* CLIENT KILL TYPE <type> is only supported starting from Redis 2.8.12, 3275 * however sending it to an instance not understanding this command is not 3276 * an issue because CLIENT is variadic command, so Redis will not 3277 * recognized as a syntax error, and the transaction will not fail (but 3278 * only the unsupported command will fail). */ 3279 retval = redisAsyncCommand(ri->cc, 3280 sentinelDiscardReplyCallback, NULL, "CLIENT KILL TYPE normal"); 3281 if (retval == REDIS_ERR) return retval; 3282 ri->pending_commands++; 3283 3284 retval = redisAsyncCommand(ri->cc, 3285 sentinelDiscardReplyCallback, NULL, "EXEC"); 3286 if (retval == REDIS_ERR) return retval; 3287 ri->pending_commands++; 3288 3289 return REDIS_OK; 3290 } 3291 3292 /* Setup the master state to start a failover. */ 3293 void sentinelStartFailover(sentinelRedisInstance *master) { 3294 redisAssert(master->flags & SRI_MASTER); 3295 3296 master->failover_state = SENTINEL_FAILOVER_STATE_WAIT_START; 3297 master->flags |= SRI_FAILOVER_IN_PROGRESS; 3298 master->failover_epoch = ++sentinel.current_epoch; 3299 sentinelEvent(REDIS_WARNING,"+new-epoch",master,"%llu", 3300 (unsigned long long) sentinel.current_epoch); 3301 sentinelEvent(REDIS_WARNING,"+try-failover",master,"%@"); 3302 master->failover_start_time = mstime()+rand()%SENTINEL_MAX_DESYNC; 3303 master->failover_state_change_time = mstime(); 3304 } 3305 3306 /* This function checks if there are the conditions to start the failover, 3307 * that is: 3308 * 3309 * 1) Master must be in ODOWN condition. 3310 * 2) No failover already in progress. 3311 * 3) No failover already attempted recently. 3312 * 3313 * We still don't know if we'll win the election so it is possible that we 3314 * start the failover but that we'll not be able to act. 3315 * 3316 * Return non-zero if a failover was started. */ 3317 int sentinelStartFailoverIfNeeded(sentinelRedisInstance *master) { 3318 /* We can't failover if the master is not in O_DOWN state. */ 3319 if (!(master->flags & SRI_O_DOWN)) return 0; 3320 3321 /* Failover already in progress? */ 3322 if (master->flags & SRI_FAILOVER_IN_PROGRESS) return 0; 3323 3324 /* Last failover attempt started too little time ago? */ 3325 if (mstime() - master->failover_start_time < 3326 master->failover_timeout*2) 3327 { 3328 if (master->failover_delay_logged != master->failover_start_time) { 3329 time_t clock = (master->failover_start_time + 3330 master->failover_timeout*2) / 1000; 3331 char ctimebuf[26]; 3332 3333 ctime_r(&clock,ctimebuf); 3334 ctimebuf[24] = '\0'; /* Remove newline. */ 3335 master->failover_delay_logged = master->failover_start_time; 3336 redisLog(REDIS_WARNING, 3337 "Next failover delay: I will not start a failover before %s", 3338 ctimebuf); 3339 } 3340 return 0; 3341 } 3342 3343 sentinelStartFailover(master); 3344 return 1; 3345 } 3346 3347 /* Select a suitable slave to promote. The current algorithm only uses 3348 * the following parameters: 3349 * 3350 * 1) None of the following conditions: S_DOWN, O_DOWN, DISCONNECTED. 3351 * 2) Last time the slave replied to ping no more than 5 times the PING period. 3352 * 3) info_refresh not older than 3 times the INFO refresh period. 3353 * 4) master_link_down_time no more than: 3354 * (now - master->s_down_since_time) + (master->down_after_period * 10). 3355 * Basically since the master is down from our POV, the slave reports 3356 * to be disconnected no more than 10 times the configured down-after-period. 3357 * This is pretty much black magic but the idea is, the master was not 3358 * available so the slave may be lagging, but not over a certain time. 3359 * Anyway we'll select the best slave according to replication offset. 3360 * 5) Slave priority can't be zero, otherwise the slave is discarded. 3361 * 3362 * Among all the slaves matching the above conditions we select the slave 3363 * with, in order of sorting key: 3364 * 3365 * - lower slave_priority. 3366 * - bigger processed replication offset. 3367 * - lexicographically smaller runid. 3368 * 3369 * Basically if runid is the same, the slave that processed more commands 3370 * from the master is selected. 3371 * 3372 * The function returns the pointer to the selected slave, otherwise 3373 * NULL if no suitable slave was found. 3374 */ 3375 3376 /* Helper for sentinelSelectSlave(). This is used by qsort() in order to 3377 * sort suitable slaves in a "better first" order, to take the first of 3378 * the list. */ 3379 int compareSlavesForPromotion(const void *a, const void *b) { 3380 sentinelRedisInstance **sa = (sentinelRedisInstance **)a, 3381 **sb = (sentinelRedisInstance **)b; 3382 char *sa_runid, *sb_runid; 3383 3384 if ((*sa)->slave_priority != (*sb)->slave_priority) 3385 return (*sa)->slave_priority - (*sb)->slave_priority; 3386 3387 /* If priority is the same, select the slave with greater replication 3388 * offset (processed more data frmo the master). */ 3389 if ((*sa)->slave_repl_offset > (*sb)->slave_repl_offset) { 3390 return -1; /* a < b */ 3391 } else if ((*sa)->slave_repl_offset < (*sb)->slave_repl_offset) { 3392 return 1; /* b > a */ 3393 } 3394 3395 /* If the replication offset is the same select the slave with that has 3396 * the lexicographically smaller runid. Note that we try to handle runid 3397 * == NULL as there are old Redis versions that don't publish runid in 3398 * INFO. A NULL runid is considered bigger than any other runid. */ 3399 sa_runid = (*sa)->runid; 3400 sb_runid = (*sb)->runid; 3401 if (sa_runid == NULL && sb_runid == NULL) return 0; 3402 else if (sa_runid == NULL) return 1; /* a > b */ 3403 else if (sb_runid == NULL) return -1; /* a < b */ 3404 return strcasecmp(sa_runid, sb_runid); 3405 } 3406 3407 sentinelRedisInstance *sentinelSelectSlave(sentinelRedisInstance *master) { 3408 sentinelRedisInstance **instance = 3409 zmalloc(sizeof(instance[0])*dictSize(master->slaves)); 3410 sentinelRedisInstance *selected = NULL; 3411 int instances = 0; 3412 dictIterator *di; 3413 dictEntry *de; 3414 mstime_t max_master_down_time = 0; 3415 3416 if (master->flags & SRI_S_DOWN) 3417 max_master_down_time += mstime() - master->s_down_since_time; 3418 max_master_down_time += master->down_after_period * 10; 3419 3420 di = dictGetIterator(master->slaves); 3421 while((de = dictNext(di)) != NULL) { 3422 sentinelRedisInstance *slave = dictGetVal(de); 3423 mstime_t info_validity_time; 3424 3425 if (slave->flags & (SRI_S_DOWN|SRI_O_DOWN|SRI_DISCONNECTED)) continue; 3426 if (mstime() - slave->last_avail_time > SENTINEL_PING_PERIOD*5) continue; 3427 if (slave->slave_priority == 0) continue; 3428 3429 /* If the master is in SDOWN state we get INFO for slaves every second. 3430 * Otherwise we get it with the usual period so we need to account for 3431 * a larger delay. */ 3432 if (master->flags & SRI_S_DOWN) 3433 info_validity_time = SENTINEL_PING_PERIOD*5; 3434 else 3435 info_validity_time = SENTINEL_INFO_PERIOD*3; 3436 if (mstime() - slave->info_refresh > info_validity_time) continue; 3437 if (slave->master_link_down_time > max_master_down_time) continue; 3438 instance[instances++] = slave; 3439 } 3440 dictReleaseIterator(di); 3441 if (instances) { 3442 qsort(instance,instances,sizeof(sentinelRedisInstance*), 3443 compareSlavesForPromotion); 3444 selected = instance[0]; 3445 } 3446 zfree(instance); 3447 return selected; 3448 } 3449 3450 /* ---------------- Failover state machine implementation ------------------- */ 3451 void sentinelFailoverWaitStart(sentinelRedisInstance *ri) { 3452 char *leader; 3453 int isleader; 3454 3455 /* Check if we are the leader for the failover epoch. */ 3456 leader = sentinelGetLeader(ri, ri->failover_epoch); 3457 isleader = leader && strcasecmp(leader,server.runid) == 0; 3458 sdsfree(leader); 3459 3460 /* If I'm not the leader, and it is not a forced failover via 3461 * SENTINEL FAILOVER, then I can't continue with the failover. */ 3462 if (!isleader && !(ri->flags & SRI_FORCE_FAILOVER)) { 3463 int election_timeout = SENTINEL_ELECTION_TIMEOUT; 3464 3465 /* The election timeout is the MIN between SENTINEL_ELECTION_TIMEOUT 3466 * and the configured failover timeout. */ 3467 if (election_timeout > ri->failover_timeout) 3468 election_timeout = ri->failover_timeout; 3469 /* Abort the failover if I'm not the leader after some time. */ 3470 if (mstime() - ri->failover_start_time > election_timeout) { 3471 sentinelEvent(REDIS_WARNING,"-failover-abort-not-elected",ri,"%@"); 3472 sentinelAbortFailover(ri); 3473 } 3474 return; 3475 } 3476 sentinelEvent(REDIS_WARNING,"+elected-leader",ri,"%@"); 3477 ri->failover_state = SENTINEL_FAILOVER_STATE_SELECT_SLAVE; 3478 ri->failover_state_change_time = mstime(); 3479 sentinelEvent(REDIS_WARNING,"+failover-state-select-slave",ri,"%@"); 3480 } 3481 3482 void sentinelFailoverSelectSlave(sentinelRedisInstance *ri) { 3483 sentinelRedisInstance *slave = sentinelSelectSlave(ri); 3484 3485 /* We don't handle the timeout in this state as the function aborts 3486 * the failover or go forward in the next state. */ 3487 if (slave == NULL) { 3488 sentinelEvent(REDIS_WARNING,"-failover-abort-no-good-slave",ri,"%@"); 3489 sentinelAbortFailover(ri); 3490 } else { 3491 sentinelEvent(REDIS_WARNING,"+selected-slave",slave,"%@"); 3492 slave->flags |= SRI_PROMOTED; 3493 ri->promoted_slave = slave; 3494 ri->failover_state = SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE; 3495 ri->failover_state_change_time = mstime(); 3496 sentinelEvent(REDIS_NOTICE,"+failover-state-send-slaveof-noone", 3497 slave, "%@"); 3498 } 3499 } 3500 3501 void sentinelFailoverSendSlaveOfNoOne(sentinelRedisInstance *ri) { 3502 int retval; 3503 3504 /* We can't send the command to the promoted slave if it is now 3505 * disconnected. Retry again and again with this state until the timeout 3506 * is reached, then abort the failover. */ 3507 if (ri->promoted_slave->flags & SRI_DISCONNECTED) { 3508 if (mstime() - ri->failover_state_change_time > ri->failover_timeout) { 3509 sentinelEvent(REDIS_WARNING,"-failover-abort-slave-timeout",ri,"%@"); 3510 sentinelAbortFailover(ri); 3511 } 3512 return; 3513 } 3514 3515 /* Send SLAVEOF NO ONE command to turn the slave into a master. 3516 * We actually register a generic callback for this command as we don't 3517 * really care about the reply. We check if it worked indirectly observing 3518 * if INFO returns a different role (master instead of slave). */ 3519 retval = sentinelSendSlaveOf(ri->promoted_slave,NULL,0); 3520 if (retval != REDIS_OK) return; 3521 sentinelEvent(REDIS_NOTICE, "+failover-state-wait-promotion", 3522 ri->promoted_slave,"%@"); 3523 ri->failover_state = SENTINEL_FAILOVER_STATE_WAIT_PROMOTION; 3524 ri->failover_state_change_time = mstime(); 3525 } 3526 3527 /* We actually wait for promotion indirectly checking with INFO when the 3528 * slave turns into a master. */ 3529 void sentinelFailoverWaitPromotion(sentinelRedisInstance *ri) { 3530 /* Just handle the timeout. Switching to the next state is handled 3531 * by the function parsing the INFO command of the promoted slave. */ 3532 if (mstime() - ri->failover_state_change_time > ri->failover_timeout) { 3533 sentinelEvent(REDIS_WARNING,"-failover-abort-slave-timeout",ri,"%@"); 3534 sentinelAbortFailover(ri); 3535 } 3536 } 3537 3538 void sentinelFailoverDetectEnd(sentinelRedisInstance *master) { 3539 int not_reconfigured = 0, timeout = 0; 3540 dictIterator *di; 3541 dictEntry *de; 3542 mstime_t elapsed = mstime() - master->failover_state_change_time; 3543 3544 /* We can't consider failover finished if the promoted slave is 3545 * not reachable. */ 3546 if (master->promoted_slave == NULL || 3547 master->promoted_slave->flags & SRI_S_DOWN) return; 3548 3549 /* The failover terminates once all the reachable slaves are properly 3550 * configured. */ 3551 di = dictGetIterator(master->slaves); 3552 while((de = dictNext(di)) != NULL) { 3553 sentinelRedisInstance *slave = dictGetVal(de); 3554 3555 if (slave->flags & (SRI_PROMOTED|SRI_RECONF_DONE)) continue; 3556 if (slave->flags & SRI_S_DOWN) continue; 3557 not_reconfigured++; 3558 } 3559 dictReleaseIterator(di); 3560 3561 /* Force end of failover on timeout. */ 3562 if (elapsed > master->failover_timeout) { 3563 not_reconfigured = 0; 3564 timeout = 1; 3565 sentinelEvent(REDIS_WARNING,"+failover-end-for-timeout",master,"%@"); 3566 } 3567 3568 if (not_reconfigured == 0) { 3569 sentinelEvent(REDIS_WARNING,"+failover-end",master,"%@"); 3570 master->failover_state = SENTINEL_FAILOVER_STATE_UPDATE_CONFIG; 3571 master->failover_state_change_time = mstime(); 3572 } 3573 3574 /* If I'm the leader it is a good idea to send a best effort SLAVEOF 3575 * command to all the slaves still not reconfigured to replicate with 3576 * the new master. */ 3577 if (timeout) { 3578 dictIterator *di; 3579 dictEntry *de; 3580 3581 di = dictGetIterator(master->slaves); 3582 while((de = dictNext(di)) != NULL) { 3583 sentinelRedisInstance *slave = dictGetVal(de); 3584 int retval; 3585 3586 if (slave->flags & 3587 (SRI_RECONF_DONE|SRI_RECONF_SENT|SRI_DISCONNECTED)) continue; 3588 3589 retval = sentinelSendSlaveOf(slave, 3590 master->promoted_slave->addr->ip, 3591 master->promoted_slave->addr->port); 3592 if (retval == REDIS_OK) { 3593 sentinelEvent(REDIS_NOTICE,"+slave-reconf-sent-be",slave,"%@"); 3594 slave->flags |= SRI_RECONF_SENT; 3595 } 3596 } 3597 dictReleaseIterator(di); 3598 } 3599 } 3600 3601 /* Send SLAVE OF <new master address> to all the remaining slaves that 3602 * still don't appear to have the configuration updated. */ 3603 void sentinelFailoverReconfNextSlave(sentinelRedisInstance *master) { 3604 dictIterator *di; 3605 dictEntry *de; 3606 int in_progress = 0; 3607 3608 di = dictGetIterator(master->slaves); 3609 while((de = dictNext(di)) != NULL) { 3610 sentinelRedisInstance *slave = dictGetVal(de); 3611 3612 if (slave->flags & (SRI_RECONF_SENT|SRI_RECONF_INPROG)) 3613 in_progress++; 3614 } 3615 dictReleaseIterator(di); 3616 3617 di = dictGetIterator(master->slaves); 3618 while(in_progress < master->parallel_syncs && 3619 (de = dictNext(di)) != NULL) 3620 { 3621 sentinelRedisInstance *slave = dictGetVal(de); 3622 int retval; 3623 3624 /* Skip the promoted slave, and already configured slaves. */ 3625 if (slave->flags & (SRI_PROMOTED|SRI_RECONF_DONE)) continue; 3626 3627 /* If too much time elapsed without the slave moving forward to 3628 * the next state, consider it reconfigured even if it is not. 3629 * Sentinels will detect the slave as misconfigured and fix its 3630 * configuration later. */ 3631 if ((slave->flags & SRI_RECONF_SENT) && 3632 (mstime() - slave->slave_reconf_sent_time) > 3633 SENTINEL_SLAVE_RECONF_TIMEOUT) 3634 { 3635 sentinelEvent(REDIS_NOTICE,"-slave-reconf-sent-timeout",slave,"%@"); 3636 slave->flags &= ~SRI_RECONF_SENT; 3637 slave->flags |= SRI_RECONF_DONE; 3638 } 3639 3640 /* Nothing to do for instances that are disconnected or already 3641 * in RECONF_SENT state. */ 3642 if (slave->flags & (SRI_DISCONNECTED|SRI_RECONF_SENT|SRI_RECONF_INPROG)) 3643 continue; 3644 3645 /* Send SLAVEOF <new master>. */ 3646 retval = sentinelSendSlaveOf(slave, 3647 master->promoted_slave->addr->ip, 3648 master->promoted_slave->addr->port); 3649 if (retval == REDIS_OK) { 3650 slave->flags |= SRI_RECONF_SENT; 3651 slave->slave_reconf_sent_time = mstime(); 3652 sentinelEvent(REDIS_NOTICE,"+slave-reconf-sent",slave,"%@"); 3653 in_progress++; 3654 } 3655 } 3656 dictReleaseIterator(di); 3657 3658 /* Check if all the slaves are reconfigured and handle timeout. */ 3659 sentinelFailoverDetectEnd(master); 3660 } 3661 3662 /* This function is called when the slave is in 3663 * SENTINEL_FAILOVER_STATE_UPDATE_CONFIG state. In this state we need 3664 * to remove it from the master table and add the promoted slave instead. */ 3665 void sentinelFailoverSwitchToPromotedSlave(sentinelRedisInstance *master) { 3666 sentinelRedisInstance *ref = master->promoted_slave ? 3667 master->promoted_slave : master; 3668 3669 sentinelEvent(REDIS_WARNING,"+switch-master",master,"%s %s %d %s %d", 3670 master->name, master->addr->ip, master->addr->port, 3671 ref->addr->ip, ref->addr->port); 3672 3673 sentinelResetMasterAndChangeAddress(master,ref->addr->ip,ref->addr->port); 3674 } 3675 3676 void sentinelFailoverStateMachine(sentinelRedisInstance *ri) { 3677 redisAssert(ri->flags & SRI_MASTER); 3678 3679 if (!(ri->flags & SRI_FAILOVER_IN_PROGRESS)) return; 3680 3681 switch(ri->failover_state) { 3682 case SENTINEL_FAILOVER_STATE_WAIT_START: 3683 sentinelFailoverWaitStart(ri); 3684 break; 3685 case SENTINEL_FAILOVER_STATE_SELECT_SLAVE: 3686 sentinelFailoverSelectSlave(ri); 3687 break; 3688 case SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE: 3689 sentinelFailoverSendSlaveOfNoOne(ri); 3690 break; 3691 case SENTINEL_FAILOVER_STATE_WAIT_PROMOTION: 3692 sentinelFailoverWaitPromotion(ri); 3693 break; 3694 case SENTINEL_FAILOVER_STATE_RECONF_SLAVES: 3695 sentinelFailoverReconfNextSlave(ri); 3696 break; 3697 } 3698 } 3699 3700 /* Abort a failover in progress: 3701 * 3702 * This function can only be called before the promoted slave acknowledged 3703 * the slave -> master switch. Otherwise the failover can't be aborted and 3704 * will reach its end (possibly by timeout). */ 3705 void sentinelAbortFailover(sentinelRedisInstance *ri) { 3706 redisAssert(ri->flags & SRI_FAILOVER_IN_PROGRESS); 3707 redisAssert(ri->failover_state <= SENTINEL_FAILOVER_STATE_WAIT_PROMOTION); 3708 3709 ri->flags &= ~(SRI_FAILOVER_IN_PROGRESS|SRI_FORCE_FAILOVER); 3710 ri->failover_state = SENTINEL_FAILOVER_STATE_NONE; 3711 ri->failover_state_change_time = mstime(); 3712 if (ri->promoted_slave) { 3713 ri->promoted_slave->flags &= ~SRI_PROMOTED; 3714 ri->promoted_slave = NULL; 3715 } 3716 } 3717 3718 /* ======================== SENTINEL timer handler ========================== 3719 * This is the "main" our Sentinel, being sentinel completely non blocking 3720 * in design. The function is called every second. 3721 * -------------------------------------------------------------------------- */ 3722 3723 /* Perform scheduled operations for the specified Redis instance. */ 3724 void sentinelHandleRedisInstance(sentinelRedisInstance *ri) { 3725 /* ========== MONITORING HALF ============ */ 3726 /* Every kind of instance */ 3727 sentinelReconnectInstance(ri); 3728 sentinelSendPeriodicCommands(ri); 3729 3730 /* ============== ACTING HALF ============= */ 3731 /* We don't proceed with the acting half if we are in TILT mode. 3732 * TILT happens when we find something odd with the time, like a 3733 * sudden change in the clock. */ 3734 if (sentinel.tilt) { 3735 if (mstime()-sentinel.tilt_start_time < SENTINEL_TILT_PERIOD) return; 3736 sentinel.tilt = 0; 3737 sentinelEvent(REDIS_WARNING,"-tilt",NULL,"#tilt mode exited"); 3738 } 3739 3740 /* Every kind of instance */ 3741 sentinelCheckSubjectivelyDown(ri); 3742 3743 /* Masters and slaves */ 3744 if (ri->flags & (SRI_MASTER|SRI_SLAVE)) { 3745 /* Nothing so far. */ 3746 } 3747 3748 /* Only masters */ 3749 if (ri->flags & SRI_MASTER) { 3750 sentinelCheckObjectivelyDown(ri); 3751 if (sentinelStartFailoverIfNeeded(ri)) 3752 sentinelAskMasterStateToOtherSentinels(ri,SENTINEL_ASK_FORCED); 3753 sentinelFailoverStateMachine(ri); 3754 sentinelAskMasterStateToOtherSentinels(ri,SENTINEL_NO_FLAGS); 3755 } 3756 } 3757 3758 /* Perform scheduled operations for all the instances in the dictionary. 3759 * Recursively call the function against dictionaries of slaves. */ 3760 void sentinelHandleDictOfRedisInstances(dict *instances) { 3761 dictIterator *di; 3762 dictEntry *de; 3763 sentinelRedisInstance *switch_to_promoted = NULL; 3764 3765 /* There are a number of things we need to perform against every master. */ 3766 di = dictGetIterator(instances); 3767 while((de = dictNext(di)) != NULL) { 3768 sentinelRedisInstance *ri = dictGetVal(de); 3769 3770 sentinelHandleRedisInstance(ri); 3771 if (ri->flags & SRI_MASTER) { 3772 sentinelHandleDictOfRedisInstances(ri->slaves); 3773 sentinelHandleDictOfRedisInstances(ri->sentinels); 3774 if (ri->failover_state == SENTINEL_FAILOVER_STATE_UPDATE_CONFIG) { 3775 switch_to_promoted = ri; 3776 } 3777 } 3778 } 3779 if (switch_to_promoted) 3780 sentinelFailoverSwitchToPromotedSlave(switch_to_promoted); 3781 dictReleaseIterator(di); 3782 } 3783 3784 /* This function checks if we need to enter the TITL mode. 3785 * 3786 * The TILT mode is entered if we detect that between two invocations of the 3787 * timer interrupt, a negative amount of time, or too much time has passed. 3788 * Note that we expect that more or less just 100 milliseconds will pass 3789 * if everything is fine. However we'll see a negative number or a 3790 * difference bigger than SENTINEL_TILT_TRIGGER milliseconds if one of the 3791 * following conditions happen: 3792 * 3793 * 1) The Sentiel process for some time is blocked, for every kind of 3794 * random reason: the load is huge, the computer was frozen for some time 3795 * in I/O or alike, the process was stopped by a signal. Everything. 3796 * 2) The system clock was altered significantly. 3797 * 3798 * Under both this conditions we'll see everything as timed out and failing 3799 * without good reasons. Instead we enter the TILT mode and wait 3800 * for SENTINEL_TILT_PERIOD to elapse before starting to act again. 3801 * 3802 * During TILT time we still collect information, we just do not act. */ 3803 void sentinelCheckTiltCondition(void) { 3804 mstime_t now = mstime(); 3805 mstime_t delta = now - sentinel.previous_time; 3806 3807 if (delta < 0 || delta > SENTINEL_TILT_TRIGGER) { 3808 sentinel.tilt = 1; 3809 sentinel.tilt_start_time = mstime(); 3810 sentinelEvent(REDIS_WARNING,"+tilt",NULL,"#tilt mode entered"); 3811 } 3812 sentinel.previous_time = mstime(); 3813 } 3814 3815 void sentinelTimer(void) { 3816 sentinelCheckTiltCondition(); 3817 sentinelHandleDictOfRedisInstances(sentinel.masters); 3818 sentinelRunPendingScripts(); 3819 sentinelCollectTerminatedScripts(); 3820 sentinelKillTimedoutScripts(); 3821 3822 /* We continuously change the frequency of the Redis "timer interrupt" 3823 * in order to desynchronize every Sentinel from every other. 3824 * This non-determinism avoids that Sentinels started at the same time 3825 * exactly continue to stay synchronized asking to be voted at the 3826 * same time again and again (resulting in nobody likely winning the 3827 * election because of split brain voting). */ 3828 server.hz = REDIS_DEFAULT_HZ + rand() % REDIS_DEFAULT_HZ; 3829 } 3830 3831