2009-12-18 15 views
5

Nous avons un service Web qui sert de petits segments arbitraires d'un inventaire fixe de gros fichiers MP3. Les fichiers MP3 sont générés à la volée par une application python. Le modèle est, faire une demande GET à une URL en spécifiant quels segments vous voulez, obtenir un flux audio/mpeg en réponse. C'est un processus coûteux.Existe-t-il un meilleur moyen de diffuser les résultats d'un processus python bloquant coûteux sur HTTP?

Nous utilisons Nginx comme gestionnaire de requêtes frontal. Nginx prend soin de la mise en cache des réponses pour les demandes courantes.

Nous avons d'abord essayé d'utiliser Tornado sur le back-end pour traiter les demandes de Nginx. Comme vous pouvez vous y attendre, l'opération de blocage du MP3 a empêché Tornado de faire son truc (E/S asynchrones). Donc, nous sommes allés multithread, ce qui a résolu le problème de blocage, et a très bien fonctionné. Cependant, il a introduit une condition de course subtile (sous la charge du monde réel) que nous n'avons pas encore pu diagnostiquer ou reproduire. La condition de course corrompt notre sortie MP3.

Nous avons donc décidé de définir notre application comme un simple gestionnaire WSGI derrière Apache/mod_wsgi (toujours avec Nginx à l'avant). Cela élimine le problème de blocage et la condition de concurrence, mais crée une charge en cascade (c'est-à-dire qu'Apache crée trop de processus) sur le serveur dans des conditions réelles. Nous travaillons actuellement sur le réglage d'Apache/mod_wsgi, mais toujours dans une phase d'essai et d'erreur. (Mise à jour: nous sommes retournés à Tornado, voir ci-dessous.)

Enfin, la question: avons-nous oublié quelque chose? Existe-t-il une meilleure façon de traiter les ressources coûteuses en ressources CPU sur HTTP?

Mise à jour: Merci à l'article informé de Graham, je suis sûr qu'il s'agit d'un problème de réglage Apache. En attendant, nous sommes retournés à Tornado et essayons de résoudre le problème de corruption de données. Pour ceux qui ont été si rapides à jeter plus de fer sur le problème, Tornado et un peu de multi-threading (malgré le problème d'intégrité des données introduit par thread) gère la charge de manière acceptable sur une petite instance Amazon EC2 .

Répondre

1

Vous pourriez envisager un système de mise en attente avec des méthodes de notification AJAX.

Chaque fois qu'une requête pour votre ressource coûteuse est requise et que cette ressource doit être générée, ajoutez cette requête à la file d'attente (si ce n'est déjà fait). Cette opération de mise en file d'attente doit renvoyer un ID d'un objet que vous pouvez interroger pour obtenir son état.

Ensuite, vous devez écrire un service d'arrière-plan qui tourne en threads de travail. Ces travailleurs suppriment simplement la demande, génèrent les données, puis sauvegardent l'emplacement des données dans l'objet de requête.

La page Web peut effectuer des appels AJAX sur votre serveur pour connaître la progression de la génération et donner un lien vers le fichier dès qu'il est disponible.

Voici comment les sites de médias de gros travaux - ceux qui doivent faire face à la vidéo en particulier. Il pourrait être trop pour votre travail MP3 cependant.

Alternativement, regardez dans l'exécution de quelques machines pour distribuer la charge. Vos discussions sur Apache bloqueront toujours, mais au moins vous ne consommerez pas de ressources sur le serveur Web.

+0

Nous desservons de petits segments arbitraires d'un inventaire fixe de gros fichiers MP3. Le modèle est, faire une requête GET à une URL spécifiant quels segments vous voulez, obtenir un flux 'audio/mpeg' en réponse, donc AJAX ne fonctionnera pas. :) –

+1

Eh bien, nous revenons à mon deuxième point: répartir la charge. Les machines Linux sont bon marché. –

0

Il semble que vous fassiez les choses correctement - il vous manque simplement la puissance du processeur: pouvez-vous déterminer quel est le chargement du processeur dans le processus de génération de ces fichiers MP3?

Je pense que la prochaine chose que vous devez faire ici est d'ajouter plus de matériel pour rendre le MP3 sur d'autres machines. Ou cela ou trouver un moyen de livrer MP3 pré-rendu (peut-être vous pouvez cahce certains de vos médias?)

BTW, mise à l'échelle pour le web a été le thème d'une conférence Keynote par Jacob Kaplan-Moss sur PyCon Brasil cette année , et c'est loin d'être un problème fermé. La pile de technologies à manipuler est assez impressionnante - (je n'ai pas pu trouver une copie en ligne de la présentation, cependant - désolé pour cela)

+0

Nous n'avions certainement pas besoin de plus de matériel quand nous servions de Tornado. Le problème peut simplement être le réglage d'Apache. –

2

Avez-vous essayé Spawning? C'est un serveur WSGI avec un assortiment flexible de modes de threading. Avez-vous fait l'erreur d'utiliser le mode intégré d'Apache/mod_wsgi?

+0

Intéressant. Je vais devoir regarder dedans. –

1

Veuillez définir "charge en cascade" car elle n'a pas de signification commune.

Votre problème le plus probable se produira si vous exécutez trop de processus Apache.

Pour une charge comme celle-ci, assurez-vous d'utiliser prefork mpm et assurez-vous de vous limiter à un nombre approprié de processus (pas moins d'un par CPU, pas plus de deux).

+0

Par «charge en cascade», je veux dire Apache était processus de ponte willy-nilly. Désolé pour l'obscurcissement. Le lien de Graham semble expliquer assez bien la situation. –