From bb645d2c95ab571b6102cc7ebfe2275c7923ecb4 Mon Sep 17 00:00:00 2001 From: Yohei Ueki Date: Fri, 6 Nov 2020 22:31:05 +0900 Subject: [PATCH] Resolve hostnames using netty's non-blocking DNS resolver #1498 We now use netty's non-blocking DNS resolver upon connect. --- pom.xml | 5 +++++ .../io/lettuce/core/AbstractRedisClient.java | 15 +++++++++++++ .../java/io/lettuce/core/RedisClient.java | 3 +++ src/main/java/io/lettuce/core/Transports.java | 22 +++++++++++++++++++ .../core/cluster/RedisClusterClient.java | 2 ++ .../lettuce/core/resource/EpollProvider.java | 18 +++++++++++++++ .../core/resource/EventLoopResources.java | 7 ++++++ .../lettuce/core/resource/KqueueProvider.java | 21 ++++++++++++++++++ 8 files changed, 93 insertions(+) diff --git a/pom.xml b/pom.xml index de17b7af10..77347c0cde 100644 --- a/pom.xml +++ b/pom.xml @@ -154,6 +154,11 @@ netty-handler + + io.netty + netty-resolver-dns + + io.netty netty-transport diff --git a/src/main/java/io/lettuce/core/AbstractRedisClient.java b/src/main/java/io/lettuce/core/AbstractRedisClient.java index d67dcc8fb9..6003ca9ab0 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisClient.java +++ b/src/main/java/io/lettuce/core/AbstractRedisClient.java @@ -54,6 +54,9 @@ import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.resolver.dns.DnsAddressResolverGroup; +import io.netty.resolver.dns.DnsNameResolverBuilder; import io.netty.util.concurrent.EventExecutorGroup; import io.netty.util.concurrent.Future; import io.netty.util.internal.logging.InternalLogger; @@ -73,6 +76,7 @@ * @author Mark Paluch * @author Jongyeol Choi * @author Poorva Gokhale + * @author Yohei Ueki * @since 3.0 * @see ClientResources */ @@ -297,6 +301,17 @@ protected void channelType(ConnectionBuilder connectionBuilder, ConnectionPoint } } + protected void resolver(ConnectionBuilder connectionBuilder, ConnectionPoint connectionPoint) { + + LettuceAssert.notNull(connectionPoint, "ConnectionPoint must not be null"); + + if (connectionPoint.getSocket() == null) { + connectionBuilder.bootstrap().resolver( + new DnsAddressResolverGroup(new DnsNameResolverBuilder().channelType(Transports.datagramChannelClass()) + .socketChannelType(Transports.socketChannelClass().asSubclass(SocketChannel.class)))); + } + } + private EventLoopGroup getEventLoopGroup(ConnectionPoint connectionPoint) { for (;;) { diff --git a/src/main/java/io/lettuce/core/RedisClient.java b/src/main/java/io/lettuce/core/RedisClient.java index 0d51225835..5241a8c234 100644 --- a/src/main/java/io/lettuce/core/RedisClient.java +++ b/src/main/java/io/lettuce/core/RedisClient.java @@ -75,6 +75,7 @@ * * @author Will Glozer * @author Mark Paluch + * @author Yohei Ueki * @see RedisURI * @see StatefulRedisConnection * @see RedisFuture @@ -322,6 +323,7 @@ private ConnectionFuture connectStatefulAsync(StatefulRedisConnecti connectionBuilder(getSocketAddressSupplier(redisURI), connectionBuilder, redisURI); connectionBuilder.connectionInitializer(createHandshake(state)); channelType(connectionBuilder, redisURI); + resolver(connectionBuilder, redisURI); ConnectionFuture> future = initializeChannelAsync(connectionBuilder); @@ -599,6 +601,7 @@ private ConnectionFuture> doConnect connectionBuilder(getSocketAddressSupplier(redisURI), connectionBuilder, redisURI); channelType(connectionBuilder, redisURI); + resolver(connectionBuilder, redisURI); ConnectionFuture sync = initializeChannelAsync(connectionBuilder); return sync.thenApply(ignore -> (StatefulRedisSentinelConnection) connection).whenComplete((ignore, e) -> { diff --git a/src/main/java/io/lettuce/core/Transports.java b/src/main/java/io/lettuce/core/Transports.java index ac5b95fdf7..ea345ef7bb 100644 --- a/src/main/java/io/lettuce/core/Transports.java +++ b/src/main/java/io/lettuce/core/Transports.java @@ -22,6 +22,8 @@ import io.netty.channel.Channel; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.DatagramChannel; +import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.channel.socket.nio.NioSocketChannel; /** @@ -29,6 +31,7 @@ * native socket transports. * * @author Mark Paluch + * @author Yohei Ueki * @since 4.4 */ class Transports { @@ -57,6 +60,18 @@ static Class socketChannelClass() { return NioSocketChannel.class; } + /** + * @return the default {@link DatagramChannel} for socket (network/UDP) transport. + */ + static Class datagramChannelClass() { + + if (NativeTransports.isSocketSupported()) { + return NativeTransports.datagramChannelClass(); + } + + return NioDatagramChannel.class; + } + /** * Native transport support. */ @@ -79,6 +94,13 @@ static Class socketChannelClass() { return RESOURCES.socketChannelClass(); } + /** + * @return the native transport socket {@link DatagramChannel} class. + */ + static Class datagramChannelClass() { + return RESOURCES.datagramChannelClass(); + } + /** * @return the native transport domain socket {@link Channel} class. */ diff --git a/src/main/java/io/lettuce/core/cluster/RedisClusterClient.java b/src/main/java/io/lettuce/core/cluster/RedisClusterClient.java index 518af0b12a..f05dd48c80 100644 --- a/src/main/java/io/lettuce/core/cluster/RedisClusterClient.java +++ b/src/main/java/io/lettuce/core/cluster/RedisClusterClient.java @@ -135,6 +135,7 @@ * possible. * * @author Mark Paluch + * @author Yohei Ueki * @since 3.0 * @see RedisURI * @see StatefulRedisClusterConnection @@ -815,6 +816,7 @@ private ConnectionBuilder createConnectionBuilder(RedisChannelHandler socketChannelClass() { return null; } + @Override + public Class datagramChannelClass() { + + checkForEpollLibrary(); + return null; + } + } /** @@ -194,6 +204,14 @@ public Class socketChannelClass() { return EpollSocketChannel.class; } + @Override + public Class datagramChannelClass() { + + checkForEpollLibrary(); + + return EpollDatagramChannel.class; + } + @Override public Class eventLoopGroupClass() { diff --git a/src/main/java/io/lettuce/core/resource/EventLoopResources.java b/src/main/java/io/lettuce/core/resource/EventLoopResources.java index de95355823..3ebe241866 100644 --- a/src/main/java/io/lettuce/core/resource/EventLoopResources.java +++ b/src/main/java/io/lettuce/core/resource/EventLoopResources.java @@ -21,12 +21,14 @@ import io.netty.channel.Channel; import io.netty.channel.EventLoopGroup; import io.netty.channel.epoll.EpollEventLoopGroup; +import io.netty.channel.socket.DatagramChannel; import io.netty.util.concurrent.EventExecutorGroup; /** * Interface to encapsulate EventLoopGroup resources. * * @author Mark Paluch + * @author Yohei Ueki * @since 6.0 */ public interface EventLoopResources { @@ -58,6 +60,11 @@ public interface EventLoopResources { */ Class socketChannelClass(); + /** + * @return the {@link DatagramChannel} class. + */ + Class datagramChannelClass(); + /** * @return the {@link EventLoopGroup} class. */ diff --git a/src/main/java/io/lettuce/core/resource/KqueueProvider.java b/src/main/java/io/lettuce/core/resource/KqueueProvider.java index a938e2aa1b..5e250376f0 100644 --- a/src/main/java/io/lettuce/core/resource/KqueueProvider.java +++ b/src/main/java/io/lettuce/core/resource/KqueueProvider.java @@ -22,9 +22,11 @@ import io.netty.channel.Channel; import io.netty.channel.EventLoopGroup; import io.netty.channel.kqueue.KQueue; +import io.netty.channel.kqueue.KQueueDatagramChannel; import io.netty.channel.kqueue.KQueueDomainSocketChannel; import io.netty.channel.kqueue.KQueueEventLoopGroup; import io.netty.channel.kqueue.KQueueSocketChannel; +import io.netty.channel.socket.DatagramChannel; import io.netty.channel.unix.DomainSocketAddress; import io.netty.util.concurrent.EventExecutorGroup; import io.netty.util.internal.SystemPropertyUtil; @@ -36,6 +38,7 @@ * the {@literal netty-transport-native-kqueue} library during runtime. Internal API. * * @author Mark Paluch + * @author Yohei Ueki * @since 4.4 */ public class KqueueProvider { @@ -153,6 +156,15 @@ public Class socketChannelClass() { return null; } + @Override + public Class datagramChannelClass() { + + + checkForKqueueLibrary(); + return null; + } + + } /** @@ -194,6 +206,15 @@ public Class socketChannelClass() { return KQueueSocketChannel.class; } + @Override + public Class datagramChannelClass() { + + checkForKqueueLibrary(); + + return KQueueDatagramChannel.class; + } + + @Override public Class eventLoopGroupClass() {