5

出于分析目的,我想对大量 IP 执行反向 DNS 查找。“大”的意思,每小时至少有几万。我正在寻找提高处理速度的方法,即降低每批的处理时间。

将Dns.GetHostEntry的异步版本包装到可等待的任务中已经有很大帮助(与顺序请求相比),从而导致了 appox 的吞吐量。100-200 IP/秒:

static async Task DoReverseDnsLookups()
{
    // in reality, thousands of IPs
    var ips = new[] { "173.194.121.9", "173.252.110.27", "98.138.253.109" }; 
    var hosts = new Dictionary<string, string>();

    var tasks =
        ips.Select(
            ip =>
                Task.Factory.FromAsync(Dns.BeginGetHostEntry,
                    (Func<IAsyncResult, IPHostEntry>) Dns.EndGetHostEntry, 
                    ip, null)
                    .ContinueWith(t => 
                    hosts[ip] = ((t.Exception == null) && (t.Result != null)) 
                               ? t.Result.HostName : null));

    var start = DateTime.UtcNow;
    await Task.WhenAll(tasks);
    var end = DateTime.UtcNow;

    Console.WriteLine("Resolved {0} IPs in {1}, that's {2}/sec.", 
      ips.Count(), end - start, 
      ips.Count() / (end - start).TotalSeconds);
}

任何想法如何进一步提高处理速度?

例如,有没有办法将一批 IP 发送到 DNS 服务器?

顺便说一句,我假设在幕后,异步方法使用了I/O 完成端口- 如果我错了,请纠正我。

4

2 回答 2

5

您好,这里有一些提示,您可以改进:

  1. 在本地缓存查询,因为这些信息通常不会在几天甚至几年内发生变化。这样你就不必每次都解决。
  2. 大多数 DNS 服务器会自动缓存信息,因此下次它会很快解析。通常缓存是 4 小时,至少在 Windows 服务器上是默认的。这意味着如果您在短时间内批量运行此过程,如果您在一天中多次解析地址以允许 cahce 过期,它会执行得更好。
  3. 使用 Task Parallelism 很好,但您仍在询问机器上配置的相同 DNS 服务器。我认为让两台机器使用不同的 DNS 服务器会改进这个过程。

我希望这有帮助。

于 2014-05-30T01:24:28.697 回答
2
  • 与往常一样,我建议使用TPL Dataflow'sActionBlock而不是一次触发所有请求并等待所有请求完成。使用ActionBlockhighMaxDegreeOfParallelism可以让TPL自己决定同时触发多少个调用,这可以更好地利用资源:

var block = new ActionBlock<string>(
    async ip => 
    { 
        try
        {
            var host = (await Dns.GetHostEntryAsync(ip)).HostName;
            if (!string.IsNullOrWhitespace(host))
            {
                hosts[ip] = host;
            }
        }
        catch
        {
            return;
        }
    },
    new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 5000});
  • 我还建议添加一个缓存,并确保您不会多次解析同一个 ip。

  • 当您使用 .net 的Dns类时,它在 DNS 旁边包含一些回退(例如 LLMNR),这使得它非常慢。如果您只需要 DNS 查询,您可能需要使用ARSoft.Tools.Net等专用库。


PS:关于您的代码示例的一些评论:

  1. 你应该使用GetHostEntryAsync而不是FromAsync
  2. 延续可能会在不同的线程上运行,所以你真的应该使用ConcurrentDictionary.
于 2014-05-30T10:42:38.980 回答