Requests: Zu viele offene Dateien

Erstellt am 5. Nov. 2011  ·  81Kommentare  ·  Quelle: psf/requests

Ich baue einen Basisladegenerator auf und habe angefangen, auf Dateideskriptor-Grenzwerte zu stoßen. Ich habe keine Dokumentation zum Freigeben von Ressourcen gesehen. Entweder mache ich es falsch und die Dokumente müssen aktualisiert werden, oder bei Anfragen treten irgendwo Dateideskriptoren auf (ohne Unterstützung) für keepalive bin ich etwas verwirrt darüber, warum irgendwelche Dateien überhaupt offen bleiben würden)

Bug Contributor Friendly

Hilfreichster Kommentar

"Zu viele geöffnete Dateien" ist das Ergebnis des Fehlers, der durch Sockets in CLOSE_WAIT verursacht wird.
Ulimit behebt also nicht nur eine Problemumgehung.

Alle 81 Kommentare

Wo benutzt du requests.async ?

Nein, alle Anfragen waren einigermaßen einfach. request.get / request.post, ich sehe immer noch ein paar darin

$ lsof | grep localhost | wc -l
110

Alle bis auf 4/5 haben das Format

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

Ich bin ein bisschen verblüfft, um ehrlich zu sein.

Ich werde noch einmal versuchen, es zuverlässig zu reproduzieren, wenn ich nicht krank bin

Ich habe gesehen, dass mir das passiert, aber nur, wenn ich das Async-Modul mit mehr als 200 gleichzeitigen Verbindungen verwende.

Hallo,
Ich habe genau das gleiche Problem mit Anfragen und Affen-Patches mit gevent: Einige Verbindungen bleiben in CLOSE_WAIT.
Vielleicht ein Problem mit gevent so.

Es kann ein Problem von ulimit -n sein. Versuchen Sie es mit einem höheren Wert.

"Zu viele geöffnete Dateien" ist das Ergebnis des Fehlers, der durch Sockets in CLOSE_WAIT verursacht wird.
Ulimit behebt also nicht nur eine Problemumgehung.

@tamiel wie beheben wir das?

Ich werde so schnell wie möglich weitere Tests durchführen und versuchen, diese zu beheben.

Ich habe mich damit befasst und scheint ein Problem mit allen Bibliotheken zu sein, die httplib.HTTPSConnection verwenden.

Hier ein Beispiel gepostet:

https://gist.github.com/1512329

Ich habe gerade einen sehr ähnlichen Fehler bei der Verwendung eines asynchronen Pools mit nur HTTP-Verbindungen festgestellt. Ich untersuche noch, aber die Übergabe einer Poolgröße an async.map führt dazu, dass der Fehler schnell reproduziert wird.

Irgendwelche Korrekturen dazu? Dies macht Anfragen mit gevent unbrauchbar.

Es geht nur um die CLOSE_WAIT s. Ich muss sie nur schließen. Ich bin mir nicht sicher, warum sie noch offen sind.

Ist es ein urllib3-Problem? Diese selbst schließen zu müssen, ist meiner Meinung nach keine großartige Idee.

Es ist eher ein allgemeines Problem. Wir können das Gespräch hier führen.

Um Ihnen eine Perspektive zu geben, versuchen wir, von httplib2 zu Anfragen zu wechseln, und wir sehen dieses Problem bei httplib2 nicht. Es ist also sicher kein allgemeines Problem.

Mit allgemein meine ich, dass es ein sehr ernstes Problem ist, das alle Beteiligten betrifft.

Wie lösen wir das? Wir möchten wirklich Anfragen + Schlaf verwenden, um vorwärts zu kommen

Ich würde gerne die Antwort darauf wissen.

Das Leck scheint auf die interne Umleitungsbehandlung zurückzuführen zu sein, die dazu führt, dass neue Anforderungen generiert werden, bevor die ausstehenden Antworten verbraucht wurden. Beim Testen von acdha @ 730c0e2e2bef77968a86962f9d5f2bebba4d19ec wurde eine erzwungen wird, bevor sie fortgesetzt wird.

Dies erforderte Änderungen an zwei Stellen, weshalb ich die Benutzeroberfläche leicht umgestalten wollte, aber ich habe keine Zeit mehr, um fortzufahren.

