-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Concurrent GET requests lead to ClientConnectorError(8, 'nodename nor servname provided, or not known') #3549
Comments
Thanks for comprehensive report. |
After some further investigation, this issue does not appear to be directly caused by
Firstly, for those looking to get some beefed-up DNS servers (I will probably not go that route), the big-name options seem to be:
(Good intro to DNS for those like me for whom network concepts are lacking.) The first thing that I did was to run the above on a beefed-up AWS EC2 instance - h1.16xlarge running Ubuntu which is IO optimized. I can't say this in itself helped, but it certainly cannot hurt. I'm not too familiar with the default DNS server used by an EC2 instance, but the OSError with errno == 8 from above went away when replicating the above script. However, that presented a new exception in its place, OSError with code 24, "Too many open files." My hotfix solution (not arguing this is the most sustainable or safest) was to increase the max file limits. I did this via:
I am admittedly feeling around in the dark, but coupling this with |
Thanks for sharing your solution! |
Thank you for this. It was the only clue I found as to why I was getting this error, which had to do with the number of open files, and not at all with a DNS error as indicated. |
The solution I found was: One, if possible don't create a new ClientSession object per request, if you can re-use the same session that fixed the DNS error for me. For the file error I limited the number of requests I was issuing using an asyncio.Semaphore, with a value of like 1k. |
I was also getting this, and again nothing to do with DNS, but the connection pool limit on the shared session (docs). You can make it unlimited like this: connector = aiohttp.TCPConnector(limit=0) # need unlimited connections
async with aiohttp.ClientSession(connector=connector) as session:
... You can also change the open file limit from within you python code with the resource library. You can't adjust the hard limit so if it's not RLIM_INFINITY on your platform you'll have to adjust that (or take the value from import resource
resource.setrlimit(resource.RLIMIT_NOFILE, (2 ** 14, resource.RLIM_INFINITY)) |
Although I have tried semaphore approach in bsolomon1124's comment and the advices given in tmo-trustpilot's comment, and additionally: i'm not creating a new session per request, I'm reusing these sessions -> I'm still getting the error ('nodename nor servname provided, or not known'). Any idea why? Or any update on the topic? |
I had some luck using @tmo-trustpilot's solution. I used a semaphore of 32. The default
I don't understand how limiting the connections to 32 would somehow consume more than 256 of the available open file resources. My specific use case is calling a little over 2k URLs with different hosts. I did not seem to encounter this when calling the same host. Does that make a difference? Is the |
I may have answered my own question. I just saw this in the docs under the "Client Quickstart" guide:
I would love to get some feedback on this, but it seems like I may have to map a session for every host. |
Sorry for the spam. I believe I better understand what's going on. Please let me know if this is correct. I was making thousands of requests against 2,637 unique domains. Is it possible that a new file descriptor is opened for each domain? If that's the case, that would definitely explain the issue. I also created a proxy wrapper class around the Time to execute when using proxy:
Time to execute w/o proxy:
I hope this helps someone else. In short, @tmo-trustpilot's suggestion of increasing I would love to know if my assumption is correct regarding a new fd being created per host. |
OMG I'm such a dummy. I thought this was still an open issue... but, nope, it's closed. Well, prob won't get a response then. I have become "that person" reviving dead threads. fml 😂 |
Does
help here (if wanting to undertake a temporary (and per-shell) test)? |
Long story short
I am stumped by a problem seemingly related to
asyncio
+aiohttp
whereby, when sending a large number of concurrent GET requests, over 85% of the requests raise anaiohttp.client_exceptions.ClientConnectorError
exception that ultimately stems fromwhile sending single GET requests or doing the underlying DNS resolution on the host/port does not raise this exception.
(But hey, at least we know that #2423 is working 😉 .)
Expected behaviour
Successful DNS resolution.
Actual behaviour
Currently, 21205 of 24934 input URLs fail resolution, raising from
aiohttp.TCPConnector._resolve_host()
coroutine.Steps to reproduce
While in my real code I'm doing a good amount of customization such as using a custom
TCPConnector
instance, I can reproduce the issue using just the "default"aiohttp
class instances & arguments, exactly as below.I've followed the traceback and the root of the exception is related to DNS resolution. It comes from the
_create_direct_connection
method ofaiohttp.TCPConnector
, which calls._resolve_host()
.I have also tried:
aiodns
sudo killall -HUP mDNSResponder
family=socket.AF_INET
as an argument toTCPConnector
(though I am fairly sure this is used byaiodns
anyway)ssl=True
andssl=False
All to no avail.
Full code to reproduce is below. The input URLs are at https://gist.github.com/bsolomon1124/fc625b624dd26ad9b5c39ccb9e230f5a.
Printing each exception string from
res
looks like:What's frustrating is that I can
ping
these hosts with no problem and even call the underlying._resolve_host()
:Bash/shell:
Python:
Information on the exception itself:
The exception is
aiohttp.client_exceptions.ClientConnectorError
, which wrapssocket.gaierror
as the underlyingOSError
.Since I have
return_exceptions=True
inasyncio.gather()
, I can get the exception instances themselves for inspection. Here is one example:Your environment
DNS info
Why do I not think this is a problem with DNS resolution at the OS level itself?
I can successfully ping the IP address of my ISP’s DNS Servers, which are given in (Mac OSX) System Preferences > Network > DNS:
The text was updated successfully, but these errors were encountered: