Question Processus suspendus indéfiniment lors de la lecture de connexions réseau


Une mise à jour de la liste ci-dessous:

J'ai rencontré un problème similaire sur un script non lié, sur une machine virtuelle Debian située dans un autre centre de données.

Cela ressemble étrangement à la question décrite ici (et comme la personne qui pose cette question, je n'ai pas de proxy configuré devant le serveur).

La principale différence par rapport à la description ci-dessous est que, lorsque je me connecte au processus bloqué, je vois un appel à recvfrom plutôt que read:

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

Cependant, Python n’a pas l’impression d’être traité par proxy:

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

Donc, je suis toujours perplexe. Malheureusement, la question liée n'a pas de réponse finale également.

(Je me demande aussi si cette question est liée, mais il semble peu probable que S3 échoue à honorer Connection: close en-têtes.)


J'ai plusieurs serveurs Debian (Wheezy, x86_64) qui présentent tous le comportement suivant:

Tous les serveurs ont un ensemble de tâches cron qui, entre autres choses, extraient des données de S3. Ceux-ci fonctionnent généralement bien, mais parfois ps aux révèle que certains des travaux commencés il y a des heures ou des jours sont toujours en cours d'exécution et ne sont pas terminés proprement.

Les inspecter avec strace -p <pid> montre que, dans tous les cas, le processus est suspendu à une commande de lecture. Par exemple, la sortie d'un processus que j'ai vérifié tout à l'heure était:

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

Et vérifier les descripteurs de fichiers ouverts me donne ceci:

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

Au début, je pensais que c'était simplement dû à l'absence de définition d'un délai de lecture dans les scripts Python, mais cela ne semble pas être le cas, pour deux raisons:

  1. Cela ne se produit pas lorsque les mêmes travaux sont exécutés sur nos boîtes OS X (tous 10.5, i386), en utilisant un code identique.
  2. Une variante du script qui Est-ce que définir un délai d'attente (de 60 secondes, à l'aide de socket.setdefaulttimeout - ceci est en Python 2.7, mais la base de code doit être compatible 2.5) a été suspendue depuis hier.
  3. Un autre processus qui n'est pas Python semble parfois présenter un comportement similaire. Dans ce cas, un script Python exécute une svn up --non-interactive processus (en utilisant subprocess.Popen, pour ce que ça vaut).

La situation avec ce processus SVN est similaire--

Python attend SVN:

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

Et SVN attend un read appel à compléter:

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

Et cette lecture pointe vers un autre hôte externe:

$ 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)

