mirror of https://mirror.osredm.com/root/redis.git
Fixed Sentinel support for hostnames (#10146)
Sentinel tries to resolve instances hostname to IP only during registration. It might be that the instance is unavailable during that time, such as leader crashed and failover took place. Yet, promoted replica must support: - Register leader, even if it fails to resolve its hostname during failover - Try later to resolve it, if instance is disconnected. Note that this condition also support ip-change of an instance.
This commit is contained in:
parent
2d391e62bd
commit
79f089bdd9
|
@ -552,10 +552,10 @@ void sentinelIsRunning(void) {
|
||||||
|
|
||||||
/* Create a sentinelAddr object and return it on success.
|
/* Create a sentinelAddr object and return it on success.
|
||||||
* On error NULL is returned and errno is set to:
|
* On error NULL is returned and errno is set to:
|
||||||
* ENOENT: Can't resolve the hostname.
|
* ENOENT: Can't resolve the hostname, unless accept_unresolved is non-zero.
|
||||||
* EINVAL: Invalid port number.
|
* EINVAL: Invalid port number.
|
||||||
*/
|
*/
|
||||||
sentinelAddr *createSentinelAddr(char *hostname, int port) {
|
sentinelAddr *createSentinelAddr(char *hostname, int port, int is_accept_unresolved) {
|
||||||
char ip[NET_IP_STR_LEN];
|
char ip[NET_IP_STR_LEN];
|
||||||
sentinelAddr *sa;
|
sentinelAddr *sa;
|
||||||
|
|
||||||
|
@ -565,8 +565,14 @@ sentinelAddr *createSentinelAddr(char *hostname, int port) {
|
||||||
}
|
}
|
||||||
if (anetResolve(NULL,hostname,ip,sizeof(ip),
|
if (anetResolve(NULL,hostname,ip,sizeof(ip),
|
||||||
sentinel.resolve_hostnames ? ANET_NONE : ANET_IP_ONLY) == ANET_ERR) {
|
sentinel.resolve_hostnames ? ANET_NONE : ANET_IP_ONLY) == ANET_ERR) {
|
||||||
errno = ENOENT;
|
serverLog(LL_WARNING, "Failed to resolve hostname '%s'", hostname);
|
||||||
return NULL;
|
if (sentinel.resolve_hostnames && is_accept_unresolved) {
|
||||||
|
ip[0] = '\0';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errno = ENOENT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sa = zmalloc(sizeof(*sa));
|
sa = zmalloc(sizeof(*sa));
|
||||||
sa->hostname = sdsnew(hostname);
|
sa->hostname = sdsnew(hostname);
|
||||||
|
@ -598,6 +604,15 @@ int sentinelAddrIsEqual(sentinelAddr *a, sentinelAddr *b) {
|
||||||
return a->port == b->port && !strcasecmp(a->ip,b->ip);
|
return a->port == b->port && !strcasecmp(a->ip,b->ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return non-zero if the two addresses are equal, either by address
|
||||||
|
* or by hostname if they could not have been resolved.
|
||||||
|
*/
|
||||||
|
int sentinelAddrOrHostnameEqual(sentinelAddr *a, sentinelAddr *b) {
|
||||||
|
return a->port == b->port &&
|
||||||
|
(!strcmp(a->ip, b->ip) ||
|
||||||
|
!strcasecmp(a->hostname, b->hostname));
|
||||||
|
}
|
||||||
|
|
||||||
/* Return non-zero if a hostname matches an address. */
|
/* Return non-zero if a hostname matches an address. */
|
||||||
int sentinelAddrEqualsHostname(sentinelAddr *a, char *hostname) {
|
int sentinelAddrEqualsHostname(sentinelAddr *a, char *hostname) {
|
||||||
char ip[NET_IP_STR_LEN];
|
char ip[NET_IP_STR_LEN];
|
||||||
|
@ -1259,7 +1274,7 @@ sentinelRedisInstance *createSentinelRedisInstance(char *name, int flags, char *
|
||||||
serverAssert((flags & SRI_MASTER) || master != NULL);
|
serverAssert((flags & SRI_MASTER) || master != NULL);
|
||||||
|
|
||||||
/* Check address validity. */
|
/* Check address validity. */
|
||||||
addr = createSentinelAddr(hostname,port);
|
addr = createSentinelAddr(hostname,port,1);
|
||||||
if (addr == NULL) return NULL;
|
if (addr == NULL) return NULL;
|
||||||
|
|
||||||
/* For slaves use ip/host:port as name. */
|
/* For slaves use ip/host:port as name. */
|
||||||
|
@ -1387,7 +1402,7 @@ sentinelRedisInstance *sentinelRedisInstanceLookupSlave(
|
||||||
* If that is the case, depending on configuration we either resolve
|
* If that is the case, depending on configuration we either resolve
|
||||||
* it and use the IP address or fail.
|
* it and use the IP address or fail.
|
||||||
*/
|
*/
|
||||||
addr = createSentinelAddr(slave_addr, port);
|
addr = createSentinelAddr(slave_addr, port, 0);
|
||||||
if (!addr) return NULL;
|
if (!addr) return NULL;
|
||||||
key = announceSentinelAddrAndPort(addr);
|
key = announceSentinelAddrAndPort(addr);
|
||||||
releaseSentinelAddr(addr);
|
releaseSentinelAddr(addr);
|
||||||
|
@ -1450,8 +1465,10 @@ sentinelRedisInstance *getSentinelRedisInstanceByAddrAndRunID(dict *instances, c
|
||||||
|
|
||||||
serverAssert(addr || runid); /* User must pass at least one search param. */
|
serverAssert(addr || runid); /* User must pass at least one search param. */
|
||||||
if (addr != NULL) {
|
if (addr != NULL) {
|
||||||
/* Resolve addr, we use the IP as a key even if a hostname is used */
|
/* Try to resolve addr. If hostnames are used, we're accepting an ri_addr
|
||||||
ri_addr = createSentinelAddr(addr, port);
|
* that contains an hostname only and can still be matched based on that.
|
||||||
|
*/
|
||||||
|
ri_addr = createSentinelAddr(addr,port,1);
|
||||||
if (!ri_addr) return NULL;
|
if (!ri_addr) return NULL;
|
||||||
}
|
}
|
||||||
di = dictGetIterator(instances);
|
di = dictGetIterator(instances);
|
||||||
|
@ -1460,8 +1477,7 @@ sentinelRedisInstance *getSentinelRedisInstanceByAddrAndRunID(dict *instances, c
|
||||||
|
|
||||||
if (runid && !ri->runid) continue;
|
if (runid && !ri->runid) continue;
|
||||||
if ((runid == NULL || strcmp(ri->runid, runid) == 0) &&
|
if ((runid == NULL || strcmp(ri->runid, runid) == 0) &&
|
||||||
(addr == NULL || (strcmp(ri->addr->ip, ri_addr->ip) == 0 &&
|
(addr == NULL || sentinelAddrOrHostnameEqual(ri->addr, ri_addr)))
|
||||||
ri->addr->port == port)))
|
|
||||||
{
|
{
|
||||||
instance = ri;
|
instance = ri;
|
||||||
break;
|
break;
|
||||||
|
@ -1565,7 +1581,7 @@ int sentinelResetMasterAndChangeAddress(sentinelRedisInstance *master, char *hos
|
||||||
dictIterator *di;
|
dictIterator *di;
|
||||||
dictEntry *de;
|
dictEntry *de;
|
||||||
|
|
||||||
newaddr = createSentinelAddr(hostname,port);
|
newaddr = createSentinelAddr(hostname,port,0);
|
||||||
if (newaddr == NULL) return C_ERR;
|
if (newaddr == NULL) return C_ERR;
|
||||||
|
|
||||||
/* There can be only 0 or 1 slave that has the newaddr.
|
/* There can be only 0 or 1 slave that has the newaddr.
|
||||||
|
@ -2355,6 +2371,7 @@ static int instanceLinkNegotiateTLS(redisAsyncContext *context) {
|
||||||
* is disconnected. Note that link->disconnected is true even if just
|
* is disconnected. Note that link->disconnected is true even if just
|
||||||
* one of the two links (commands and pub/sub) is missing. */
|
* one of the two links (commands and pub/sub) is missing. */
|
||||||
void sentinelReconnectInstance(sentinelRedisInstance *ri) {
|
void sentinelReconnectInstance(sentinelRedisInstance *ri) {
|
||||||
|
|
||||||
if (ri->link->disconnected == 0) return;
|
if (ri->link->disconnected == 0) return;
|
||||||
if (ri->addr->port == 0) return; /* port == 0 means invalid address. */
|
if (ri->addr->port == 0) return; /* port == 0 means invalid address. */
|
||||||
instanceLink *link = ri->link;
|
instanceLink *link = ri->link;
|
||||||
|
@ -2365,7 +2382,21 @@ void sentinelReconnectInstance(sentinelRedisInstance *ri) {
|
||||||
|
|
||||||
/* Commands connection. */
|
/* Commands connection. */
|
||||||
if (link->cc == NULL) {
|
if (link->cc == NULL) {
|
||||||
|
|
||||||
|
/* It might be that the instance is disconnected because it wasn't available earlier when the instance
|
||||||
|
* allocated, say during failover, and therefore we failed to resolve its ip.
|
||||||
|
* Another scenario is that the instance restarted with new ip, and we should resolve its new ip based on
|
||||||
|
* its hostname */
|
||||||
|
if (sentinel.resolve_hostnames) {
|
||||||
|
sentinelAddr *tryResolveAddr = createSentinelAddr(ri->addr->hostname, ri->addr->port, 0);
|
||||||
|
if (tryResolveAddr != NULL) {
|
||||||
|
releaseSentinelAddr(ri->addr);
|
||||||
|
ri->addr = tryResolveAddr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
link->cc = redisAsyncConnectBind(ri->addr->ip,ri->addr->port,server.bind_source_addr);
|
link->cc = redisAsyncConnectBind(ri->addr->ip,ri->addr->port,server.bind_source_addr);
|
||||||
|
|
||||||
if (link->cc && !link->cc->err) anetCloexec(link->cc->c.fd);
|
if (link->cc && !link->cc->err) anetCloexec(link->cc->c.fd);
|
||||||
if (!link->cc) {
|
if (!link->cc) {
|
||||||
sentinelEvent(LL_DEBUG,"-cmd-link-reconnection",ri,"%@ #Failed to establish connection");
|
sentinelEvent(LL_DEBUG,"-cmd-link-reconnection",ri,"%@ #Failed to establish connection");
|
||||||
|
@ -4892,6 +4923,7 @@ sentinelRedisInstance *sentinelSelectSlave(sentinelRedisInstance *master) {
|
||||||
max_master_down_time += master->down_after_period * 10;
|
max_master_down_time += master->down_after_period * 10;
|
||||||
|
|
||||||
di = dictGetIterator(master->slaves);
|
di = dictGetIterator(master->slaves);
|
||||||
|
|
||||||
while((de = dictNext(di)) != NULL) {
|
while((de = dictNext(di)) != NULL) {
|
||||||
sentinelRedisInstance *slave = dictGetVal(de);
|
sentinelRedisInstance *slave = dictGetVal(de);
|
||||||
mstime_t info_validity_time;
|
mstime_t info_validity_time;
|
||||||
|
|
Loading…
Reference in New Issue