如何优化百万级DNS查询效率?检测AlexaTop1M域名DMARC状态
优化Alexa Top 1M域名DMARC检测效率方案
问题现状
需要检测Alexa Top 1M域名中启用DMARC的数量,通过dnsPython查询_dmarc.xxx子域的TXT记录,后续结果存入DynamoDB或Postgres。当前代码每分钟仅完成440次查询,跑完1M条数据需约26小时,效率亟待提升。现有代码存在并发调用错误,且未针对IO密集型的DNS查询做优化。
核心优化点及代码修复
1. 修复并发执行逻辑错误
现有代码中ProcessPoolExecutor的使用完全错误:循环内直接调用runDNS(domain[0])是同步执行,而非提交异步任务;且executor.map的参数传递不符合API要求。同时,DNS查询是IO密集型任务,用ThreadPoolExecutor比进程池更高效(进程池开销远大于线程池,仅适合CPU密集场景)。
2. 复用DNS客户端实例
原代码每次查询都新建DNS()实例,会重复建立DNS连接、初始化配置,浪费资源。改为复用单个客户端实例,减少初始化开销。
3. 配置合理的DNS查询参数
设置DNS查询超时时间,避免单个慢查询阻塞整体进度;启用DNS缓存,重复查询同一域名时直接返回缓存结果。
4. 正确同步进度条
结合tqdm和executor.map,确保进度条准确反映任务完成情况。
优化后完整代码
import csv import tqdm from utils.dns import DNS from concurrent.futures import ThreadPoolExecutor # 预加载域名列表 with open('../data/top-1m.csv', 'r') as f: reader = csv.reader(f) # 假设CSV格式为「排名,域名」,提取域名列表 domains = [domain for _, domain in reader] # 初始化DNS客户端,复用实例减少开销 dns_client = DNS() def runDNS(domain): try: # 设置3秒超时,避免慢查询拖慢整体进度 return domain, dns_client.query(f"_dmarc.{domain}", "TXT", timeout=3) except Exception as e: # 捕获查询失败场景,返回域名和错误信息 return domain, str(e) # 执行并发查询 with tqdm.tqdm(total=len(domains), desc="检测DMARC状态") as pbar: # 线程数建议设100-200,过高易被DNS服务器限流 with ThreadPoolExecutor(max_workers=150) as executor: # 批量提交任务,每完成一个更新进度条 for result in executor.map(runDNS, domains): domain, dmarc_record = result # 可先将结果存入内存列表,积累到指定数量后批量写入数据库 pbar.update(1)
额外效率提升建议
- 改用异步DNS库:用
aiodns结合asyncio实现异步查询,并发效率比线程池更高,适合超大规模域名检测。 - 搭建本地DNS缓存:部署dnsmasq等本地缓存服务器,减少重复DNS查询的网络延迟。
- 数据库批量写入:将查询结果先缓存到内存列表,每积累1000-5000条再批量写入数据库,避免单条写入的IO开销。
- 添加重试机制:针对超时、临时错误的查询添加重试逻辑,同时控制查询速率,避免被公共DNS服务器限流。
- 拆分数据集并行处理:将1M域名拆分为多个小文件,用多进程+多线程组合的方式并行处理,进一步提升吞吐量。
内容的提问来源于stack exchange,提问作者PrettyNewbieAtThis
相关产品推荐
相关产品推荐

