Prozesse hängen unbegrenzt beim Lesen von Netzwerkverbindungen

7

Ein Update auf das Folgende:

Ich habe ein ähnliches Problem bei einem nicht verwandten Skript auf einer virtuellen Debian-Maschine in einem anderen Rechenzentrum festgestellt.

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

Der Hauptunterschied zur folgenden Beschreibung besteht darin, dass ich beim Anhängen an den hängengebliebenen Prozess recvfromeher einen Aufruf sehe als read:

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

Python hat jedoch keinen Eindruck davon, dass es sich um einen Proxy handelt:

>>> 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 ohne endgültige Antwort.

(Ich frage mich auch, ob diese Frage verwandt ist, aber es ist unwahrscheinlich, dass S3 die Überschriften nicht Connection: closeberücksichtigt.)


Ich habe mehrere Debian-Server (Wheezy, x86_64), die alle 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, zeigen jedoch gelegentlich ps aux, dass einige der vor Stunden oder Tagen gestarteten Jobs noch ausgeführt werden und nicht sauber abgeschlossen wurden.

Wenn Sie sie mit strace -p <pid>Shows überprüfen, wird der Prozess in jedem Fall an einen Lesebefehl gehängt. Die Ausgabe eines Prozesses, den ich gerade überprüft habe, war beispielsweise:

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

Wenn ich die Deskriptoren für geöffnete Dateien überprüfe, habe ich Folgendes:

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

Zuerst nahm ich an, dass dies nur darauf zurückzuführen ist, dass in den Python-Skripten kein Lesezeitlimit festgelegt wurde. Dies scheint jedoch aus mehreren Gründen nicht der Fall zu sein:

  1. Dies ist nicht der Fall, wenn auf unseren OS X-Boxen (alle 10.5, i386) dieselben Jobs mit identischem Code ausgeführt werden.
  2. Eine Variante des Skripts , das nicht ein Timeout - Set (60 Sekunden, unter Verwendung von socket.setdefaulttimeout- dies ist in Python 2.7, aber die Code - Basis hat 2,5 kompatibel sein) ist seit gestern worden hängt.
  3. Ein anderer Prozess, der nicht Python ist, scheint gelegentlich ein ähnliches Verhalten aufzuweisen. In diesem Fall führt ein Python-Skript einen svn up --non-interactiveProzess aus (unter Verwendung dessen subprocess.Popen, was das wert ist).

Die Situation mit diesem SVN-Prozess ist ähnlich.

Python wartet auf SVN:

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

Und SVN wartet auf einen readAnruf:

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

Und diese Lesung zeigt 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)

