2012-05-01 49 views
3

我需要将大量(数十万个)域解析为Java中的IP地址。虽然使用InetAddress.getByName()对于小数字是可行的,但大量使用它的速度远远不够(可能是因为它只向DNS服务器发送一个请求并等待响应,然后才转到下一个请求)。批量解析DNS

是否有更有效的方法(例如将它们发送到DNS服务器批量),这将减少解决大量域所需的时间?

在fmucar的要求我加入用于尝试更多的多线程方法的代码:

Set<String> ips = Collections.synchronizedSet(new HashSet<String>()); 
int i = 0; 
List<Set<String>> sets = new ArrayList<Set<String>>(); 
for (String host : domains) { 
    if (i++ % 5 == 0) { 
     sets.add(new HashSet<String>()); 
    } 
    Set<String> ipset = sets.get(sets.size()-1); 
    ipset.add(host); 
} 
for (Set<String> ipset : sets) { 
    Thread t = new Thread(new DomainResolver(ips, ipset)); 
    t.start(); 
} 

在250元线,我们达到顶峰大约每分钟700结果。其中,虽然比以前更好(< 300)仍然不是那么好,当需要解决数十万。将它降低到每个线程只有5个,这大大加速了每分钟几千个。这显然创造了一个疯狂的数量的线程虽然,所以目前正在调查做解决在C使用http://www.chiark.greenend.org.uk/~ian/adns/

+5

你最好不要发送他们到我的DNS服务器...... – Alnitak

+0

我们有我们自己的:-) – Exupery

+1

递归服务器?他们将在哪里发送_their_查询? – Alnitak

回答

1

您可以使用java.util.concurrent。*类创建一个多线程的应用程序来做几个查询,而无需等待结果。

See ExecutorService, Runnable, Callable, Future, Thread ... classes. 

如果这些对你来说是新的,那么阅读教程可能是个好主意。您的应用程序的

eg. You can use a `BlockingQueue`, and producer-consumer pattern. 

一部分将开始创建调用对象它变得可用,另外会从BlockingQueue的结果,并写入到文件也许他们会将该结果放入BlockingQueue的。

编辑1: 样品:

ExecutorService threadExecutor = Executors.newFixedThreadPool(50); 
for(....){ 
    Runnable thread = new Thread(new DomainResolver(ips, ipset)); 
    threadExecutor.execute(thread); 
} 

而不是创建并立即启动几个线程,委托执行任务指派给执行(见上文编辑),它在接受最多50线程随时服务。您将需要找到最佳的线程数,太多的线程意味着,大多数cpu周期将用于切换线程。过低意味着,CPU周期将被浪费在等待DNS服务器返回结果

+0

用一个,四个和八个线程进行实验,其收益实际上并不那么棒。一个线程每分钟处理大约275个线程,八个线程每分钟处理大约330个线程......我们确实需要更接近每分钟数千个线程(这可能是不可能的) – Exupery

+0

如果您的软件处于最佳优化点,那么您可能想升级硬件。但我认为它应该比330per/min更好,如果它是275per/min之前。向我们展示一些代码,你是如何实现的 – fmucar

+0

请参阅我的编辑代码使用。我已经稍微重新考虑了它,现在每分钟处理速度略高于700。 – Exupery

2

按照RFC for DNS Implementation你只能在一个时间问一个问题,定义如下:

4.1.2。问题部分格式

问题部分用于在大多数查询中携带“问题”,即 ,即定义所要求问题的参数。部分 包含QDCOUNT(通常为1)的条目,每个格式如下:

       1 1 1 1 1 1 
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
|            | 
/     QNAME     /
/           /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
|      QTYPE      | 
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
|      QCLASS     | 
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 

其中:

QNAME域名表示作为标签的序列, 其中 每个标签包含一个长度的八位字节,然后是 个八位字节。域名以 零长度八位字节为根的空标签结束。注意 该字段可能是奇数个八位字节;没有 使用填充。

QTYPE指定 查询类型的两个八位字节代码。 该字段的值包括对 TYPE字段有效的所有代码,以及 可以匹配多个类型的RR的一些更一般的代码。

莫卡派乔斯[页 28] RFC 1035域实现和规范
1987年11月

QCLASS两个八位字节代码,指定该类的 查询。 例如,Internet的QCLASS字段为IN。 ....

然而,你可能会得到自定义[higly不大可能]解析器是mainitain自己的高速缓存,并支持批量传输作为其规范微张结束。我不知道是否有任何存在。也许你可以写一个:) ...有关解析器的更多信息,请参阅此部分的第5部分RFC

最简单的解决方案是使用前面建议的线程。

编辑: 我想这个故事的寓意是,DNS服务器不能接受批量请求。这是有道理的,否则攻击者可能很容易从单个DNS服务器请求太多信息

+1

即使批量解析不可行,也可以通过使用配置良好的DNS服务器大大提高查找速度。使用Google的DNS,我们能够每分钟处理数千个DNS。 – Exupery