399 hat einen Fix, der in meinem asynchronen Lastgenerator (https://github.com/acdha/webtoolbox/blob/master/bin/http_bench.py) mit Tausenden von Anfragen und einem niedrigen fd ulimit gut funktioniert

Ich bin bei der Verwendung von asynchronem Problem auf dasselbe Problem gestoßen - habe eine Problemumgehung durch Aufteilen von Anforderungen und Löschen von Antworten / Aufrufen von gc.collect behoben

Ich glaube, ich bin heute darauf gestoßen, eine Verbindung zu einem lizenzierten Server herzustellen, der nur 5 Verbindungen zulässt.

Mit Async konnte ich nur 4 Dinge abrufen, bevor es für 60 Sekunden pausierte.

Mit dem normalen GET mit Verbrauch konnte ich in weniger als 40 Sekunden etwa 150 Dinge seriell abrufen.

Ich habe meinen Kludge noch nicht gemacht, seit ich dieses Problem gesehen habe.

Ich habe gerade diesen Fehler bei der Verwendung von ipython erhalten und diese Meldung erhalten. Dies bedeutet nur, dass jede Anfrage einzeln gestellt wird, aber ich glaube, ich habe bei der Verwendung von Async etwas Ähnliches erhalten.

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.

Seltsamerweise denke ich, wenn ich nur den normalen Python-Interpreter verwende, erhalte ich einen "Max Retries Error", aber ich denke, das ist ein weiteres Problem, wenn ich Anfragen auf derselben Domain mache, aber nicht sicher.

Ich bin beim ersten Projekt darauf gestoßen, bei dem allow_redirects True war. Dies scheint darauf zurückzuführen zu sein, dass durch die Umleitungskette Antwortobjekte verloren gehen, die auch mit prefetch = True nicht freigegeben werden. Dies hat es in meinen ersten Tests behoben:

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

Hmmm..

@ acdha Einstellung:

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

Bevor ich Anfragen stelle, führt dies immer noch zu demselben Fehler. Ich denke jedoch, dass dies keine Option für meine Implementierung ist, da für alle von mir gestellten Anfragen eine Umleitung erforderlich ist = /

@dalanmiller Wie verarbeitest du deine Antworten? Ich habe zuvor async.map mit einem Antwort-Hook verwendet und es scheint stabiler zu sein, wenn eine einfache Schleife über 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

Ich habe nur eine for-Schleife durch eine URL-Liste verwendet und eine request.get für jede mit meinen Einstellungen und dergleichen durchgeführt.

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

Ich habe versucht, Ihre Paste zu verwenden, und sie funktioniert für ungefähr 50 Anfragen in meiner 900-Längen-Liste, bis ich für den Rest "maximale Wiederholungsfehler mit URL überschritten" erhalte. Dies ist jedoch ein ziemlich normaler Fehler, wenn dieselbe Domain wiederholt aufgerufen wird, nicht wahr?

Hey, ich habe eine riesige Liste von URLs gecrawlt, 35k, und habe den gleichen Fehler bei einigen Anfragen erhalten.

Ich erhalte URLs in 10er-Stücken wie folgt:

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

Irgendwo im Bereich von 20.000 bekam ich Fehler 24, dann war es bis 30.000 in Ordnung und dann wieder.

Haben Sie weitere Informationen, die Sie interessieren würden, um sie einzugrenzen?

requests.async ist weg. Vielleicht möchten Sie in Betracht ziehen, zu Grequests zu wechseln.

OK, danke. Wäre gut, dies in den Dokumenten zu erwähnen.

Eine Art Noob, wenn es um Pull-Anfragen und das Schreiben von Unterlagen geht, aber ich habe es versucht und gesendet. Bitte kommentieren oder kritisieren :)

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

Ok, dies geschieht auch ohne Verwendung von Async mit nur request.get nach 6K-Anforderungen.

Das habe ich vermutet.

Bei mir ist der Fehler "Zu viele offene Dateien" aufgetreten, nachdem genau 1k Dateien heruntergeladen wurden. Meine Lösung bestand darin, Keep-Alive-Eigenschaften zu deaktivieren und immer Anfragen in Blöcken zu erhalten ( lsof -p PID | wc -l zeigt eine nicht zunehmende Anzahl von Verbindungen während der Ausführung an.

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] Chunking: http://stackoverflow.com/a/312464

Schließen, während auf urllib3 fix verschoben wird.

@kennethreitz Wie lautet die Ausgabenummer der urllib3?

Sieht so aus, als wäre dies das Problem http://bugs.python.org/issue16298

@silvexis könnte sehr gut mit dem urllib3-Fehler zusammenhängen, jetzt wünsche ich mir nur, jemand hätte @ piotr-dobrogost geantwortet: P.

Tritt noch jemand auf dieses Problem?

Ich habe keine Berichte darüber gehört. Bist du?

Es ist ein Problem der Box-Konfiguration, nicht des Frameworks. Sehen Sie sich die Kernelkonfiguration Ihres Betriebssystems an. In BSD heißt es kern.maxfiles . In Linux-Systemen gibt es einen Thread über ulimit : http://stackoverflow.com/questions/34588/how-do-i-change-the-number-of-open-files-limit-in-linux
Ich hoffe, es hilft, und ich weiß nicht, wie ich diesen Parameter unter Windows ändern soll.

