为了账号安全,请及时绑定邮箱和手机立即绑定

aiohttp 并发 GET 请求导致 ClientConnectorError

aiohttp 并发 GET 请求导致 ClientConnectorError

千万里不及你 2021-10-12 10:41:19
我被一个似乎与asyncio+相关的问题难住了aiohttp,当发送大量并发 GET 请求时,超过 85% 的请求会引发一个aiohttp.client_exceptions.ClientConnectorError异常,该异常最终源于socket.gaierror(8, 'nodename nor servname provided, or not known')发送单个 GET 请求或在主机/端口上执行底层 DNS 解析时不会引发此异常。在我的真实代码中,我进行了大量自定义,例如使用自定义TCPConnector实例,我可以仅使用“默认”aiohttp类实例和参数来重现该问题,如下所示。我遵循了回溯,异常的根源与 DNS 解析有关。它来自 的_create_direct_connection方法aiohttp.TCPConnector,它调用._resolve_host().我也试过:使用(和不使用) aiodnssudo killall -HUP mDNSResponder使用family=socket.AF_INET作为参数传递给TCPConnector(虽然我相当肯定,这是使用aiodns反正)。这使用2而不是该0参数的默认 int随着ssl=True和ssl=False一切都无济于事。要重现的完整代码如下。输入 URL 位于https://gist.github.com/bsolomon1124/fc625b624dd26ad9b5c39ccb9e230f5a。从res看起来像打印每个异常字符串:Cannot connect to host sigmainvestments.com:80 ssl:False [nodename nor servname provided, or not known]Cannot connect to host giaoducthoidai.vn:443 ssl:False [nodename nor servname provided, or not known]Cannot connect to host chauxuannguyen.org:80 ssl:False [nodename nor servname provided, or not known]Cannot connect to host www.baohomnay.com:443 ssl:False [nodename nor servname provided, or not known]Cannot connect to host www.soundofhope.org:80 ssl:False [nodename nor servname provided, or not known]# And so on...令人沮丧的是,我可以ping毫无问题地使用这些主机,甚至可以调用底层._resolve_host():重击/外壳: [~/] $ ping -c 5 www.hongkongfp.comPING www.hongkongfp.com (104.20.232.8): 56 data bytes64 bytes from 104.20.232.8: icmp_seq=0 ttl=56 time=11.667 ms64 bytes from 104.20.232.8: icmp_seq=1 ttl=56 time=12.169 ms64 bytes from 104.20.232.8: icmp_seq=2 ttl=56 time=12.135 ms64 bytes from 104.20.232.8: icmp_seq=3 ttl=56 time=12.235 ms64 bytes from 104.20.232.8: icmp_seq=4 ttl=56 time=14.252 ms--- www.hongkongfp.com ping statistics ---5 packets transmitted, 5 packets received, 0.0% packet lossround-trip min/avg/max/stddev = 11.667/12.492/14.252/0.903 msPython:
查看完整描述

1 回答

?
小怪兽爱吃肉

TA贡献1852条经验 获得超1个赞

经过进一步调查,此问题似乎不是由aiohttp/直接引起的,asyncio而是由以下两者引起的限制/限制:

  • DNS 服务器的容量/速率限制

  • 系统级别的最大打开文件数。

首先,对于那些希望获得一些增强的 DNS 服务器的人(我可能不会走那条路),大名鼎鼎的选择似乎是:

  • 1.1.1.1 (Cloudflare)

  • 8.8.8.8(谷歌公共 DNS)

  • 亚马逊 53 号公路

(对于像我这样缺乏网络概念的人来说,很好地介绍了 DNS。)

我做的第一件事是在增强的 AWS EC2 实例上运行上述内容 - h1.16xlarge 运行 IO 优化的 Ubuntu。我不能说这本身有帮助,但它肯定不会伤害。我对 EC2 实例使用的默认 DNS 服务器不太熟悉,但是在复制上述脚本时,上面带有 errno == 8 的 OSError 消失了。

然而,它出现了一个新的异常,OSError 代码为 24,“打开的文件太多”。我的修补程序解决方案(不认为这是最可持续或最安全的)是增加最大文件限制。我是通过以下方式做到的:

sudo vim /etc/security/limits.conf

# Add these lines

root    soft    nofile  100000

root    hard    nofile  100000

ubuntu    soft    nofile  100000

ubuntu    hard    nofile  100000


sudo vim /etc/sysctl.conf

# Add this line

fs.file-max = 2097152


sudo sysctl -p


sudo vim /etc/pam.d/commmon_session

# Add this line

session required pam_limits.so


sudo reboot

诚然,我在黑暗中感觉周围,但将其与asyncio.Semaphore(1024)(此处的示例)相结合导致上述两个异常中的 0 个被引发:


# Then call this from bulk_get with asyncio.Sempahore(n)

async def bounded_get(sem, url, session) -> str:

    async with sem:

        return await get(url, session)

在大约 25k 个输入 URL 中,只有大约 100 个 GET 请求返回异常,主要是由于这些网站被合法破坏,完成的总时间在几分钟内,我认为可以接受。


查看完整回答
反对 回复 2021-10-12
  • 1 回答
  • 0 关注
  • 1014 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信