2011-09-23 3 views
3

J'ai une application Django qui fonctionne derrière 2 serveurs mod_wsgi/Apache équilibrés en charge derrière Nginx (fichiers statiques, proxy inverse/balance de charge).Django/Apache geler avec mod_wsgi

Tous les jours, mon site ne répond plus complètement. Je suppose que beaucoup de clients demandent des URL qui bloquent.

Voici ma config

WSGIDaemonProcess web1 user=web1 group=web1 processes=8 threads=15 maximum-requests=500 python-path=/home/web1/django_env/lib/python2.6/site-packages display-name=%{GROUP} 
WSGIProcessGroup web1 
WSGIScriptAlias//home/web1/django/wsgi/wsgi_handler.py 

J'ai essayé d'expérimenter avec seulement l'aide d'un seul fil et plusieurs processus, et plus de fils et un seul processus. Presque tout ce que j'essaie tôt ou tard aboutit à des chargements de pages temporisés.

Des suggestions pour ce que je pourrais essayer? Je suis prêt à essayer d'autres options de déploiement si cela permet de résoudre le problème.

De même, existe-t-il un meilleur moyen de surveiller mod_wsgi autre que le module d'état Apache? J'ai frappais:

curl http://localhost:8080/server-status?auto 

Et en regardant le nombre de travailleurs occupés comme un indicateur pour savoir si je suis sur le point d'avoir des ennuis (je suppose que plus les travailleurs occupés que j'ai, les opérations de blocage plus sont en cours endroit).

REMARQUE: Certaines de ces demandes concernent un service Web REST que j'héberge pour l'application. Cela aurait-il un sens de limiter la localisation de cette URL via Nginx?

+0

Vous n'êtes pas en train de courir avec 'DEBUG = True' non? –

Répondre

0

Si je comprends bien votre problème, vous pouvez essayer les options suivantes:

  • URL de déplacement aller chercher de la demande/cycle de réponse (en utilisant par exemple le céleri);
  • augmenter le nombre de threads (ils peuvent mieux gérer ces blocs que les processus car ils consomment moins de mémoire);
  • diminution de la temporisation pour urllib2.urlopen;
  • essayer gevent ou eventlet (ils magiquement résoudre votre problème, mais peut présenter un autre sujet subtiles)

Je ne pense pas que ce soit un problème de déploiement, ce qui est plus d'un problème de code et il n'y a pas apache configuration le résoudre.

+0

Je ne fais aucune recherche d'URL dans ma demande/réponse.L'API REST que j'ai mentionnée est juste un couple de vues qui produisent une sortie JSON, mais qui sont touchées beaucoup plus souvent que les requêtes humaines. J'ai pensé qu'ils pourraient causer un pileup de quelque sorte ... – erikcw

+0

Ok, j'ai mal interprété votre question alors, désolé. –

3

Utilisation:

http://code.google.com/p/modwsgi/wiki/DebuggingTechniques#Extracting_Python_Stack_Traces

pour inclure la fonctionnalité que vous pouvez déclencher à un moment où vous vous attendez demandes coincé et savoir ce qu'ils font. Il est probable que les demandes s'accumulent au fil du temps plutôt que de se produire toutes en même temps, alors vous pouvez le faire périodiquement plutôt que d'attendre un échec total.

En fail safe, vous pouvez ajouter l'option:

inactivity-timeout=600 

à la directive WSGIDaemonProcess. Cela va faire redémarrer le processus en mode démon s'il est inactif pendant 10 minutes.

Malheureusement pour le moment cela se produit dans deux scénarios cependant.

Le premier est où il n'y a eu aucune demande pendant 10 minutes, le processus sera redémarré. La seconde, et celle que vous voulez lancer, est la suivante: si tous les threads de requête sont bloqués et qu'aucun d'entre eux n'a lu aucune entrée de wsgi.input, aucun contenu de réponse n'a été généré, en 10 minutes, le processus sera à nouveau redémarré automatiquement. Cela signifie au moins que votre processus devrait se rétablir automatiquement et que vous ne serez pas appelé à sortir du lit. Parce que vous exécutez autant de processus, il y a de fortes chances qu'ils ne soient pas tous bloqués en même temps, de sorte que le redémarrage ne devrait pas être remarqué par les nouvelles requêtes car d'autres processus traiteront toujours les requêtes.

Ce que vous devez déterminer, c'est combien vous pouvez réduire ce délai. Vous ne voulez pas que les processus redémarrent parce qu'il n'y a pas de demande car cela déchargera l'application et la prochaine requête si le chargement paresseux est utilisé ralentira. Ce que je devrais faire est en fait ajouter une nouvelle option block-timeout qui vérifie spécifiquement que toutes les demandes sont bloquées pour la période définie, donc le séparer des redémarrages en raison de pas de demandes du tout. Cela rendrait cela plus flexible car le redémarrer en raison de l'absence de requêtes apporte de nouveau ses problèmes avec le chargement de l'application.

Malheureusement, on ne peut pas facilement implémenter un délai de requête qui s'applique à une seule requête car la configuration de l'hébergement peut être multithread. L'injection d'exceptions Python dans une requête ne débloquera pas nécessairement le thread et, en fin de compte, vous devrez tuer le processus et intercepter d'autres requêtes simultanées. Ainsi bloqué-timeout est probablement meilleur.

Une autre chose intéressante à faire pourrait être pour moi d'ajouter des choses dans mod_wsgi pour signaler de tels redémarrages forcés en raison de processus bloqués dans l'agent New Relic. Ce serait vraiment cool alors que vous auriez la visibilité d'eux dans l'outil de surveillance. :-)

+0

Merci beaucoup pour le partage! Cela m'a aidé à trouver un très mauvais problème sur l'un de nos serveurs. – leech

0

Nous avons eu un problème similaire à mon travail. Le meilleur que nous ayons pu imaginer était des problèmes de course/blocage avec l'application, ce qui a bloqué mod_wsgi. En général, tuer un ou plusieurs processus mod_wsgi le décollerait pendant un moment.

La meilleure solution consistait à passer à tous les processus, sans thread. Nous avons confirmé avec nos équipes de développement que certaines des bibliothèques Python qu'elles utilisaient n'étaient probablement pas sûres pour les threads.

Essayer:

WSGIDaemonProcess web1 user = groupe web1 = processus de web1 = 16 threads = 1 Maximum-requests = 500 python-path =/home/web1/django_env/lib/python2.6/d'affichage site-packages -name =% {GROUP}

Le problème est que les processus absorbent plus de mémoire que les threads. Par conséquent, nous nous retrouvons généralement avec moins de travailleurs dans l'ensemble (d'où 16x1 au lieu de 8x15). Et puisque mod_wsgi ne fournit pratiquement rien pour signaler comment les travailleurs sont occupés, vous êtes SOL en plus de ne faire que déterminer aveuglément combien vous en avez. A l'envers, ce problème ne se produit plus et les applications sont complètement fiables à nouveau. Comme avec PHP, n'utilisez pas une implémentation à threads sauf si vous êtes sûr que c'est sûr ... cela signifie le noyau (généralement ok), le framework, votre propre code et tout ce que vous importez. :)