fragen stichworte

Prozesse hängen unbegrenzt ab, wenn von Netzwerkverbindungen gelesen wird

Eine Aktualisierung der folgenden Seite:

Ich habe ein ähnliches Problem in einem unabhängigen Skript auf einer virtuellen Debian-Maschine in einem anderen Rechenzentrum festgestellt.

Dies sieht verdächtig wie das beschriebene Problem hier aus (und wie die Person, die diese Frage stellt, habe ich keinen Proxy vor dem Server konfiguriert).

Der Hauptunterschied zur Beschreibung unten ist, dass ich beim Anhängen an den Verbindungsprozess einen Aufruf an recvfrom und nicht an read:

sehe
$ strace -p 17527
Process 17527 attached - interrupt to quit
recvfrom(3, 

Allerdings hat Python keinen Eindruck, dass es weitergeleitet wird:

>>> import os; print os.getenv("HTTP_PROXY"), os.getenv("http_proxy")
None, None

Also bin ich immer noch ratlos. Leider ist die verknüpfte Frage auch nicht endgültig.

(Ich frage mich auch, ob diese Frage verwandt ist, aber es ist unwahrscheinlich, dass S3 die Connection: close -Header nicht würdigen kann.)


Ich habe mehrere Debian-Server (Wheezy, x86_64), die das folgende Verhalten aufweisen:

Alle Server verfügen über eine Reihe von Cron-Jobs, die unter anderem Daten aus S3 abrufen. Diese laufen normalerweise einwandfrei, aber gelegentlich zeigt ps aux, dass einige der Jobs, die vor Stunden oder Tagen begonnen wurden, noch ausgeführt werden und nicht sauber abgeschlossen wurden.

Wenn Sie sie mit strace -p <pid> überprüfen, wird in jedem Fall ein Lesebefehl angezeigt. Die Ausgabe eines Prozesses, den ich gerade geprüft habe, war zum Beispiel:

$ strace -p 12089
Process 12089 attached - interrupt to quit
read(5, 

Wenn Sie die offenen Dateideskriptoren überprüfen, erhalten Sie Folgendes:

$ sudo lsof -i | grep 12089
python  12089    user    5u  IPv4 809917771      0t0  TCP my.server.net:35427->185-201.amazon.com:https (ESTABLISHED)

Zunächst ging ich davon aus, dass dies nur auf das Fehlen einer Lesezeitüberschreitung in den Python-Skripten zurückzuführen ist. Dies scheint jedoch aus mehreren Gründen nicht der Fall zu sein:

  1. Dies geschieht nicht, wenn auf unseren OS X-Boxen (alle 10.5, i386) dieselben Jobs ausgeführt werden und identischen Code verwenden.
  2. Eine Variante des Skripts, das ein Timeout (von 60 Sekunden mit socket.setdefaulttimeout - dies ist in Python 2.7, aber die Codebasis muss 2.5 kompatibel sein muss) wurde eingestellt seit gestern.
  3. Ein anderer Prozess, bei dem es sich nicht um Python handelt, scheint gelegentlich ein ähnliches Verhalten aufzuweisen. In diesem Fall führt ein Python-Skript einen svn up --non-interactive -Prozess aus (mit subprocess.Popen, was sich lohnt).

Die Situation bei diesem SVN-Prozess ist ähnlich -

Python wartet auf SVN:

$ strace -p 28034
Process 28034 attached - interrupt to quit   
wait4(28127, 

Und der SVN wartet darauf, dass ein read -Aufruf abgeschlossen wird:

$ strace -p 28127
Process 28127 attached - interrupt to quit
read(6, 

Und dieser Hinweis verweist auf einen anderen externen Host:

$ sudo lsof -i | grep 28127
svn     28127    user    3u  IPv4 701186417      0t0  TCP my.server.net:49299->sparrow.telecommunity.com:svn (ESTABLISHED)
svn     28127    user    6u  IPv4 701186439      0t0  TCP my.server.net:49309->sparrow.telecommunity.com:svn (ESTABLISHED)

(Es gibt anscheinend eine svn:externals -Eigenschaft für das zu aktualisierende Verzeichnis auf ez_setup svn://svn.eby-sarna.com/svnroot/ez_setup; je nach Website denke ich, dass dies auf telecommunity.com umgeleitet wird)

Zusätzliche möglicherweise relevante Punkte:

  • Die Python-Umgebung auf den Macs ist 2.5. In den Debian-Boxen ist es 2.7.
  • Ich bin mit SVN nicht vertraut, und ich habe keine Ahnung, ob der Grund, warum es hängt, grundsätzlich derselbe ist oder nicht. Ich bin auch nicht ganz sicher, was die Auswirkungen von svn:externals sind. Dies wurde vor meiner Zeit eingerichtet.
  • Die Python-Skripts selbst rufen große Datenmengen von Amazon S3 ab (in einigen Fällen ~ 10 MB). Dies hat die Tendenz, langsam zu sein (ich sehe Downloadzeiten bis zu drei Minuten, was lang erscheint.) im Vergleich zu der Zeit, in der die Server - auch in verschiedenen Rechenzentren - miteinander kommunizieren müssen). Ebenso sind einige unserer SVN-Repositories ziemlich groß. Das heißt im Grunde, dass einige dieser Operationen ohnehin lang sind , aber in manchen Fällen scheinen sie auch Stunden oder Tage hängen zu bleiben.
  • Auf einem Server hat der OOM-Killer heute Morgen MySQL entfernt. Bei genauerer Betrachtung lag der Speicherverbrauch bei 90% und der Swap-Verbrauch bei 100% (wie von Monit angegeben). Durch den Abbruch eines großen Auftragsstaus an Python-Jobs konnten diese Statistiken auf 60% bzw. 40% reduziert werden. Dies gibt mir den Eindruck, dass zumindest einige (wenn nicht alle) Daten heruntergeladen/gelesen werden (und im Speicher gehalten werden, während der Prozess hängt).
  • Diese Cron-Jobs fordern eine Liste von Ressourcen von S3 an und aktualisieren eine Liste von MySQL-Tabellen entsprechend. Jeder Job wird mit derselben Liste gestartet. Versuchen Sie daher, dieselben Ressourcen anzufordern und dieselben Tabellen zu aktualisieren.
  • Ich konnte etwas Verkehr von einem der blockierten Prozesse erfassen. es ist alles ein wenig undurchschaubar für mich, aber ich frage mich, ob es zeigt, dass die Verbindung aktiv ist und funktioniert, nur sehr, sehr langsam? Ich habe es als einen Hauptpunkt angegeben, um Unordnung zu vermeiden (ich sollte beachten, dass dies etwa zwei Stunden dauern wird): https://gist.github.com/petronius/286484766ad8de4fe20b Ich glaube, das war ein roter Hering. Es gibt Aktivität an diesem Port, aber es ist nicht dieselbe Verbindung wie die zu S3 - es ist nur eine zufällige Serveraktivität.
  • Ich habe versucht, dieses Problem auf einer Box in einem anderen Rechenzentrum (einer VM, auf der dieselbe Version von Debian mit demselben System-Setup ausgeführt wird) ohne Erfolg neu zu erstellen (ich hatte gedacht, dass das Problem möglicherweise damit zusammenhängt.) this, aber bei den Boxen, bei denen diese Probleme auftreten, handelt es sich nicht um VMs, und es werden keine Pakete nach ifconfig verworfen. Ich vermute, dies weist auf ein Problem mit der Netzwerkkonfiguration hin, aber ich bin nicht sicher, wo ich damit anfangen soll.

Ich denke also, meine Fragen lauten:

  • Kann ich das auf Systemebene beheben oder ist bei jedem einzelnen Prozess etwas nicht in Ordnung?
  • Gibt es etwas grundlegend anderes, wie OS X und Linux mit read -Aufrufen umgehen, die ich wissen muss, um endlos hängende Prozesse zu vermeiden?

antworten

Can I fix this at a system level, or is this something going wrong with each individual process?

Es ist schwierig zu sagen, weil es unbekannt ist, was auf der Protokollebene passiert. Grundsätzlich wird read(2) unbegrenzt blockieren: -

  • Die TCP-Verbindung bleibt offen.
  • Sie erwarten, dass mindestens 1 Byte an Daten ankommt.
  • Der Absender ist nicht bereit, Ihnen Daten zu senden.

Nun könnte es sein, dass etwas mit dem Prozess nicht stimmt, etwa wenn das andere Ende eine Antwort von Ihnen erwartet, bevor es weitere Daten sendet, oder eine vorherige Antwort vom anderen Ende erwartet, dass SVN etwas anderes tut, bevor Sie weitere Daten anfordern. Angenommen, es kam zum Beispiel eine Fehlermeldung zurück, die den Client zwingen sollte, einige Informationen erneut zu senden.

Sie können das nicht elegant beheben, weil es unmöglich ist, aus den Informationen zu ermitteln, was der Absender dieser Daten von Ihnen erwartet. Es gibt jedoch einige Möglichkeiten, das Problem zu vermeiden und zu melden.

  • Anstatt wait in einem einfachen Blockierungsmodus zu verwenden, führen Sie wait aus und konfigurieren Sie einen Alarm im übergeordneten Prozess. Jetzt, wenn der Prozess nicht innerhalb einer bestimmten Zeit abgeschlossen ist, können Sie ihn töten und melden, dass dies passiert ist. Eine günstige Möglichkeit, dies zu tun, besteht darin, den Subprozess.Popen zu ändern, um den Befehl timeout aufzurufen.
  • Ändern Sie den Lesevorgang so, dass er eine Lese-Timeout-Socket-Option festlegt. Sie können dies tun, indem Sie den Code ändern oder - mit einem Interposer den Standard socket -Systemaufruf außer Kraft setzen, um dem Empfänger auch eine Zeitüberschreitung hinzuzufügen. Beides ist nicht trivial. Dies kann dazu führen, dass sich svn unerwartet verhält.

Is there something fundamentally different about how OS X and Linux handle read calls that I need to know to avoid infinitely-hanging processes?

Ich kenne die Antwort nicht, aber wenn beide sich richtig verhalten, sollten sie sich beide auf die gleiche Weise verhalten. Wenn Sie versuchen, von einem Socket zu lesen, das noch nicht bereit ist, Ihnen Daten zu senden, die den Stream auf unbestimmte Zeit blockieren, ist das erwartete Verhalten.

Insgesamt denke ich, dass der beste Angriffspunkt darin zu erwarten ist, dass Ihr svn -Befehl innerhalb eines bestimmten Zeitraums abgeschlossen wurde. Wenn es nicht tötet und meldet, dass du es getan hast.

Ich denke, ich habe das oben beschriebene Problem herausgefunden, und das meiste Geheimnis rührt von meinem Missverständnis her, was auf den Servern passiert ist.

Es gab die folgenden grundlegenden Probleme:

  • Python-Skripte, für die ein Zeitlimit gesetzt sein sollte (was ich annahm, taten dies nicht). Einige davon hingen unbestimmt, wenn sie sich mit S3 verbanden, und zeigten das Verhalten, endlos darauf zu warten, dass ein Lesevorgang abgeschlossen wurde. Das Durchlaufen des Codes und das Sicherstellen, dass globale Socket-Timeouts festgelegt wurden und nicht deaktiviert wurden, scheint diesen Teil gelöst zu haben.
  • Einige der alten Python-Prozesse schienen blockiert zu sein, aber bei näherer Betrachtung (sobald die wirklich blockierten Prozesse ausgemustert wurden) listeten sie einfach große S3-Buckets auf, um den Status der Schlüssel in diesen Buckets zu überprüfen, und dieser Vorgang war Stunden oder Tage dauern.
  • Der SVN-Checkout-Befehl hing (noch) lange Zeit beim Aktualisieren sehr großer Projekte mit vielen Dateien in sehr tiefen Verzeichnisstrukturen. Der Client wartet darauf, dass ein Lesevorgang abgeschlossen wird, aber dies ist völlig legitim (es scheint, dass der Repository-Server eine lange Zeit braucht, um die Daten zu sammeln, die er zum Senden an den Client benötigt).

Ich lasse diese Antwort hier, um zu erklären, was vor sich geht, aber ich werde Matthew annehmen, weil er recht hatte, was die tatsächlichen möglichen Probleme waren.