antirez/redis — pull request #2118 by mattsta (2014-10-31 20:36:01+00:00)
Title: Sentinel: resolve master_host to IP address

Background
----

This problem has been reported multiple times on the mailing list and here in GitHub Issues.

People sometimes configure replicas using "SLAVEOF masterhost.internal.corp 6379", then Sentinel shows up, compares the *hostname* to the IP address on the master, then re-runs SLAVEOF IP PORT even though the slave is _already_ connected to the correct server.

Potential Fixes
----
The bad "comparing hostname to IP address" issue can be fixed in two places:
- redis-server: Force SLAVEOF to resolve hostname to IP address
- potentially causes a server stall because DNS resolution isn't async
- I decided not to use this approach, but it's still at https://github.com/mattsta/redis/commit/4d522c374b85b53c59e37303d89db7e6a30b8c49
- sentinel: Force Sentniel to resolve all `master_host` addresses
- Still non-async resolution, but not performance impacting since it's in Sentinel and not Redis itself.
- This approach seems the best, and it's what this PR is all about.

Alternatively, we could just deny _all_ hostnames by forcing IP-only in the SLAVEOF command. That seems like an extreme fix because hostnames are useful things to have.

This Fix
----

If we don't resolve hosts to IP addresses, Sentniel compares
a slave's masterhost (potentially a hostname) against the
master's slave list (only IPs).

This commit resolves hostnames provided by replicas so
we can string compare IP->IP instead of Hostname->IP.

During any failures, Sentinel will use IP addresses to
re-parent replicas or rewrite the main config, so the
hostnames are for convenience only and never get persisted
in the Sentinel config.

If a replica goes away and comes back, Sentinel will re-attach it to the master using the master's IP address and not the previous hostname that was configured. Sentinel internally still operates 100% on IP addresses *except* for comparing the `master_host` field on replicas against master IP addresses.

If the resolve fails, we emit a "-noresolve" event and
set the local IP field equal to the non-existing hostname
anyway. (Note: since the Redis server is _already_ connected
to the hostname it reports in INFO, it is *very* unlikely that Sentniel can't also
resolve the same hostname because Redis already had to resolve
it when somebody configured `SLAVEOF hostname port`.)

Also, now `SENTNIEL SLAVES mymaster` reports `master-host` as the hostname and `master-host-ip` as the resolved IP address of the hostname.
Example:
```haskell
localhost:26379> sentinel slaves mymaster
.
.
.
33) "master-host"
34) "mememe.vcap.me"
35) "master-host-ip"
36) "127.0.0.1"
.
.
.
```
Fixes #2075
Fixes #2032