Python异步反向DNS查找

3

我希望在短时间内完成大量的反向DNS查找。目前,我已经使用socket.gethostbyaddr和concurrent.futures线程池实现了异步查找,但是仍然没有达到期望的性能。例如,脚本在2500个IP地址上运行了约22分钟。

我想知道是否有更快的方法来完成这项任务,而无需使用像adns-python这样的工具。我在http://blog.schmichael.com/2007/09/18/a-lesson-on-python-dns-and-threads/上找到了一些额外的背景信息。

代码片段:

ips = [...]
with concurrent.futures.ThreadPoolExecutor(max_workers = 16) as pool:
    list(pool.map(get_hostname_from_ip, ips))
def get_hostname_from_ip(ip):
    try:
        return socket.gethostbyaddr(ip)[0]
    except:
        return ""

我认为问题的一部分是许多IP地址无法解析并超时。我尝试了以下操作:

socket.setdefaulttimeout(2.0)

但似乎它没有产生任何效果。

3个回答

3
我发现我的主要问题在于IP地址无法解析,因此套接字没有遵守其设置的超时时间,在30秒后失败。请参见Python 2.6 urlib2 timeout issue
由于缺乏对IPv6的支持(没有补丁),adns-python是不可行的。
在搜索了一番之后,我找到了这个:使用dnspython进行反向DNS查找,并在我的代码中实现了一个类似的版本(他的代码还使用了可选的线程池,并实现了超时)。
最终,我使用dnspython和concurrent.futures线程池进行异步反向DNS查找(参见Python: Reverse DNS Lookup in a shared hostingDnspython: Setting query timeout/lifetime)。以1秒为超时时间,这使2500个IP地址的运行时间从大约22分钟缩短到了大约16秒。这种巨大的差异可能归因于套接字上的全局解释器锁和30秒的超时时间。
代码段:
import concurrent.futures
from dns import resolver, reversename
dns_resolver = resolver.Resolver()
dns_resolver.timeout = 1
dns_resolver.lifetime = 1
ips = [...]
results = []

with concurrent.futures.ThreadPoolExecutor(max_workers = 16) as pool:
    results = list(pool.map(get_hostname_from_ip, ips))

def get_hostname_from_ip(ip):
    try:
        reverse_name = reversename.from_address(ip)
        return dns_resolver.query(reverse_name, "PTR")[0].to_text()[:-1]
    except:
        return ""

1

1
我对Python GIL的理解非常有限,但由于大部分时间都花在IO阻塞上,这个问题不应该很重要吧? 编辑:我使用类似的代码进行异步http请求,似乎效果不错。 - Wert
你找出问题所在了吗? - Addison
是的,出现了IP无法解析的问题。套接字忽略了它们的超时时间,有些套接字要花费长达30秒才会失败。在浏览周围的内容时,我发现了这个网址:https://dev59.com/zGzXa4cB1Zd3GeqPW7px,阐述了这个问题。我将发布我的解决方案。 - Wert

0

请使用异步DNS,其他方式会导致性能极差。


我发现使用dnspython得出的答案性能相当不错。我想知道adns-python会怎样比较。 - Wert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接