(In dem zu aktualisierenden Verzeichnis scheint eine svn:externalsEigenschaft festgelegt zu ez_setup svn://svn.eby-sarna.com/svnroot/ez_setupsein. Aufgrund ihrer Website wird dies meiner Meinung nach zu telekommunity.com umgeleitet.)

Zusätzliche möglicherweise relevante Punkte:

  • Die Python-Umgebung auf den Macs ist 2.5. Auf den Debian-Boxen ist es 2.7.
  • Ich bin nicht gut mit SVN vertraut und ich habe keine Ahnung, ob der Grund, warum es hängt, im Grunde der gleiche ist oder nicht. Ich bin mir auch nicht ganz sicher, welche Auswirkungen dies hat svn:externals. Dies wurde vor meiner Zeit eingerichtet.
  • Die Python-Skripte selbst rufen große Datenblöcke (in einigen Fällen ~ 10 MB) von Amazon S3 ab, und dies ist in der Regel langsam (ich sehe Downloadzeiten von bis zu drei Minuten, was im Vergleich zu wie lange lang erscheint Es dauert lange, bis die Server - auch in verschiedenen Rechenzentren - miteinander kommunizieren. In ähnlicher Weise sind einige unserer SVN-Repositorys ziemlich groß. Das heißt also im Grunde, dass einige dieser Operationen ohnehin schon lange dauern, in einigen Fällen jedoch auch stunden- oder tagelang hängen bleiben .
  • Auf einem Server hat der OOM-Killer heute Morgen MySQL entfernt. Bei näherer Betrachtung lag die Speichernutzung bei 90% und die Swap-Nutzung bei 100% (wie von Monit gemeldet). Durch das Beenden eines großen Rückstands an blockierten Python-Jobs wurden diese Statistiken auf 60% bzw. 40% reduziert. 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 der Ressourcen von S3 an und aktualisieren eine Liste der MySQL-Tabellen entsprechend. Jeder Job wird mit derselben Liste gestartet. Daher wird versucht, dieselben Ressourcen anzufordern und dieselben Tabellen zu aktualisieren.
  • Ich konnte etwas Verkehr von einem der blockierten Prozesse erfassen; es ist alles ein bisschen unergründlich für mich, aber ich frage mich, ob es anzeigt, dass die Verbindung aktiv ist und funktioniert, nur sehr, sehr langsam? Ich habe es als Kern bereitgestellt, um Unordnung zu vermeiden (ich sollte beachten, dass dies eine Erfassung im Wert von etwa zwei Stunden ist): https://gist.github.com/petronius/286484766ad8de4fe20b Dies war ein roter Hering, denke ich. Es gibt Aktivitäten an diesem Port, aber es ist nicht die gleiche Verbindung wie an S3 - es ist nur eine andere 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 Glück neu zu erstellen (ich hatte gedacht, dass das Problem möglicherweise mit diesem Problem zusammenhängt) . Bei den Boxen, bei denen diese Probleme auftreten, handelt es sich jedoch nicht um VMs, und es gibt keine verworfenen Pakete gemäß ifconfig). Ich denke, dies deutet auf ein Problem mit der Netzwerkkonfiguration hin, bin mir aber nicht sicher, wo ich damit anfangen soll.

Meine Fragen sind also:

  • Kann ich dies auf Systemebene beheben oder läuft bei jedem einzelnen Prozess etwas schief?
  • Gibt es etwas grundlegend anderes an der Verarbeitung von readAnrufen durch OS X und Linux, das ich wissen muss, um unendlich hängende Prozesse zu vermeiden?
Michael Schuller
quelle
Der tcpdump gibt an, dass der Trace mehrere Lesevorgänge anzeigen soll, vorausgesetzt, Sie verfolgen den richtigen Prozess - es werden viele Daten übertragen. Der einzige Fall, in dem dies möglicherweise nicht der Fall ist, besteht darin, dass das Leseflag MSG_WAITALL und ein sehr großer Puffer verwendet werden.
Matthew Ife
Ich ließ den tcpdump laufen, während ich zum Mittagessen ging. Die ersten fünfzehn Minuten (bevor ich das Büro verließ) zeigte es nichts. Ich glaube, ich war nicht so geduldig mit den Strace-Befehlen, aber ich werde einen gehen lassen und sehen, was dabei herauskommt.
Michael Schuller

Antworten:

3

Kann ich dies auf Systemebene beheben oder läuft bei jedem einzelnen Prozess etwas schief?

Es ist schwer zu sagen, da nicht bekannt ist, was auf Protokollebene geschieht. Grundsätzlich read(2)blockiert der Wille auf unbestimmte Zeit: -

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

Nun kann es sein, dass etwas mit dem Prozess nicht stimmt, z. B. erwartet das andere Ende zuerst eine Antwort von Ihnen, bevor Sie weitere Daten senden, oder eine vorherige Antwort vom anderen Ende erwartet, dass SVN etwas anderes tut, bevor weitere Daten angefordert werden. Angenommen, es wurde eine Fehlerantwort zurückgegeben, die den Client zwingen sollte, einige Informationen erneut zu senden.

Sie können dies nicht ordnungsgemäß beheben, da es unmöglich ist, anhand der Informationen zu bestimmen, was der Absender dieser Daten von Ihnen erwartet. Es gibt jedoch einige Möglichkeiten, um das Problem zu vermeiden und es zu melden.

  • Anstatt mit waitin einem einfachen Blockiermodus läuft waitund konfiguriert einen Alarm im übergeordneten Prozess. Wenn der Vorgang nicht innerhalb eines festgelegten Zeitraums abgeschlossen werden kann, können Sie ihn beenden und melden, dass dies geschehen ist. Ein billiger Weg, dies zu tun, besteht darin, den Unterprozess zu ändern. Öffnen Sie, um den timeoutBefehl aufzurufen .
  • Ändern Sie den Lesevorgang so, dass eine Socket-Option für das Lesezeitlimit festgelegt wird. Sie können dies tun, indem Sie den Code ändern oder - mithilfe eines Interposers den Standardsystemaufruf überschreiben, socketum dem Empfänger auch eine Zeitüberschreitung hinzuzufügen. Beides ist nicht trivial. Dies kann svnzu unerwartetem Verhalten führen.

Gibt es etwas grundlegend anderes daran, wie OS X und Linux mit Leseaufrufen umgehen, das ich wissen muss, um unendlich hängende Prozesse zu vermeiden?

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

Insgesamt denke ich, dass Ihre beste Angriffsmöglichkeit darin besteht, zu erwarten, dass Ihr svnBefehl innerhalb eines bestimmten Zeitraums abgeschlossen ist. Wenn es es nicht tötet und meldet, dass Sie es getan haben.

Matthew Ife
quelle
Aufgrund der Art der Umgebung muss davon ausgegangen werden, dass die Python-Skripte modifizierbar sind, aber das Hacken von SVN ist keine Option. Der SVN-Befehl ist weniger dringlich, da er als Teil eines Prozesses, den ich in einem Terminal beobachte, im Vordergrund ausgeführt wird. Die Python-Jobs sind problematischer, da sie von cron ausgeführt und gestapelt werden (und dabei Speicher verbrauchen). Das Verhalten scheint zwischen OS X und Linux unterschiedlich zu sein, aber ich zögere, den einen oder anderen zu beschuldigen, den POSIX-Standard nicht zu befolgen (da dies weniger wahrscheinlich ist als ein Problem an einem anderen Ort).
Michael Schuller
Bei reinen Python-Skripten können Sie die socket.settimeoutOption verwenden, um sicherzustellen, dass eine Zeitüberschreitung auftritt.
Matthew Ife
Interessanterweise habe ich gerade entdeckt , dass eine Variante des Skripts , das gestern aufgehängt worden ist , da ist ein Timeout gesetzt. Ich habe meine Frage entsprechend aktualisiert. Stellt SVN auch keine eigenen Netzwerk-Lesezeitlimits ein? Obwohl ich die Hilfe sehr schätze, würde ich gerne sehen, ob ich dies auf Netzwerk- / Systemebene lösen kann, anstatt für jeden Prozess, der eines Tages auf diesen Boxen ausgeführt werden muss.
Michael Schuller
1

Ich glaube, ich habe die oben beschriebenen Probleme herausgefunden, und das meiste Rätsel rührt von meinem Missverständnis darüber her, was auf den Servern geschah.

Es gab die folgenden grundlegenden Probleme:

  • Python-Skripte, für die ein Timeout festgelegt werden sollte (und von denen ich vermutete, dass sie dies taten), taten dies nicht. Einige davon hingen beim Herstellen einer Verbindung mit S3 auf unbestimmte Zeit und zeigten das Verhalten, auf unbestimmte Zeit auf den Abschluss eines Lesevorgangs zu warten. Das Durchkämmen des Codes und das Sicherstellen, dass globale Socket-Timeouts festgelegt wurden und nicht aufgehoben werden, scheint diesen Teil gelöst zu haben.
  • Einige der alten Python-Prozesse schienen hängen zu bleiben, aber bei näherer Betrachtung (sobald die wirklich blockierten Prozesse beseitigt waren) listeten sie einfach große S3-Buckets auf, um den Status der Schlüssel in diesen Buckets zu überprüfen, und dieser Vorgang dauerte Stunden oder Stunden Tage zu vervollständigen.
  • Der SVN-Checkout-Befehl blieb (bleibt) lange Zeit hängen, wenn sehr große Projekte mit vielen Dateien in sehr tiefen Verzeichnisstrukturen aktualisiert wurden. Der Client wartet auf den Abschluss eines Lesevorgangs, dies ist jedoch völlig legitim (es scheint, dass der Repository-Server lange braucht, um die Daten zu sammeln, die er zum Zurücksenden an den Client benötigt).

Ich lasse diese Antwort hier, um zu erklären, was los war, aber ich werde Matthews akzeptieren, weil er Recht hatte, was die tatsächlich möglichen Probleme waren.

Michael Schuller
quelle