Requests: Trop de fichiers ouverts

CrĂ©Ă© le 5 nov. 2011  Â·  81Commentaires  Â·  Source: psf/requests

Je construis un gĂ©nĂ©rateur de charge de base et j'ai commencĂ© Ă  rencontrer des limites de descripteurs de fichiers, je n'ai pas vu de documentation sur la façon de libĂ©rer des ressources, donc soit je le fais mal et les documents doivent ĂȘtre mis Ă  jour, soit les demandes fuient des descripteurs de fichiers quelque part (sans support pour keepalive, je ne comprends pas trĂšs bien pourquoi des fichiers seraient laissĂ©s ouverts)

Bug Contributor Friendly

Commentaire le plus utile

"Trop de fichiers ouverts" est le résultat du bogue causé par le maintien des sockets dans CLOSE_WAIT.
Donc, ulimit ne résoudra pas simplement une solution de contournement.

Tous les 81 commentaires

OĂč utilisez-vous requests.async ?

non, toutes les demandes Ă©taient raisonnablement simples requests.get / requests.post, j'en vois encore quelques-unes

$ lsof | grep localhost | wc -l
110

tous sauf 4/5 d'entre eux sont du format

Python    82117 daleharvey  123u    IPv4 0xffffff800da304e0       0t0      TCP localhost:61488->localhost:http (CLOSE_WAIT)

Je suis un peu dĂ©concertĂ© par cela, pour ĂȘtre honnĂȘte.

Hah malade prendre une autre photo pour le reproduire de maniĂšre fiable, si je ne peux pas me fermer

J'ai vu cela m'arriver, mais uniquement lorsque j'utilise le module async avec plus de 200 connexions simultanées.

Salut,
J'ai eu exactement le mĂȘme problĂšme en utilisant les requĂȘtes et le patching de singe avec gevent: certaines connexions restent dans CLOSE_WAIT.
Peut-ĂȘtre un problĂšme avec gevent donc.

Cela peut ĂȘtre un problĂšme de ulimit -n. Essayez avec une valeur plus Ă©levĂ©e.

"Trop de fichiers ouverts" est le résultat du bogue causé par le maintien des sockets dans CLOSE_WAIT.
Donc, ulimit ne résoudra pas simplement une solution de contournement.

@tamiel comment résoudre ce problÚme?

Je vais faire plus de tests dĂšs que possible et essayer de corriger.

Je l'ai examinĂ© et semble ĂȘtre un problĂšme avec toutes les bibliothĂšques utilisant httplib.HTTPSConnection.

Publié un exemple ici:

https://gist.github.com/1512329

Je viens de rencontrer une erreur trĂšs similaire en utilisant un pool asynchrone avec uniquement des connexions HTTP - j'Ă©tudie toujours, mais en passant une taille de pool Ă  async.map, l'erreur se reproduit rapidement.

Des correctifs Ă  cela? Cela rend les requĂȘtes inutilisables avec gevent.

Tout tourne autour des CLOSE_WAIT s. Il suffit de les fermer. Je ne sais pas pourquoi ils sont toujours ouverts.

Est-ce un problĂšme urllib3? Devoir les fermer nous-mĂȘmes n'est pas une bonne idĂ©e Ă  mon avis.

C'est plus un problÚme général. Nous pouvons garder la conversation ici.

Ok juste pour vous donner une perspective, nous essayons de passer de httplib2 aux requĂȘtes, et nous ne voyons pas ce problĂšme avec httplib2. Ce n'est donc pas un problĂšme gĂ©nĂ©ral Ă  coup sĂ»r.

En général, je veux dire que c'est un problÚme trÚs grave qui affecte toutes les personnes impliquées.

alors comment pouvons-nous rĂ©soudre ce problĂšme? nous voulons vraiment utiliser les requĂȘtes + le sommeil pour aller de l'avant

J'adorerais connaßtre la réponse à cela.

La fuite semble ĂȘtre due Ă  la gestion de la redirection interne, ce qui entraĂźne la gĂ©nĂ©ration de nouvelles demandes avant que les rĂ©ponses en attente aient Ă©tĂ© consommĂ©es. Lors des tests, acdha @ 730c0e2e2bef77968a86962f9d5f2bebba4d19ec a un

