- 
                Notifications
    You must be signed in to change notification settings 
- Fork 1.1k
Resolve hostnames using netty's non-blocking DNS resolver #1517
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -75,6 +75,7 @@ | |
| * | ||
| * @author Will Glozer | ||
| * @author Mark Paluch | ||
| * @author Yohei Ueki | ||
| * @see RedisURI | ||
| * @see StatefulRedisConnection | ||
| * @see RedisFuture | ||
|  | @@ -322,6 +323,7 @@ private <K, V, S> ConnectionFuture<S> connectStatefulAsync(StatefulRedisConnecti | |
| connectionBuilder(getSocketAddressSupplier(redisURI), connectionBuilder, redisURI); | ||
| connectionBuilder.connectionInitializer(createHandshake(state)); | ||
| channelType(connectionBuilder, redisURI); | ||
| resolver(connectionBuilder, redisURI); | ||
| 
      Comment on lines
    
      325
     to 
      +326
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Supplemental Comments] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it makes sense to refactor the connect code a bit to pull things more together. I'll take care of this during the merge. | ||
|  | ||
| ConnectionFuture<RedisChannelHandler<K, V>> future = initializeChannelAsync(connectionBuilder); | ||
|  | ||
|  | @@ -599,6 +601,7 @@ private <K, V> ConnectionFuture<StatefulRedisSentinelConnection<K, V>> doConnect | |
| connectionBuilder(getSocketAddressSupplier(redisURI), connectionBuilder, redisURI); | ||
|  | ||
| channelType(connectionBuilder, redisURI); | ||
| resolver(connectionBuilder, redisURI); | ||
| ConnectionFuture<?> sync = initializeChannelAsync(connectionBuilder); | ||
|  | ||
| return sync.thenApply(ignore -> (StatefulRedisSentinelConnection<K, V>) connection).whenComplete((ignore, e) -> { | ||
|  | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -22,16 +22,19 @@ | |
| 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; | ||
|  | ||
| /** | ||
| * Transport infrastructure utility class. This class provides {@link EventLoopGroup} and {@link Channel} classes for socket and | ||
| * native socket transports. | ||
| * | ||
| * @author Mark Paluch | ||
| * @author Yohei Ueki | ||
| * @since 4.4 | ||
| */ | ||
| class Transports { | ||
| public class Transports { | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Supplemental Comments] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should move  | ||
|  | ||
| /** | ||
| * @return the default {@link EventLoopGroup} for socket transport that is compatible with {@link #socketChannelClass()}. | ||
|  | @@ -48,7 +51,7 @@ static Class<? extends EventLoopGroup> eventLoopGroupClass() { | |
| /** | ||
| * @return the default {@link Channel} for socket (network/TCP) transport. | ||
| */ | ||
| static Class<? extends Channel> socketChannelClass() { | ||
| public static Class<? extends Channel> socketChannelClass() { | ||
|  | ||
| if (NativeTransports.isSocketSupported()) { | ||
| return NativeTransports.socketChannelClass(); | ||
|  | @@ -57,6 +60,18 @@ static Class<? extends Channel> socketChannelClass() { | |
| return NioSocketChannel.class; | ||
| } | ||
|  | ||
| /** | ||
| * @return the default {@link DatagramChannel} for socket (network/UDP) transport. | ||
| */ | ||
| public static Class<? extends DatagramChannel> datagramChannelClass() { | ||
|  | ||
| if (NativeTransports.isSocketSupported()) { | ||
| return NativeTransports.datagramChannelClass(); | ||
| } | ||
|  | ||
| return NioDatagramChannel.class; | ||
| } | ||
|  | ||
| /** | ||
| * Native transport support. | ||
| */ | ||
|  | @@ -79,6 +94,13 @@ static Class<? extends Channel> socketChannelClass() { | |
| return RESOURCES.socketChannelClass(); | ||
| } | ||
|  | ||
| /** | ||
| * @return the native transport socket {@link DatagramChannel} class. | ||
| */ | ||
| static Class<? extends DatagramChannel> datagramChannelClass() { | ||
| return RESOURCES.datagramChannelClass(); | ||
| } | ||
|  | ||
| /** | ||
| * @return the native transport domain socket {@link Channel} class. | ||
| */ | ||
|  | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| package io.lettuce.core.resource; | ||
|  | ||
| import java.util.function.Supplier; | ||
|  | ||
| import io.lettuce.core.Transports; | ||
| import io.netty.channel.socket.SocketChannel; | ||
| import io.netty.resolver.AddressResolverGroup; | ||
| import io.netty.resolver.DefaultAddressResolverGroup; | ||
| import io.netty.resolver.dns.DnsAddressResolverGroup; | ||
| import io.netty.resolver.dns.DnsNameResolverBuilder; | ||
| import io.netty.util.internal.logging.InternalLogger; | ||
| import io.netty.util.internal.logging.InternalLoggerFactory; | ||
|  | ||
| /** | ||
| * Wraps and provides {@link AddressResolverGroup} classes. This is to protect the user from {@link ClassNotFoundException}'s | ||
| * caused by the absence of the {@literal netty-dns-resolver} library during runtime. This class will be deleted when | ||
|          | ||
| * {@literal netty-dns-resolver} becomes mandatory. Internal API. | ||
| * | ||
| * @author Yohei Ueki | ||
| * @since xxx | ||
| */ | ||
| class AddressResolverGroupProvider { | ||
|  | ||
| private static final InternalLogger logger = InternalLoggerFactory.getInstance(AddressResolverGroupProvider.class); | ||
|  | ||
| private static final AddressResolverGroup<?> ADDRESS_RESOLVER_GROUP; | ||
|  | ||
| static { | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These should be unit-tested, but I could not come up with a good way to write unit tests regarding this in lettuce's test repository, because we need unittest jars with and without netty-dns-resolver. We might be able do it by dirty-hacking class loader, but I am not quite familiar with it. I wrote a unit test code outside of this repo: | ||
| boolean dnsResolverAvailable; | ||
| try { | ||
| Class.forName("io.netty.resolver.dns.DnsAddressResolverGroup"); | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use  | ||
| dnsResolverAvailable = true; | ||
| } catch (ClassNotFoundException e) { | ||
| dnsResolverAvailable = false; | ||
| } | ||
|  | ||
| // create addressResolverGroup instance via Supplier to avoid NoClassDefFoundError. | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Supplemental Comments] | ||
| Supplier<AddressResolverGroup<?>> supplier; | ||
| if (dnsResolverAvailable) { | ||
| logger.debug("Starting with netty's non-blocking DNS resolver library"); | ||
| supplier = AddressResolverGroupProvider::defaultDnsAddressResolverGroup; | ||
| } else { | ||
| logger.debug("Starting without optional netty's non-blocking DNS resolver library"); | ||
| supplier = () -> DefaultAddressResolverGroup.INSTANCE; | ||
| } | ||
| ADDRESS_RESOLVER_GROUP = supplier.get(); | ||
| } | ||
|  | ||
| /** | ||
| * Returns the {@link AddressResolverGroup} for dns resolution. | ||
| * | ||
| * @return the {@link DnsAddressResolverGroup} if {@literal netty-dns-resolver} is available, otherwise return | ||
| * {@link DefaultAddressResolverGroup#INSTANCE}. | ||
| * @since xxx | ||
| */ | ||
| static AddressResolverGroup<?> addressResolverGroup() { | ||
| return ADDRESS_RESOLVER_GROUP; | ||
| } | ||
|  | ||
| private static DnsAddressResolverGroup defaultDnsAddressResolverGroup() { | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method signature creates a dependency to  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As far as I tried with my UT and jenkins' doc, this did not produce  | ||
| return new DnsAddressResolverGroup(new DnsNameResolverBuilder().channelType(Transports.datagramChannelClass()) | ||
| .socketChannelType(Transports.socketChannelClass().asSubclass(SocketChannel.class))); | ||
| } | ||
|  | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -24,6 +24,7 @@ | |
| import io.lettuce.core.metrics.CommandLatencyCollectorOptions; | ||
| import io.lettuce.core.metrics.CommandLatencyRecorder; | ||
| import io.lettuce.core.tracing.Tracing; | ||
| import io.netty.resolver.AddressResolverGroup; | ||
| import io.netty.util.Timer; | ||
| import io.netty.util.concurrent.EventExecutorGroup; | ||
| import io.netty.util.concurrent.Future; | ||
|  | @@ -45,10 +46,12 @@ | |
| * <li>{@link DnsResolver} to collect latency details. Requires the {@literal LatencyUtils} library.</li> | ||
| * <li>{@link Timer} for scheduling</li> | ||
| * <li>{@link Tracing} to trace Redis commands.</li> | ||
| * <li>{@link AddressResolverGroup} for dns resolution.</li> | ||
| * </ul> | ||
| * | ||
| * @author Mark Paluch | ||
| * @author Mikhael Sokolov | ||
| * @author Yohei Ueki | ||
| * @since 3.4 | ||
| * @see DefaultClientResources | ||
| */ | ||
|  | @@ -241,6 +244,18 @@ default Builder commandLatencyCollector(CommandLatencyCollector commandLatencyCo | |
| */ | ||
| Builder tracing(Tracing tracing); | ||
|  | ||
| /** | ||
| * Sets the {@link AddressResolverGroup} for dns resolution. This option is only effective if | ||
| * {@link DnsResolvers#UNRESOLVED} is used as {@link DnsResolver}. Defaults to | ||
| * {@link io.netty.resolver.DefaultAddressResolverGroup#INSTANCE} if {@literal netty-dns-resolver} is not available, | ||
| * otherwise defaults to {@link io.netty.resolver.dns.DnsAddressResolverGroup}. | ||
| * | ||
| * @param addressResolverGroup the {@link AddressResolverGroup} instance, must not be {@code null}. | ||
| * @return {@code this} {@link Builder} | ||
| * @since xxx | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since 6.1 | ||
| */ | ||
| Builder addressResolverGroup(AddressResolverGroup<?> addressResolverGroup); | ||
|  | ||
| /** | ||
| * @return a new instance of {@link DefaultClientResources}. | ||
| */ | ||
|  | @@ -385,4 +400,12 @@ default Builder commandLatencyCollector(CommandLatencyCollector commandLatencyCo | |
| */ | ||
| Tracing tracing(); | ||
|  | ||
| /** | ||
| * Return the {@link AddressResolverGroup} instance for dns resolution. | ||
| * | ||
| * @return the address resolver group. | ||
| * @since xxx | ||
| */ | ||
| AddressResolverGroup<?> addressResolverGroup(); | ||
|  | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -35,6 +35,7 @@ | |
| import io.lettuce.core.metrics.MetricCollector; | ||
| import io.lettuce.core.resource.Delay.StatefulDelay; | ||
| import io.lettuce.core.tracing.Tracing; | ||
| import io.netty.resolver.AddressResolverGroup; | ||
| import io.netty.util.HashedWheelTimer; | ||
| import io.netty.util.Timer; | ||
| import io.netty.util.concurrent.DefaultEventExecutorGroup; | ||
|  | @@ -70,9 +71,11 @@ | |
| * <li>a {@code socketAddressResolver} which is a provided instance of {@link SocketAddressResolver}.</li> | ||
| * <li>a {@code timer} that is a provided instance of {@link io.netty.util.HashedWheelTimer}.</li> | ||
| * <li>a {@code tracing} that is a provided instance of {@link Tracing}.</li> | ||
| * <li>a {@code addressResolverGroup} that is a provided instance of {@link AddressResolverGroup}.</li> | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: We try to sort elements alphabetically. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (nits) also i noticed it should be  | ||
| * </ul> | ||
| * | ||
| * @author Mark Paluch | ||
| * @author Yohei Ueki | ||
| * @since 3.4 | ||
| */ | ||
| public class DefaultClientResources implements ClientResources { | ||
|  | @@ -103,6 +106,12 @@ public class DefaultClientResources implements ClientResources { | |
| */ | ||
| public static final NettyCustomizer DEFAULT_NETTY_CUSTOMIZER = DefaultNettyCustomizer.INSTANCE; | ||
|  | ||
| /** | ||
| * Default {@link AddressResolverGroup}. | ||
| */ | ||
| public static final AddressResolverGroup<?> DEFAULT_ADDRESS_RESOLVER_GROUP = AddressResolverGroupProvider | ||
| .addressResolverGroup(); | ||
|  | ||
| static { | ||
|  | ||
| int threads = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", | ||
|  | @@ -147,6 +156,8 @@ public class DefaultClientResources implements ClientResources { | |
|  | ||
| private final Tracing tracing; | ||
|  | ||
| private final AddressResolverGroup<?> addressResolverGroup; | ||
|  | ||
| private volatile boolean shutdownCalled = false; | ||
|  | ||
| protected DefaultClientResources(Builder builder) { | ||
|  | @@ -243,6 +254,7 @@ protected DefaultClientResources(Builder builder) { | |
| reconnectDelay = builder.reconnectDelay; | ||
| nettyCustomizer = builder.nettyCustomizer; | ||
| tracing = builder.tracing; | ||
| addressResolverGroup = builder.addressResolverGroup; | ||
|  | ||
| if (!sharedTimer && timer instanceof HashedWheelTimer) { | ||
| ((HashedWheelTimer) timer).start(); | ||
|  | @@ -308,6 +320,8 @@ public static class Builder implements ClientResources.Builder { | |
|  | ||
| private Tracing tracing = Tracing.disabled(); | ||
|  | ||
| private AddressResolverGroup<?> addressResolverGroup = DEFAULT_ADDRESS_RESOLVER_GROUP; | ||
|  | ||
| private Builder() { | ||
| } | ||
|  | ||
|  | @@ -569,6 +583,25 @@ public Builder tracing(Tracing tracing) { | |
| return this; | ||
| } | ||
|  | ||
| /** | ||
| * Sets the {@link AddressResolverGroup} for dns resolution. This option is only effective if | ||
| * {@link DnsResolvers#UNRESOLVED} is used as {@link DnsResolver}. Defaults to | ||
| * {@link io.netty.resolver.DefaultAddressResolverGroup#INSTANCE} if {@literal netty-dns-resolver} is not available, | ||
| * otherwise defaults to {@link io.netty.resolver.dns.DnsAddressResolverGroup}. | ||
| * | ||
| * @param addressResolverGroup the {@link AddressResolverGroup} instance, must not be {@code null}. | ||
| * @return {@code this} {@link ClientResources.Builder} | ||
| * @since xxx | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since 6.1 | ||
| */ | ||
| @Override | ||
| public Builder addressResolverGroup(AddressResolverGroup<?> addressResolverGroup) { | ||
|  | ||
| LettuceAssert.notNull(addressResolverGroup, "AddressResolverGroup must not be null"); | ||
|  | ||
| this.addressResolverGroup = addressResolverGroup; | ||
| return this; | ||
| } | ||
|  | ||
| /** | ||
| * @return a new instance of {@link DefaultClientResources}. | ||
| */ | ||
|  | @@ -603,7 +636,7 @@ public DefaultClientResources.Builder mutate() { | |
| .commandLatencyPublisherOptions(commandLatencyPublisherOptions()).dnsResolver(dnsResolver()) | ||
| .eventBus(eventBus()).eventExecutorGroup(eventExecutorGroup()).reconnectDelay(reconnectDelay) | ||
| .socketAddressResolver(socketAddressResolver()).nettyCustomizer(nettyCustomizer()).timer(timer()) | ||
| .tracing(tracing()); | ||
| .tracing(tracing()).addressResolverGroup(addressResolverGroup()); | ||
|  | ||
| builder.sharedCommandLatencyCollector = sharedEventLoopGroupProvider; | ||
| builder.sharedEventExecutor = sharedEventExecutor; | ||
|  | @@ -742,4 +775,9 @@ public Tracing tracing() { | |
| return tracing; | ||
| } | ||
|  | ||
| @Override | ||
| public AddressResolverGroup<?> addressResolverGroup() { | ||
| return addressResolverGroup; | ||
| } | ||
|  | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.