【问题标题】:Provide custom implementation for DNS lookup in java.net.URL class在 java.net.URL 类中为 DNS 查找提供自定义实现
【发布时间】:2015-02-06 08:07:36
【问题描述】:

我想知道是否可以为 java.net.URL 上的 DNS 查找提供自定义实现 - 我的托管服务提供商的 DNS 在一天中的某些时间变得不稳定,然后 DNS 查找失败几分钟,但如果我手动配置我的主机文件中的相关域,它们工作正常,所以我想做的是在软件级别有某种 DNS 缓存,如果 DNS 查找成功,更新缓存,如果失败,回退到缓存的 IP 地址并在该 IP 地址上打开 URLConnection。

这是我的 URL 连接实现:

    URL endpoint = new URL(null, url, new URLStreamHandler() {
        @Override
        protected URLConnection openConnection(URL url)
                throws IOException {
            URL target = new URL(url.toString());
            URLConnection connection = target.openConnection();
            // Connection settings
            connection.setConnectTimeout(connectionTimeout);
            connection.setReadTimeout(readTimeout);
            return (connection);
        }
    });

我在 Oracle 上查看代理,但看不到任何直接在软件级别进行自定义 DNS 查找的方法。

限制

1:需要在Java6下工作(可能是Java7,但客户端不会很快切换到Java8)

2:无法添加 JVM 参数

3:我不拥有这些端点,因此用 IP 地址替换主机名不是解决方案,因为负载均衡器将根据您来自主机名还是 IP 地址来提供不同的内容/API。例如:mail.google.com 解析为 216.58.223.37,访问该 IP 地址将提供 google.com 内容而不是 mail.google.com 内容,因为这两个服务都位于使用单个 IP 地址的同一负载均衡器后面.

4:我不知道需要缓存多少个 URL 的 DNS 解析,但我知道不会超过 1000 个。理想的解决方案是将 DNS 解析放在静态哈希图中,如果有任何DNS解析成功,更新hashmap,如果失败,使用hashmap中的DNS解析。

5:如果有本地 java 解决方案,我更喜欢使用 JNI - Understanding host name resolution and DNS behavior in Java

【问题讨论】:

  • 如果需要更优雅的解决方案,您是否可以简单地将 URL 的主机部分替换为您的自定义 DNS 实现将返回的 IP 地址?我的意思是使用普通的旧字符串操作。
  • 我有大约 500 个 URL 需要维护,我希望有一个解决方案,我可以只拥有一个静态哈希图并在内存中查找 90 秒 DNS 不稳定,可能每天一次.
  • @JanVladimirMostert 你解决问题了吗?我的代码无法访问在hackerrank 上运行的AWS。任何 id 如何获取 ip 或更改 dns?
  • 我已经发布了我的解决方案。如果没有帮助,请发布一个新的 Stack Overflow 问题,我会看看。
  • 在我的情况下不起作用,我无法访问 /etc/hosts,如果您知道任何解决方案,请告诉我

标签: java caching dns


【解决方案1】:

您可以创建一个自定义方法来检查主机是否解析为 IP。如果主机未解析,则在打开连接之前进行查找并直接使用 IP 来构建 URL:

在班级层面:

private Map<String,InetAddress> cacheMap = new HashMap<String,InetAddress>();

....然后有几个方法来构建你的 URL:

private URL buildUrl (String host) throws MalformedURLException {
    InetAddress ia = resolveHostToIp(host);
    URL url = null;

    if (ia != null) {
        url = new URL(ia.getHostAddress());
    } else {
        // Does not resolve and is not in cache....dunno
    }
    return url;
}


 private InetAddress resolveHostToIp(String host) {
    InetAddress ia = null;
    try {
        ia = InetAddress.getByName(host);
        // Update your cache
        cacheMap.put(host, ia);
    } catch (UnknownHostException uhe) {
        System.out.println("\"" + host + "\" does not resolve to an IP! Looking for it in the cacheMap....");
        // Head off to your cache and return the InetAddress from there.....
        ia = cacheMap.get(host);
    }
    return ia;
}

【讨论】:

  • 我连接的其中一些端点位于 AWS 和 GCE 上,如果您解析 www.example.com 的 IP 地址,您将获得一个 IP 地址,但发布到 IP 地址并发布到如果在该 IP 地址上运行多个服务,则 HOST 名称将给出完全不同的结果。
  • 好的。从你的问题中没有意识到这一点。那么“如果失败,回退到缓存的 IP 地址并在该 IP 地址上打开 URLConnection”如何工作,如果 IP 上运行多个服务?
  • 如果控制端点,用 IP 地址替换主机将是一个解决方案,不幸的是我不是。让我们以 mail.google.com 为例,它解析为 216.58.223.37,但访问它会转到 google.com 而不是 mail.google.com
  • NGINX / Apache / ...负载平衡器根据您的主机名决定加载哪个服务,如果您通过 IP 地址进入,您实际上是通过不同的主机名进入。跨度>
  • 好的。明白。我可以建议您修改原始问题以包含这些额外信息吗? ATM问题不包括任何这些细节!
【解决方案2】:

您可以简单地构建另一个 URL:

URL target = new URL(
    url.getProtocol(),
    customDns.resolve(url.getHost()),
    url.getFile());

您可以使用任何您需要的策略来实施customDns.resolve(String)

【讨论】:

  • 如果要控制端点,用 IP 地址替换主机将是一种解决方案,不幸的是我不是。让我们以 mail.google.com 为例,它解析为 216.58.223.37,但访问它会转到 google.com 而不是 mail.google.com
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
  • 2015-12-02
相关资源
最近更新 更多