Cela a nécessité des changements à deux endroits ce qui me donne envie de refactoriser légÚrement l'interface mais je n'ai plus le temps de continuer actuellement.

399 a un correctif qui fonctionne bien dans mon gĂ©nĂ©rateur de charge asynchrone (https://github.com/acdha/webtoolbox/blob/master/bin/http_bench.py) avec des milliers de requĂȘtes et un faible ulimit fd

J'ai rencontrĂ© le mĂȘme problĂšme lors de l'utilisation d'async - a supprimĂ© une solution de contournement en segmentant les demandes et en supprimant les rĂ©ponses / en appelant gc.collect

Je crois que je rencontrais cela aujourd'hui en me connectant Ă  un serveur sous licence qui n'autorise que 5 connexions.

En utilisant async, je n'ai pu OBTENIR que 4 choses avant qu'il ne s'arrĂȘte pendant 60 secondes.

En utilisant le GET normal avec consommation, je pouvais récupérer environ 150 choses en série en moins de 40 secondes.

Je n'ai pas encore fait mon kludge depuis que j'ai vu ce problĂšme.

Je viens de recevoir cette erreur lors de l'utilisation d'ipython et j'ai reçu ce message. Il s'agit simplement de faire chaque demande une à la fois, mais je pense que j'ai obtenu quelque chose de similaire en utilisant async.

ERROR: Internal Python error in the inspect module.
Below is the traceback from this internal error.
Traceback (most recent call last):
    File "/Library/Python/2.7/site-packages/IPython/core/ultratb.py", line 756, in structured_traceback
    File "/Library/Python/2.7/site-packages/IPython/core/ultratb.py", line 242, in _fixed_getinnerframes
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 1035, in getinnerframes
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 995, in getframeinfo
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 456, in getsourcefile
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 485, in getmodule
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 469, in getabsfile
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.py", line 347, in abspath
OSError: [Errno 24] Too many open files

Unfortunately, your original traceback can not be constructed.

Bizarrement, je pense qu'en n'utilisant que l'interprĂ©teur Python normal, j'obtiens une "Erreur Max Retries", mais je pense que c'est un autre problĂšme avec moi faisant des requĂȘtes sur le mĂȘme domaine, mais pas sĂ»r.

J'ai rencontrĂ© ceci sur le premier projet que j'avais oĂč allow_redirects Ă©tait True; il semble ĂȘtre causĂ© par la chaĂźne de redirection qui fuit des objets de rĂ©ponse qui ne sont pas libĂ©rĂ©s mĂȘme avec prefetch = True. Cela a rĂ©solu le problĂšme lors de mes tests initiaux:

        [i.raw.release_conn() for i in resp.history]
        resp.raw.release_conn()

Hmmm ..

RĂ©glage @acdha :

requests.defaults.defaults['allow_redirects'] = False

avant de faire des demandes, cela entraĂźne toujours la mĂȘme erreur, mais je pense que ce n'est pas une option pour mon implĂ©mentation car toutes les demandes que je fais nĂ©cessiteront une redirection = /

@dalanmiller Comment async.map avec un hook de rĂ©ponse et il _ semble_ ĂȘtre plus stable en utilisant une simple boucle sur async.imap :

for resp in requests.async.imap(reqs, size=8):
    try:
        print resp.status_code, resp.url
    finally:
        [i.raw.release_conn() for i in resp.history]
        resp.raw.release_conn()

@acdha

J'utilisais juste une boucle for Ă  travers une liste d'url et faisais un request.get sur chacun avec mes paramĂštres et autres.

for u in urls:
    response_list.append(requests.get(u))

J'ai essayĂ© d'utiliser votre pĂąte et cela fonctionne pour environ 50 requĂȘtes dans ma liste de 900 longueurs, jusqu'Ă  ce que je commence Ă  avoir des "erreurs de tentatives maximales dĂ©passĂ©es avec l'URL" pour le reste. C'est une erreur assez standard pour frapper le mĂȘme domaine Ă  plusieurs reprises, non?

HĂ©, j'explorais une Ă©norme liste d'URL, 35k, et j'ai eu cette mĂȘme erreur sur _some_ de demandes.

Je reçois des URL par blocs de 10, comme ceci:

responses = requests.async.map([requests.async.get(u, params=self.params()) for u in chunk]) # chunk is a list of 10

Quelque part dans la plage de 20k, j'ai commencé à avoir l'erreur 24, puis ça allait jusqu'à 30k et encore une fois.

Y a-t-il plus d'informations qui vous intéresseraient pour le réduire?

requests.async est parti. Vous pourriez envisager de passer aux grequests.

TrĂšs bien, merci. Il serait bon de mentionner cela dans la documentation.

Une sorte de noob quand il s'agit de Pull Requests et d'écriture de la documentation, mais je l'ai essayé et je l'ai envoyé. Veuillez commenter ou critiquer :)