(Il semble y avoir un svn:externals propriété définie sur ez_setup svn://svn.eby-sarna.com/svnroot/ez_setup sur le répertoire en cours de mise à jour; basé sur leur site Web, je pense que ceci est une redirection vers telecommunity.com)

Autres points éventuellement pertinents:

  • L’environnement Python sur les Mac est 2.5. Sur les boîtes Debian, il s'agit de 2.7.
  • Je ne suis pas très au courant de SVN et je ne sais pas si la raison pour laquelle elle est suspendue est fondamentalement la même chose ou non. Je ne suis pas non plus tout à fait sûr des implications de svn:externals sont; cela a été mis en place avant mon temps.
  • Les scripts Python eux-mêmes récupèrent des blocs de données volumineux (environ 10 Mo dans certains cas) d'Amazon S3, ce qui a tendance à être lent (le temps de téléchargement est de trois minutes, ce qui semble long par rapport à la façon dont longtemps, il faut que les serveurs, même dans différents centres de données, communiquent entre eux). De même, certains de nos référentiels SVN sont plutôt grands. Voilà donc essentiellement pour dire que certaines de ces opérations sont de longue durée en tous casCependant, dans certains cas, ils semblent également être bloqués pendant des heures ou des jours.
  • Sur un serveur, le tueur de MOO a sorti MySQL ce matin. En regardant de plus près, l'utilisation de la mémoire était à 90% et l'utilisation de l'échange à 100% (comme indiqué par Monit); l'élimination d'un important arriéré d'emplois bloqués en Python a permis de ramener ces statistiques à 60% et 40% respectivement. Cela me donne l'impression qu'au moins une partie (sinon la totalité) des données est en cours de téléchargement / lecture (et conservée en mémoire pendant que le processus est suspendu).
  • Ces tâches cron demandent une liste de ressources à S3 et mettent à jour une liste de tables MySQL en conséquence. Chaque travail est démarré avec la même liste. Nous allons donc essayer de demander les mêmes ressources et mettre à jour les mêmes tables.
  • J'ai pu capturer du trafic provenant de l'un des processus bloqués; tout cela est un peu impénétrable pour moi, mais je me demande si cela indique que la connexion est active et fonctionne, tout simplement très lente? Je l'ai fourni comme un résumé, pour éviter l'encombrement (je dois noter que cela représente environ deux heures de capture): https://gist.github.com/petronius/286484766ad8de4fe20b C'était un hareng rouge, je pense. Il y a de l'activité sur ce port, mais ce n'est pas la même connexion que celle vers S3, c'est simplement une autre activité de serveur aléatoire.
  • J'ai essayé de recréer ce problème sur une boîte d'un autre centre de données (une machine virtuelle exécutant la même version de Debian avec la même configuration système) sans succès (je pensais que le problème était peut-être lié à celui-là, mais les boites rencontrant ces problèmes ne sont pas des machines virtuelles et il n’y a pas de paquets perdus conformément à ifconfig). Je suppose que cela indique un problème de configuration réseau, mais je ne sais pas par où commencer.

Donc, je suppose que mes questions sont:

  • Puis-je résoudre ce problème au niveau du système ou est-ce que quelque chose ne va pas avec chaque processus?
  • Existe-t-il quelque chose de fondamentalement différent dans la manière dont OS X et Linux gèrent read les appels que je dois savoir pour éviter les processus indéfiniment suspendus?

7
2017-07-08 13:37


origine


Tcpdump indique que la trace doit afficher plusieurs lectures, à condition que vous traçiez le bon processus - de nombreuses données sont en cours de transmission. Le seul cas où cela ne se produira peut-être pas si l'indicateur de lecture MSG_WAITALL est utilisé et un très grand tampon. - Matthew Ife
J'ai laissé le tcpdump en marche pendant que je sortais déjeuner. Les quinze premières minutes (avant que je quitte le bureau) ne montraient rien. Je pense que je n’ai pas été aussi patient avec les commandes strace, mais je vais en laisser une et voir ce qui se passe. - Michael Schuller


Réponses:


Puis-je résoudre ce problème au niveau du système ou est-ce que quelque chose ne va pas avec chaque processus?

Il est difficile de dire parce que son inconnu ce qui se passe au niveau du protocole. Fondamentalement la read(2) bloquera indéfiniment en fournissant: -

  • La connexion TCP reste ouverte.
  • Vous attendez au moins 1 octet de données à arriver.
  • L'expéditeur n'est pas prêt à vous envoyer des données.

Maintenant, il se peut que quelque chose ne va pas dans le processus, par exemple, l'autre extrémité attend une réponse de votre part avant d'envoyer plus de données, ou une réponse précédente de l'autre extrémité anticipe que SVN fera quelque chose. autre avant de demander plus de données. Supposons, par exemple, une réponse d'erreur qui obligerait le client à renvoyer certaines informations.

Vous ne pouvez pas résoudre ce problème avec élégance, car il vous est impossible, à partir des informations dont vous disposez, de déterminer ce que l'expéditeur de ces données attend de vous. Cependant, il existe plusieurs moyens d'éviter le problème et de le signaler.

  • Plutôt que d'utiliser wait dans un mode de blocage simple, exécutez wait et configurer une alarme dans le processus parent. Maintenant, lorsque le processus ne se termine pas dans un délai déterminé, vous pouvez le tuer et signaler ce qui s'est passé. Une méthode peu coûteuse consiste à modifier le sous-processus.Popen pour appeler le timeoutcommander.
  • Modifiez la lecture afin qu’elle définisse une option de socket de délai de lecture. Vous pouvez le faire en modifiant le code ou en utilisant un interposeur pour remplacer la valeur par défaut. socket appel système pour ajouter également un délai au récepteur. Les deux ne sont pas triviaux. Cela peut causer svn se comporter de manière inattendue.

Existe-t-il quelque chose de fondamentalement différent dans la manière dont OS X et Linux gèrent les appels en lecture que je dois savoir pour éviter les processus ininterrompus?

Je ne connais pas la réponse à cette question, mais si les deux se comportent de manière posixly correcte, ils doivent se comporter de la même manière. Si vous essayez de lire à partir d'un socket qui n'est pas encore prêt à vous envoyer des données, le comportement anticipé est bloqué indéfiniment.

Globalement, je pense que votre meilleur choix d’attaque est d’attendre votre svn commande à avoir achevé dans un délai déterminé. Si cela ne tue pas et que vous signalez que vous l'avez fait.


3
2017-07-09 10:44



En raison de la nature de l'environnement, je pense qu'il faut supposer que les scripts Python sont modifiables, mais le piratage de SVN n'est pas une option. La commande SVN pose moins de problèmes, car elle est exécutée au premier plan, dans le cadre d’un processus que je surveille dans un terminal. Les tâches Python sont plus problématiques car elles sont exécutées par cron et empilées (et consomment de la mémoire en même temps). Le comportement fait sembler être différent entre OS X et Linux, mais j’hésite à accuser l’un ou l’autre de ne pas suivre le standard POSIX (car cela semble moins probable qu’un problème ailleurs). - Michael Schuller
Pour les scripts python purs, vous pouvez utiliser le socket.settimeout option pour assurer un délai d'attente se produit. - Matthew Ife
Fait intéressant, je viens de découvrir qu'une variante du script qui a été suspendue depuis hier Est-ce que définir un délai d'attente. J'ai mis à jour ma question en conséquence. De plus, SVN ne définit-il pas vraiment ses propres délais de lecture sur le réseau? Bien que j'apprécie l'aide, j'aimerais vraiment voir si je peux résoudre ce problème au niveau du réseau / du système, plutôt que pour chaque processus qui pourrait un jour devoir fonctionner sur ces boîtes. - Michael Schuller


Je pense avoir compris le (s) problème (s) décrit (s) ci-dessus, et la plupart du mystère provient de mon incompréhension de ce qui se passait sur les serveurs.

Il y avait les problèmes fondamentaux suivants:

  • Les scripts Python qui auraient dû avoir un délai d'attente défini (et que j'ai supposé l'avoir fait) n'en avaient pas. Certains de ceux-ci ont été suspendus indéfiniment lors de la connexion à S3, affichant le comportement d'attendre indéfiniment qu'une lecture soit terminée. Combiner le code et s’assurer que les délais d’attente globaux pour les sockets ont bien été définis, et ne pas être désaffecté, semble avoir résolu ce problème.
  • Certains des anciens processus Python semblaient être bloqués, mais à y regarder de plus près (une fois les processus véritablement bloqués éliminés), ils répertoriaient simplement les grands compartiments S3 afin de vérifier l'état des clés dans ces compartiments. Cette opération prenait des heures ou des minutes. jours à compléter.
  • La commande de contrôle SVN était (elle est toujours) suspendue pendant de longues périodes lors de la mise à jour de très gros projets contenant de nombreux fichiers dans des structures de répertoire très profondes. Le client attend la fin d'une lecture, mais cela est tout à fait légitime (le serveur de référentiel semble mettre longtemps à collecter les données dont il a besoin pour être renvoyé au client).

Je laisse cette réponse ici pour expliquer ce qui se passait, mais je vais accepter celui de Matthew, car il avait raison quant aux véritables problèmes possibles.


1
2017-09-01 14:17