Dns.BeginGetHost ...方法阻塞

时间:2012-07-14 03:20:22

标签: c# asynchronous dns blocking

所以我想做一个很多的DNS查询。

我从Begin/EndGetHostEntry异步对中创建了(数千个)任务:

var lookupTask = Task.Factory.FromAsync
   ( Dns.BeginGetHostEntry,
     (Func<IAsyncResult, IPHostEntry>) Dns.EndGetHostEntry,
     "google.com", 
     null
   )

然后Task.WaitAll完成所有事情。我看到ThreadPool线程的数量急剧增加以响应我的请求。如果我强制ThreadPool minThreads为500,则工作量的消耗会大大加快。所有这些都指向Dns异步实现中的阻塞。

如果我用managed Dns client替换Dns,我可以使用ThreadPool中只有1或2个线程消耗相同的工作负载,而cpu几乎空闲。

问题是,Dns实施绝对是许多网络API(HttpWebRequestWebClientHttpClient)的核心,而且它们似乎都受此影响问题。如果我使用第三方库解析DNS,并使用IP地址作为uri中的主机发出HTTP请求,那么更改Host标头以修复请求,与任何涉及{{{{{{{{{ 1}}。

这里发生了什么?我错过了什么或System.Net.Dns实施真的那么糟糕吗?

4 个答案:

答案 0 :(得分:3)

System.Net.Dns使用Windows gethostbyname函数进行DNS查询,并且根本没有异步函数。 BeginGetHostEntry函数基本上只是线程池上同步GetHostEntry调用的包装器。

上次我遇到慢速/同步DNS查找的同样问题时,我最终只使用了一个大型ThreadPool来完成工作,因为没有一个内置的Windows或.net DNS相关的功能支持正确的(并行)异步执行。

答案 1 :(得分:2)

这可能不是一个完整的答案,但是:

在.net内解析的DNS,打开与dns的连接,询问问题并关闭。您链接的托管DNS客户端的示例清楚地表明,此库建立了连接,然后在保持打开状态时,您可以提出许多问题,就像这样做

nslookup -

>hostname1
>hostname2
...
在dos / unix下

通常在打开它时可能需要一段时间,通过多次调用已经打开的连接,您不必对自己进行反向连接,并且本身和所有其他垃圾连接到dns服务器时首先执行连接。例如:如果我列表中的第一个DNS服务器忙,我的机器通常需要时间来解析到可用的其他服务器,因此,如果您在.net下每次查看时都遇到过这种情况。库,您会看到漫长的等待,并且需要很多线程,当然还会增加CPU负载,但实际上并没有太多。

实施并非“糟糕”,它不是为多个批处理作业而设计的。除非有电话我也错过了。

答案 2 :(得分:1)

我没有1000个URL的数据集来测试您的代码,并且重复请求相同的URL会导致命中缓存(而不是我的网络的DNS服务器)。因此,请在测试后对成功/失败进行评论。

我对此(或任何其他假设)进行测试的建议是创建一个包含1000个URL的测试数据集,并对其进行编号。然后设置一些日志记录(即:log4net或类似的)并在每个DNS解析任务完成时写出一条语句,包括已完成任务的索引。我相信你会看到这1000个任务完全同步完成。或者至少每组2-8个异步结果,其中2-8的所有组都是同步的。

原因是连接管理。在内部.Net只允许同一端点的这么多并发连接。如果打开与dns服务器的1000连接,则一次只能创建几个连接。其余的需要等到一些早期的连接关闭,然后才能建立到同一端点(您的DNS服务器)的另一个连接。

这种限制通常有充分的理由。但对于像DNS这样的数据量相对较少且服务请求成本相对较低的情况,我可以打开这个限制,最多可以说100-200个DNS请求。

您可以使用以下配置打开此限制:

<configuration>
  <system.net>
    <connectionManagement>
      <add address="*" maxconnection="100"/>
    </connectionManagement>
  </system.net>
</configuration>

MSDN for System.Net.ConnectionManagement

您可以指定特定的端点地址(URL或IP)以及与该地址的最大连接数。一些负载测试应用程序将只使用通配符*和65535来为所有内容打开它。

我怀疑托管DNS实施要么重用与DNS服务器相同的连接,要么具有如上所述的内部配置。

您可能在问题中包含的更多详细信息是您是在同一物理网络上查询本地DNS服务器,还是从本地ISP或OpenDNS等公共DNS服务器查询DNS服务器。这些特定DNS服务器的配置可能会有自己的限制(ISP可能会限速,我不知道)。

答案 3 :(得分:0)

当dns查找是异步的时,正常使用通常不会有更好的性能,因为代码需要答案才能继续工作。平行无益。只有当你只想查找多个DNS时,这才成为一个真正的问题。

为什么它有点慢,并提高性能检查这个SO问题和答案 GetHostEntry is very slow