30

有没有一种干净的方法来异步解析 Java 中的 DNS 查询(通过主机名获取 IP),以非阻塞方式(即状态机,不是 1 个查询 = 1 个线程 - 我想同时运行数万个查询,但是不运行数万个线程)?

到目前为止我发现了什么:

  • 标准InetAddress.getByName()实现是阻塞的,看起来标准 Java 库缺少任何非阻塞实现。
  • Resolving DNS in bulk question 讨论了类似的问题,但找到的唯一解决方案是多线程方法(即一个线程在每个给定时刻仅处理 1 个查询),这不是真正可扩展的。
  • dnsjava库也只是阻塞的。
  • dnsjava的古老非阻塞扩展可以追溯到 2006 年,因此缺乏任何现代 Java 并发内容,例如Future范式使用,以及非常有限的仅队列实现。
  • dnsjnio项目也是对 dnsjava 的扩展,但它也适用于线程模型(即 1 个查询 = 1 个线程)。
  • asyncorg似乎是迄今为止我找到的针对此问题的最佳可用解决方案,但是:
    • 它也是 2007 年的,看起来被遗弃了
    • 几乎没有任何文档/javadoc
    • 使用了很多非标准的技术,比如Funclass

我错过了任何其他想法/实现?

澄清。我有相当大(每天几 TB)的日志量。每个日志行都有一个主机名,该主机名几乎可以来自互联网上的任何地方,我需要该主机名的 IP 地址以进行进一步的统计计算。行的顺序并不重要,所以,基本上,我的想法是启动 2 个线程:首先迭代行:

  • 读取一行,解析,获取主机名
  • 向 DNS 服务器发送查询以解析给定的主机名,不要阻止回答
  • 将线路和 DNS 查询套接字句柄存储在内存中的某个缓冲区中
  • 转到下一行

第二个线程将:

  • 等待 DNS 服务器回答任何查询(使用epoll/ kqueuelike 技术)
  • 阅读答案,找出它在缓冲区中的哪一行
  • 将解析 IP 的行写入输出
  • 继续等待下一个答案

Perl 中使用的一个简单模型实现AnyEvent向我表明,我的想法通常是正确的,并且我可以通过这种方式轻松实现每秒 15-20K 查询的速度(天真的阻塞实现每秒查询 2-3 次 - 只是为了比较 - 所以这就像4个数量级的差异)。现在我需要在 Java 中实现相同的功能 - 我想跳过推出我自己的 DNS 实现;)

4

6 回答 6

5

您可能正在寻找基于 MINA的 DNS 的 Apache 目录服务实现。JavaDocs 和其他有用的指南位于该页面的左侧边栏中。

于 2012-08-18T00:49:51.887 回答
5

在 netty 中有一些关于非阻塞 DNS的工作,但它仍在进行中,可能只会在 5.0 中发布

于 2013-06-03T15:55:48.090 回答
3

我认为,您必须自己在原始 UDP 之上使用基本套接字支持实现 DNS 客户端协议,或者在 TCP 之上使用 NIO 通道实现。

于 2012-08-18T00:40:54.097 回答
2

我没有你的问题的答案(我不知道是否有一个 DNS 库可以在你想要的异步模式下运行),这对于评论来说太长了。

但是,您应该能够快速生成异步,而无需自己编写完整的 DNS 处理程序。警告,我没有这样做,所以我可能都错了。

从 dnsjava 代码开始,您应该能够实现自己的解析器,该解析器将为您提供发送方和接收方方法。查看SimpleResolver并查看send方法。您应该能够将此方法分解为两种方法,一种将您的请求发送到对 TCPClient 或 UDPClient 的调用(正如您所描述的,此时您将处理实际的在线发送,与您的第一个线程),并且,一个接收,将由您的第二个线程调用作为对套接字读取的响应,并处理解析响应。您可能必须从 SimpleResolver 复制所有代码(您需要许多私有方法,并且许可允许它),或者,您可以创建自己的版本并简单地将其加载到类路径中的 jared 版本之前,或者,您可以反映您对相关方法的方式并将它们设置为可访问

您可以使用nettymina快速构建网络客户端。对于文档,我更喜欢 netty。

如果您确实走这条路并且可以/想要开源它,如果您遇到麻烦,我可以留出一些时间来提供帮助。

于 2012-08-20T13:27:18.863 回答
1

Linux有异步DNS查找功能:http ://www.imperialviolet.org/2005/06/01/asynchronous-dns-lookups-with-glibc.html

如果您在 Linux 上,您只需将其包装在一些 JNI 中。

于 2012-08-23T10:44:30.943 回答
-1

你有多种选择

选项 1:Java 5 执行器

  1. 固定线程池:Executors.newFixedThreadPool(int)
  2. Future:Future 代表异步计算的结果。提供了检查计算是否完成、等待其完成以及检索计算结果的方法。

选项 2:带有 MessageListener 的 JMS

  1. 需要依赖 JMS Provider 等。

选项 2:基于 Actor 的框架

你可以用 this 很好地扩展它。看看Akka

于 2012-08-15T22:44:38.517 回答