https://github.com/kennethreitz/requests/pull/665

Ok, cela se produit mĂȘme sans utiliser async, avec juste requests.get, aprĂšs 6K demandes.

Je m'en doutais.

Pour moi, l'erreur «Trop de fichiers ouverts» s'est produite aprÚs avoir téléchargé exactement 1k fichiers. Ma solution était de désactiver la propriété keep-alive, en recevant toujours des demandes par morceaux ( @acdha merci pour l'indice). lsof -p PID | wc -l montre un nombre non croissant de connexions pendant l'exécution.

rsess = requests.session()
rsess.config['keep-alive'] = False

rs = [grequests.get(l, session=rsess) for l in links]

for s in chunks(rs,100):
    responses = grequests.map(s, size=concurrency)
    for r in responses:
        try:
            print(r.status_code, r.url)
        finally:
            r.raw.release_conn()

[1] segmentation: http://stackoverflow.com/a/312464

Fermeture en reportant au correctif urllib3.

@kennethreitz Quel est le numéro de problÚme de urllib3?

On dirait que c'est le problĂšme http://bugs.python.org/issue16298

@silvexis pourrait trĂšs bien ĂȘtre liĂ© au bogue urllib3, maintenant je souhaite juste que quelqu'un ait rĂ©pondu @ piotr-dobrogost: P

Quelqu'un d'autre rencontre-t-il toujours ce problĂšme?

Je n'en ai entendu aucun rapport. Es-tu?

C'est un problĂšme de config box, pas de framework. Regardez la configuration du noyau de votre systĂšme d'exploitation. En BSD, il s'appelle kern.maxfiles . Il y a un fil sur ulimit dans les systĂšmes Linux: http://stackoverflow.com/questions/34588/how-do-i-change-the-number-of-open-files-limit-in-linux
J'espĂšre que cela aide, et je ne sais pas comment modifier ce paramĂštre sous Windows.

Avec l'avertissement que nous exĂ©cutons toujours une ancienne version de requĂȘtes, nous avons le code horrible suivant en place pour gĂ©rer cela:

    if self._current_response is not None:
            # Requests doesn't have a clean API to actually close the
            # socket properly. Dig through multiple levels of private APIs
            # to close the socket ourselves. Icky.
            self._current_response.raw.release_conn()
            if self._current_response.raw._fp.fp is not None:
                sock = self._current_response.raw._fp.fp._sock
                try:
                    logger.debug('Forcibly closing socket')
                    sock.shutdown(socket.SHUT_RDWR)
                    sock.close()
                except socket.error:
                    pass

(Je pense que self._current_response est l'objet de rĂ©ponse des requĂȘtes)

Hmm, oĂč est la chaĂźne de fermeture cassĂ©e? Nous avons une mĂ©thode Response.close() qui appelle release_conn() , alors que faut-il se passer dans release_conn() pour que cela fonctionne?

@Lukasa cela a Ă©tĂ© dĂ©finitivement corrigĂ© dans urllib3 car je faisais partie de la discussion. Avec une tendance Ă  ĂȘtre prudente dans mon estimation, je dirais que c'est lĂ  depuis les demandes 1.2.x sinon 1.1.x.

Ouais, je pensais que c'était réglé. Sauf si nous voyons quelque chose sur 1.2.3, je vais continuer à supposer que cela est corrigé.

Je vois une fuite CLOSE_WAIT avec 2.0.2, avez-vous des tests unitaires pour vous assurer qu'il n'y a pas de régression sur le sujet?

Non, nous ne le faisons pas. AFAIK urllib3 non plus. Pouvez-vous reproduire facilement votre fuite?

Nous utilisons la requĂȘte dans notre application interne depuis lundi et atteignons les 1024 fichiers max aujourd'hui.

2 heures aprÚs le redémarrage, nous avons 40 CLOSE_WAIT comme indiqué par lsof.

Je pense donc que nous pourrons reproduire dans un environnement de développement, oui. Je vous tiendrai au courant

@tardyp aussi, comment as-tu installĂ© les requĂȘtes? Je pense que tous les responsables du paquet OS suppriment urllib3. S'ils ne le tiennent pas Ă  jour et que vous utilisez une ancienne version, cela pourrait en ĂȘtre la cause. Si vous utilisez pip, n'hĂ©sitez pas Ă  ouvrir un nouveau numĂ©ro pour le suivre au lieu d'ajouter une discussion sur celui-ci.

J'ai installé avec pip, mais j'utilise python 2.6, j'ai vu un correctif sur python2.7 pour
ce bug. Avez-vous monkeypatch pour une version plus ancienne?

Pierre

Le vendredi 29 novembre 2013 Ă  17:33, Ian Cordasco [email protected] a Ă©crit:

@tardyp https://github.com/tardyp Ă©galement, comment avez-vous installĂ© les requĂȘtes? je
pense que tous les mainteneurs de paquet OS suppriment urllib3. S'ils ne le font pas
gardez cela Ă  jour et vous utilisez une ancienne version, cela pourrait ĂȘtre le
cause à la place. Si vous utilisez pip, n'hésitez pas à ouvrir un nouveau numéro à
suivez ceci avec au lieu d'ajouter une discussion sur celui-ci.

-
RĂ©pondez directement Ă  cet e-mail ou consultez-le sur Gi tHubhttps: //github.com/kennethreitz/requests/issues/239#issuecomment -29526302
.

@tardyp veuillez ouvrir un nouveau problÚme avec autant de détails que possible, y compris si les demandes que vous faites ont des redirections et si vous utilisez gevent. De plus, tous les détails sur le systÚme d'exploitation et un exemple de la façon de le reproduire seraient fantastiques.

FYI https://github.com/shazow/urllib3/issues/291 a été annulé en raison de bugs.

Devrions-nous rouvrir cela?
J'ai le mĂȘme problĂšme!

@polvoazul Il n'y a aucun moyen que ce soit le mĂȘme problĂšme, qui a Ă©tĂ© signalĂ© Ă  l'origine en 2011, donc je ne pense pas que la rĂ©ouverture soit correcte. Cependant, si vous exĂ©cutez la version actuelle des requĂȘtes (2.4.3) et que vous pouvez reproduire le problĂšme, ouvrir un nouveau problĂšme serait correct.

@Lukasa j'ai besoin de votre aide。 j'utilise eventlet + requĂȘtes  qui crĂ©ent toujours autant de chaussettes qui ne peuvent pas identifier le protocole。 mes requĂȘtes sont 2.4.3, les requĂȘtes eventlet + sont-elles Ă  l'origine de ce problĂšme?

Je suis dĂ©solĂ© @mygoda , mais c'est impossible Ă  savoir. Si vous ne limitez pas le nombre de demandes qui peuvent ĂȘtre en attente Ă  un moment donnĂ©, c'est certainement possible, mais c'est un problĂšme d'architecture qui ne relĂšve pas des demandes.

@Lukasa merci。 je pense que mon problùme est similaire avec ça 。 mon projet est pyvmomi . cette connexion est une connexion longue. Je ne comprends toujours pas pourquoi tant de personnes ne peuvent pas identifier la chaussette de protocole

Avoir le mĂȘme problĂšme maintenant, exĂ©cuter 120 threads, causer plus de 100000 fichiers ouverts, une solution pour le moment?

@mygoda vous utilisez des pĂ©riodes gĂ©niales。

@ 1a1a11a _Quels_ fichiers avez-vous ouverts? Ce serait une premiĂšre Ă©tape utile pour comprendre ce problĂšme.

@ 1a1a11a quelle version des requĂȘtes utilisez-vous? Quelle version de python? Quel systĂšme d'exploitation? Pouvons-nous obtenir des informations?

J'utilise request 2.9.1, python 3.4, ubuntu 14.04, en gros, j'écris un robot d'exploration en utilisant 30 threads avec des proxies pour explorer certains sites Web. Actuellement, j'ai ajusté la limite de fichiers par processus à 655350, sinon cela signalera une erreur.

Je reçois toujours l'erreur "Impossible d'Ă©tablir une nouvelle connexion: [Errno 24] Trop de fichiers ouverts" de requests.packages.urllib3.connection.VerifiedHTTPSConnection. "J'utilise Python 3.4, demande 2.11.1 et demandes-futures 0.9.7. J'apprĂ©cie que les requĂȘtes-futures soit une bibliothĂšque distincte, mais il semble que l'erreur provienne de requĂȘtes. J'essaie de faire 180 000 requĂȘtes asynchrones via SSL. J'ai divisĂ© ces requĂȘtes en segments de 1000, donc je ne passez aux 1000 prochains objets qu'une fois que tous les objets futurs ont Ă©tĂ© rĂ©solus. J'exĂ©cute Ubuntu 16.04.2 et ma limite de fichiers ouverts par dĂ©faut est de 1024. Il serait bon de comprendre la raison sous-jacente de cette erreur. La bibliothĂšque de requĂȘtes crĂ©e-t-elle un fichier ouvert pour chaque requĂȘte individuelle? Et si oui, pourquoi? S'agit-il d'un fichier de certificat SSL? Et la bibliothĂšque de requĂȘtes ferme-t-elle automatiquement ces fichiers ouverts lorsque le futur objet est rĂ©solu?

Requests ouvre de nombreux fichiers. Certains de ces fichiers sont ouverts pour les certificats, mais ils sont ouverts par OpenSSL et non par des requĂȘtes, donc ils ne sont pas conservĂ©s. De plus, les requĂȘtes ouvriront Ă©galement, si nĂ©cessaire, le fichier .netrc , le fichier hosts et bien d'autres.

Vous serez mieux servi en utilisant un outil comme strace pour dĂ©terminer quels fichiers sont ouverts. Il existe une liste stricte d'appels systĂšme qui conduisent Ă  l'allocation de descripteurs de fichiers, vous devriez donc ĂȘtre raisonnablement en mesure de les Ă©numĂ©rer rapidement. Cela vous permettra Ă©galement de savoir s'il y a un problĂšme ou non. Mais, oui, je m'attendrais Ă  ce que si vous Ă©tablissez activement 1000 connexions via HTTPS, Ă  la charge maximale, nous pourrions facilement utiliser plus de 1000 FD.

J'ai Ă©galement luttĂ© avec ce problĂšme et j'ai trouvĂ© que l'utilisation de opensnoop sur OS X fonctionnait trĂšs bien pour me permettre de voir ce qui se passait si quelqu'un rencontrait les mĂȘmes problĂšmes.

Je vois aussi frĂ©quemment cette erreur lorsque j'appelle Ă  plusieurs reprises requests.post(url, data=data) vers un serveur HTTP (pas HTTPS). ExĂ©cution sur Ubuntu 16.04.3, Python 3.5.2, requĂȘtes 2.9.1

Qu'est-ce que data ?

Texte de quelques centaines de Ko

Pas un objet fichier?

Non, je forme une grande requĂȘte en mĂ©moire.

Exécutez-vous ce code dans plusieurs threads?

Non, fil de discussion unique, publication sur localhost

Il nous semble presque impossible de divulguer autant de FD Ă  ce moment-lĂ : nous devrions utiliser Ă  plusieurs reprises la mĂȘme connexion TCP ou la fermer de maniĂšre agressive. Vous voulez vĂ©rifier ce que fait votre serveur?

J'ai ce problĂšme. Python 2.7, requĂȘtes 2.18.4, urllib3 1.22.
Exécution de code multi-thread (non multi-traité). Connexion à au plus 6 URL à la fois, création et fermeture manuelle d'une nouvelle session pour chacune.

J'ai le mĂȘme problĂšme sur Python 3.5 , requests==2.18.4

@mcobzarenco ĂȘtes-vous sĂ»r de fermer (implicitement) la connexion sous-jacente de la rĂ©ponse? Le simple fait de renvoyer la rĂ©ponse ne fermera pas la connexion. Lors de la lecture de response.content, les donnĂ©es sont rĂ©ellement lues et aprĂšs cela, le socket ne restera pas dans CLOSE_WAIT.

Cette page vous a été utile?
0 / 5 - 0 notes