org.apache.pulsar.client.impl.ConnectionPool.ConnectionPool(ClientConfigurationData, EventLoopGroup, Supplier<ClientCnx>)
public ConnectionPool(ClientConfigurationData conf, EventLoopGroup eventLoopGroup,
Supplier<ClientCnx> clientCnxSupplier) throws PulsarClientException {
this.eventLoopGroup = eventLoopGroup;
this.maxConnectionsPerHosts = conf.getConnectionsPerBroker();
pool = new ConcurrentHashMap<>();
bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup);
bootstrap.channel(EventLoopUtil.getClientSocketChannelClass(eventLoopGroup));
bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, conf.getConnectionTimeoutMs());
bootstrap.option(ChannelOption.TCP_NODELAY, conf.isUseTcpNoDelay());
bootstrap.option(ChannelOption.ALLOCATOR, PulsarByteBufAllocator.DEFAULT);
try {
bootstrap.handler(new PulsarChannelInitializer(conf, clientCnxSupplier));
} catch (Exception e) {
log.error("Failed to create channel initializer");
throw new PulsarClientException(e);
}
//初始化dns解析器
this.dnsResolver = new DnsNameResolverBuilder(eventLoopGroup.next()).traceEnabled(true)
.channelType(EventLoopUtil.getDatagramChannelClass(eventLoopGroup)).build();
}
//具体dns解析类:
io.netty.resolver.dns.DnsNameResolverBuilder.build()
/**
* Returns a new {@link DnsNameResolver} instance.
*
* @return a {@link DnsNameResolver}
*/
public DnsNameResolver build() {
if (eventLoop == null) {
throw new IllegalStateException("eventLoop should be specified to build a DnsNameResolver.");
}
if (resolveCache != null && (minTtl != null || maxTtl != null || negativeTtl != null)) {
throw new IllegalStateException("resolveCache and TTLs are mutually exclusive");
}
if (authoritativeDnsServerCache != null && (minTtl != null || maxTtl != null || negativeTtl != null)) {
throw new IllegalStateException("authoritativeDnsServerCache and TTLs are mutually exclusive");
}
DnsCache resolveCache = this.resolveCache != null ? this.resolveCache : newCache();
DnsCnameCache cnameCache = this.cnameCache != null ? this.cnameCache : newCnameCache();
AuthoritativeDnsServerCache authoritativeDnsServerCache = this.authoritativeDnsServerCache != null ?
this.authoritativeDnsServerCache : newAuthoritativeDnsServerCache();
return new DnsNameResolver(
eventLoop,
channelFactory,
socketChannelFactory,
resolveCache,
cnameCache,
authoritativeDnsServerCache,
dnsQueryLifecycleObserverFactory,
queryTimeoutMillis,
resolvedAddressTypes,
recursionDesired,
maxQueriesPerResolve,
traceEnabled,
maxPayloadSize,
optResourceEnabled,
hostsFileEntriesResolver,
dnsServerAddressStreamProvider,
searchDomains,
ndots,
decodeIdn,
completeOncePreferredResolved);
}
解析域名:
org.apache.pulsar.client.impl.ConnectionPool.resolveName(String)
@VisibleForTesting
CompletableFuture<List<InetAddress>> resolveName(String hostname) {
CompletableFuture<List<InetAddress>> future = new CompletableFuture<>();
//解析域名
dnsResolver.resolveAll(hostname).addListener((Future<List<InetAddress>> resolveFuture) -> {
if (resolveFuture.isSuccess()) {
future.complete(resolveFuture.get());
} else {
future.completeExceptionally(resolveFuture.cause());
}
});
return future;
}
//netty具体解析dns
io.netty.resolver.SimpleNameResolver.resolveAll(String, Promise<List<T>>)
@Override
public final Future<List<T>> resolveAll(String inetHost) {
final Promise<List<T>> promise = executor().newPromise();
return resolveAll(inetHost, promise);
}
@Override
public Future<List<T>> resolveAll(String inetHost, Promise<List<T>> promise) {
checkNotNull(promise, "promise");
try {
doResolveAll(inetHost, promise);
return promise;
} catch (Exception e) {
return promise.setFailure(e);
}
}
/**
* Invoked by {@link #resolve(String)} to perform the actual name resolution.
*/
protected abstract void doResolve(String inetHost, Promise<T> promise) throws Exception;
/**
* Invoked by {@link #resolveAll(String)} to perform the actual name resolution.
*/
protected abstract void doResolveAll(String inetHost, Promise<List<T>> promise) throws Exception;
具体dns解析实现类:
DnsNameResolver类解析域名:
io.netty.resolver.dns.DnsNameResolver.doResolveAll(String, Promise<List<InetAddress>>)
/**
* Hook designed for extensibility so one can pass a different cache on each resolution attempt
* instead of using the global one.
*/
protected void doResolveAll(String inetHost,
DnsRecord[] additionals,
Promise<List<InetAddress>> promise,
DnsCache resolveCache) throws Exception {
if (inetHost == null || inetHost.isEmpty()) {
// If an empty hostname is used we should use "localhost", just like InetAddress.getAllByName(...) does.
promise.setSuccess(Collections.singletonList(loopbackAddress()));
return;
}
//ip解析
final byte[] bytes = NetUtil.createByteArrayFromIpAddressString(inetHost);
if (bytes != null) {
// The unresolvedAddress was created via a String that contains an ipaddress.
promise.setSuccess(Collections.singletonList(InetAddress.getByAddress(bytes)));
return;
}
final String hostname = hostname(inetHost);
//本地host解析
InetAddress hostsFileEntry = resolveHostsFileEntry(hostname);
if (hostsFileEntry != null) {
promise.setSuccess(Collections.singletonList(hostsFileEntry));
return;
}
//具体解析获取结果
if (!doResolveAllCached(hostname, additionals, promise, resolveCache, resolvedInternetProtocolFamilies)) {
doResolveAllUncached(hostname, additionals, promise, resolveCache, completeOncePreferredResolved);
}
}
pulsar每次断开重连,重新创建连接都会重新解析DNS
hosts为什么不行?
io.netty.resolver.dns.DnsNameResolver.resolveHostsFileEntry(String)
private InetAddress resolveHostsFileEntry(String hostname) {
if (hostsFileEntriesResolver == null) {
return null;
} else {
//hostsFileEntriesResolver 初始化缓存hosts问题,不会再次加载更新后的hosts文件
InetAddress address = hostsFileEntriesResolver.address(hostname, resolvedAddressTypes);
if (address == null && PlatformDependent.isWindows() && LOCALHOST.equalsIgnoreCase(hostname)) {
// If we tried to resolve localhost we need workaround that windows removed localhost from its
// hostfile in later versions.
// See https://github.com/netty/netty/issues/5386
return LOCALHOST_ADDRESS;
}
return address;
}
}
来源:oschina
链接:https://my.oschina.net/xiaominmin/blog/4332710