hiredis icon indicating copy to clipboard operation
hiredis copied to clipboard

Resolve IPv6 address takes too much time

Open zh1029 opened this issue 4 years ago • 4 comments

We have nss-mdns (http://0pointer.de/lennart/projects/nss-mdns/#documentation) deployed in our system and publish IPv6 address with DNS via avahi-publish. The problem that we realize redis connect via redis-cli takes much time(several seconds). The root cause is hiredis first looks for IPv4 address of the DNS, than looks for IPv6 address. but due to system doesn't publish IPv4 address, It takes time(timeout) to failed to get IPv4 address.

static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
                                   const struct timeval *timeout,
                                   const char *source_addr) {
    ......
    snprintf(_port, 6, "%d", port);
    memset(&hints,0,sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;

    /* Try with IPv6 if no IPv4 address was found. We do it in this order since
     * in a Redis client you can't afford to test if you have IPv6 connectivity
     * as this would add latency to every connect. Otherwise a more sensible
     * route could be: Use IPv6 if both addresses are available and there is IPv6
     * connectivity. */
    if ((rv = getaddrinfo(c->tcp.host,_port,&hints,&servinfo)) != 0) {
         hints.ai_family = AF_INET6;
         if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) {
            __redisSetError(c,REDIS_ERR_OTHER,gai_strerror(rv));
            return REDIS_ERR;
        }
    }
    ......
}

So can hints.ai_family be set AF_UNSPEC instead of try IPv4 and IPv6 in order?

zh1029 avatar Aug 05 '19 02:08 zh1029

Perhaps we can add this as an option?

mnunberg avatar Aug 09 '19 08:08 mnunberg

I don't understand the reason behind here to try IPv4 first, then IPv6 in order. Doesn't it always working no matter get IPv4 or IPv6 whatever configured?

zh1029 avatar Aug 15 '19 02:08 zh1029

The normal way to do this is as zh1029 says and use AF_UNSPEC with a single call to getaddrinfo()

Underneath, getaddrinfo() will race to find working IPv4 and IPv6 addresses, preferring IPv6 (i.e IPv6 addresses will be the first in the list as returned). I believe this is part of the 'Happy Eyeballs' protocol.

ac000 avatar Feb 19 '20 21:02 ac000

I've not heard of this before, but it looks interesting.

It seems reasonable to add this logic as long as we can do it without breaking too many things.

michael-grunder avatar Feb 20 '20 02:02 michael-grunder

Good morning!

This has been discussed recently in the Redis main repo. DNS-lookup has been added in redis-cli. See https://github.com/redis/redis/pull/11151 and https://github.com/redis/redis/pull/10436.

TL;DR for redis-cli, this was decided and implemented:

  • It was decided to use AF_UNSPEC by default.
  • It was not acceptable to prefer IPv4 over IPv6. According to standards, the default should rather be to prefer IPv6. It is also something the user can configure in /etc/gai.conf.
  • Since not all users have access to configure /etc/gai.conf, options -4 and -6 were added to redis-cli to prefer IPv4 or IPv6 respectively.

For hiredis, I suggest we do something similar.

  • We can add options for redisConnectWithOptions to prefer IPv4, IPv6 or unspecified.
  • We can leave the default to prefer IPv4 over IPv6 for backward compatibilty, to be really safe.
  • ... or, if you (@michael-grunder) are willing to take the risk, we can change the default to AF_UNSPEC. I think it is a better default in general.

zuiderkwast avatar Sep 01 '22 07:09 zuiderkwast