Mit der Einschränkung, dass wir immer noch eine ältere Version von Anfragen ausführen, haben wir den folgenden schrecklichen Code, um dies zu handhaben:

    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

(Ich denke, self._current_response ist das Antwortobjekt der Anforderungen.)

Hmm, wo ist die Schließkette gebrochen? Wir haben eine Response.close() -Methode, die release_conn() aufruft. Was muss also in release_conn() geschehen, damit dies funktioniert?

@ Lukasa dies wurde definitiv in urllib3 behoben, da ich Teil der Diskussion war. Mit einer Neigung, in meiner Schätzung konservativ zu sein, würde ich sagen, dass es da ist, da Anfragen 1.2.x, wenn nicht 1.1.x.

Ja, ich dachte das wäre behoben. Sofern wir in 1.2.3 nichts sehen, gehe ich weiterhin davon aus, dass dies behoben ist.

Ich sehe ein CLOSE_WAIT-Leck mit 2.0.2. Haben Sie Unit-Tests, um sicherzustellen, dass es keine Regression zu diesem Thema gibt?

Nein, das tun wir nicht. AFAIK urllib3 auch nicht. Können Sie Ihr Leck leicht reproduzieren?

Wir verwenden die Anfrage seit Montag in unserer internen App und haben heute die 1024 Maxfiles erreicht.

2 Stunden nach dem Neustart haben wir 40 CLOSE_WAIT, wie von lsof mitgeteilt.

Ich denke, wir können uns in einer Entwicklungsumgebung reproduzieren, ja. Ich werde dich in Kontakt halten

@tardyp auch, wie haben Sie Anfragen installiert? Ich denke, alle OS-Paketbetreuer entfernen urllib3. Wenn sie das nicht auf dem neuesten Stand halten und Sie eine alte Version verwenden, könnte dies stattdessen die Ursache sein. Wenn Sie pip verwenden, können Sie ein neues Problem öffnen, um dies zu verfolgen, anstatt diesem eine Diskussion hinzuzufügen.

Ich habe mit pip installiert, aber ich benutze Python 2.6, ich habe Fix auf Python2.7 für gesehen
dieser Fehler. Haben Sie Monkeypatch für ältere Version?

Pierre

Am Freitag, den 29. November 2013 um 17:33 Uhr schrieb Ian Cordasco [email protected] :

@tardyp https://github.com/tardyp auch, wie haben Sie Anfragen installiert? ich
Denken Sie, dass alle OS-Paketbetreuer urllib3 entfernen. Wenn nicht
Halten Sie das auf dem neuesten Stand und Sie verwenden eine alte Version, das könnte die sein
Ursache stattdessen. Wenn Sie pip verwenden, können Sie eine neue Ausgabe für öffnen
Verfolgen Sie dies mit, anstatt eine Diskussion zu diesem hinzuzufügen.

- -
Antworten Sie direkt auf diese E-Mail oder sehen Sie sie sich auf Gi tHubhttps an: //github.com/kennethreitz/requests/issues/239#issuecomment -29526302
.

@tardyp Bitte öffnen Sie eine neue Ausgabe mit möglichst vielen Details, einschließlich der Frage, ob die von Ihnen gestellten Anfragen Weiterleitungen enthalten und ob Sie gevent verwenden. Außerdem wären alle Details zum Betriebssystem und ein Beispiel für die Reproduktion fantastisch.

Zu Ihrer Information https://github.com/shazow/urllib3/issues/291 wurde aufgrund von Fehlern zurückgesetzt.

Sollten wir das wieder öffnen?
Ich habe das gleiche Problem!

@polvoazul Es gibt keine Möglichkeit, dass dies das gleiche Problem ist, das ursprünglich im Jahr 2011 gemeldet wurde, daher halte ich die Wiedereröffnung nicht für richtig. Wenn Sie jedoch die aktuelle Version von Anforderungen (2.4.3) ausführen und das Problem reproduzieren können, ist das Öffnen eines neuen Problems korrekt.

@ Lukasa Ich brauche

Es tut mir leid @mygoda , aber es ist unmöglich zu wissen. Wenn Sie die Anzahl der Anfragen, die gleichzeitig ausstehen können, nicht einschränken, ist dies sicherlich möglich, aber dies ist ein Architekturproblem außerhalb des Zuständigkeitsbereichs von Anfragen.

@ Lukasa danke。 ich denke mein Problem ist ähnlich mit diesem 。 mein Projekt ist pyvmomi . Diese Verbindung ist eine lange Verbindung. Ich war immer verwirrt, warum so viele Protokollsocken nicht identifizieren können

Wenn Sie jetzt das gleiche Problem haben und 120 Threads ausführen, verursachen Sie mehr als 100000 geöffnete Dateien. Gibt es derzeit eine Lösung?

