Resolve backend DNS on a bounded thread pool to avoid head-of-line blocking (#1834)
* Use a bounded thread pool for backend DNS resolution * Queue DNS lookups instead of rejecting when the resolver pool is busy
This commit is contained in:
+12
-5
@@ -32,17 +32,20 @@ import java.net.InetAddress;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of {@code InetNameResolver} that performs blocking DNS name lookups
|
* An implementation of {@code InetNameResolver} that performs blocking DNS name lookups
|
||||||
* in a separate thread, avoiding blocking the Netty threads for an extended period of time
|
* on a small bounded pool of separate threads, avoiding blocking the Netty threads for an
|
||||||
* and without the downsides of Netty's native DNS resolver.
|
* extended period of time and without the downsides of Netty's native DNS resolver.
|
||||||
*/
|
*/
|
||||||
public final class SeparatePoolInetNameResolver extends InetNameResolver {
|
public final class SeparatePoolInetNameResolver extends InetNameResolver {
|
||||||
|
|
||||||
|
private static final int MAX_RESOLVE_THREADS = 8;
|
||||||
|
|
||||||
private final ExecutorService resolveExecutor;
|
private final ExecutorService resolveExecutor;
|
||||||
private final InetNameResolver delegate;
|
private final InetNameResolver delegate;
|
||||||
private final Cache<String, List<InetAddress>> cache;
|
private final Cache<String, List<InetAddress>> cache;
|
||||||
@@ -56,11 +59,15 @@ public final class SeparatePoolInetNameResolver extends InetNameResolver {
|
|||||||
*/
|
*/
|
||||||
public SeparatePoolInetNameResolver(EventExecutor executor) {
|
public SeparatePoolInetNameResolver(EventExecutor executor) {
|
||||||
super(executor);
|
super(executor);
|
||||||
this.resolveExecutor = Executors.newSingleThreadExecutor(
|
ThreadPoolExecutor resolveExecutor = new ThreadPoolExecutor(
|
||||||
|
MAX_RESOLVE_THREADS, MAX_RESOLVE_THREADS,
|
||||||
|
60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(),
|
||||||
new ThreadFactoryBuilder()
|
new ThreadFactoryBuilder()
|
||||||
.setNameFormat("Velocity DNS Resolver")
|
.setNameFormat("Velocity DNS Resolver #%d")
|
||||||
.setDaemon(true)
|
.setDaemon(true)
|
||||||
.build());
|
.build());
|
||||||
|
resolveExecutor.allowCoreThreadTimeOut(true);
|
||||||
|
this.resolveExecutor = resolveExecutor;
|
||||||
this.delegate = new DefaultNameResolver(executor);
|
this.delegate = new DefaultNameResolver(executor);
|
||||||
this.cache = Caffeine.newBuilder()
|
this.cache = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(30, TimeUnit.SECONDS)
|
.expireAfterWrite(30, TimeUnit.SECONDS)
|
||||||
|
|||||||
Reference in New Issue
Block a user