@mygoda du verwendest tolle Perioden。

@ 1a1a11a _Welche_ Dateien haben Sie geöffnet? Das wäre ein nützlicher erster Schritt, um dieses Problem zu verstehen.

@ 1a1a11a Welche Version von Anfragen verwenden Sie? Welche Version von Python? Welches Betriebssystem? Können wir irgendwelche Informationen bekommen?

Ich verwende Anfrage 2.9.1, Python 3.4, Ubuntu 14.04, im Grunde schreibe ich einen Crawler mit 30 Threads mit Proxys, um eine Website zu crawlen. Derzeit habe ich das Dateilimit pro Prozess auf 655350 angepasst, andernfalls wird ein Fehler gemeldet.

Ich erhalte weiterhin die Fehlermeldung "Fehler beim Herstellen einer neuen Verbindung: [Errno 24] Zu viele geöffnete Dateien" von request.packages.urllib3.connection.VerifiedHTTPSConnection. "Ich verwende Python 3.4, Requests 2.11.1 und Requests-Futures 0.9.7. Ich schätze, dass Requests-Futures eine separate Bibliothek ist, aber es scheint, dass der Fehler von Anfragen herrührt. Ich versuche, 180.000 asynchrone Anfragen über SSL zu stellen. Ich habe diese Anfragen in Segmente von 1000 unterteilt, also habe ich Fahren Sie erst mit den nächsten 1000 fort, wenn alle zukünftigen Objekte aufgelöst wurden. Ich verwende Ubuntu 16.04.2 und mein Standardlimit für geöffnete Dateien ist 1024. Es wäre gut, den zugrunde liegenden Grund für diesen Fehler zu verstehen. Wird die Anforderungsbibliothek erstellt Eine geöffnete Datei für jede einzelne Anforderung. Und wenn ja, warum? Ist dies eine SSL-Zertifikatdatei? Und schließt die Anforderungsbibliothek diese geöffneten Dateien automatisch, wenn das zukünftige Objekt aufgelöst wird?

Anfragen öffnen viele Dateien. Einige dieser Dateien werden für Zertifikate geöffnet, aber sie werden von OpenSSL und nicht von Requests geöffnet, sodass diese nicht verwaltet werden. Darüber hinaus öffnen Anfragen bei Bedarf auch die Datei .netrc , die Hosts-Datei und viele andere.

Sie werden am besten mit einem Tool wie strace , um herauszufinden, welche Dateien geöffnet werden. Es gibt eine strenge Liste von Systemaufrufen, die dazu führen, dass Dateideskriptoren zugewiesen werden. Sie sollten sie daher relativ schnell auflisten können. Dadurch erfahren Sie auch, ob ein Problem vorliegt oder nicht. Aber ja, ich würde erwarten, dass wir bei Spitzenlast über 1000 FDs problemlos über 1000 FDs verwenden können, wenn Sie aktiv 1000 Verbindungen über HTTPS herstellen.

Ich hatte auch mit diesem Problem zu kämpfen und stellte fest, dass die Verwendung von opensnoop unter OS X hervorragend funktioniert, um zu sehen, was passiert, wenn jemand auf dieselben Probleme stößt.

Ich sehe diesen Fehler auch häufig, wenn ich wiederholt requests.post(url, data=data) auf einen HTTP (nicht HTTPS) Server aufrufe. Unter Ubuntu 16.04.3, Python 3.5.2, werden 2.9.1 angefordert

Was ist data ?

Ein paar hundert kb Text

Kein Dateiobjekt?

Nein, ich bilde eine große Abfrage im Speicher.

Führen Sie diesen Code in mehreren Threads aus?

Nein, einzelner Thread, Posting auf localhost

Es scheint fast unmöglich für uns, so viele FDs zu verlieren: Wir sollten wiederholt dieselbe TCP-Verbindung verwenden oder sie aggressiv schließen. Möchten Sie überprüfen, was Ihr Server vorhat?

Ich habe dieses Problem. Python 2.7, Anforderungen 2.18.4, urllib3 1.22.
Ausführen von Multithread-Code (nicht mehrfach verarbeitet). Herstellen einer Verbindung zu höchstens 6 URLs gleichzeitig, manuelles Erstellen und Schließen einer neuen Sitzung für jede einzelne URL.

Ich habe das gleiche Problem mit Python 3.5 , requests==2.18.4

@mcobzarenco Sind Sie sicher, dass Sie (implizit) die zugrunde liegende Verbindung der Antwort schließen? Durch einfaches Zurücksenden der Antwort wird die Verbindung nicht geschlossen. Beim Lesen von response.content werden die Daten tatsächlich gelesen und danach bleibt der Socket nicht in CLOSE_WAIT.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen