2009-12-18 9 views
5

Tenemos un servicio web que sirve segmentos pequeños y arbitrarios de un inventario fijo de archivos MP3 más grandes. Los archivos MP3 se generan sobre la marcha con una aplicación de Python. El modelo es, realizar una solicitud GET a una URL especificando qué segmentos desea, obtener una transmisión audio/mpeg en respuesta. Este es un proceso costoso.¿Existe alguna forma mejor de servir los resultados de un costoso proceso de bloqueo de python a través de HTTP?

Estamos utilizando Nginx como el controlador de solicitudes de la interfaz de usuario. Nginx se ocupa de las respuestas de caché para solicitudes comunes.

Inicialmente tratamos de usar Tornado en el back-end para manejar las solicitudes de Nginx. Como era de esperar, la operación de bloqueo de MP3 impidió que Tornado hiciera lo suyo (E/S asíncrona). Entonces, fuimos multiproceso, lo que resolvió el problema de bloqueo y funcionó bastante bien. Sin embargo, introdujo una sutil condición de carrera (bajo la carga del mundo real) que aún no hemos podido diagnosticar ni reproducir. La condición de carrera corrompe nuestra salida de MP3.

Así que decidimos configurar nuestra aplicación como un gestor de WSGI simple detrás de Apache/mod_wsgi (todavía con Nginx desde el principio). Esto elimina el problema de bloqueo y la condición de carrera, pero crea una carga en cascada (es decir, Apache crea demasiados procesos) en el servidor en condiciones del mundo real. Estamos trabajando para ajustar Apache/mod_wsgi en este momento, pero aún en una fase de prueba y error. (Actualización: hemos cambiado a Tornado. Consulte a continuación.)

Finalmente, la pregunta: ¿nos falta algo? ¿Hay una mejor manera de servir recursos costosos de CPU a través de HTTP?

Actualización: Gracias al artículo informado de Graham, estoy bastante seguro de que se trata de un problema de ajuste de Apache. Mientras tanto, hemos vuelto a usar Tornado y estamos tratando de resolver el problema de corrupción de datos.

Para aquellos que fueron tan rápidos para lanzar más hierro al problema, Tornado y un poco de multi-threading (a pesar del problema de integridad de datos introducido por el enhebrado) maneja la carga aceptablemente en una pequeña instancia de Amazon EC2 .

Respuesta

1

¿Está cometiendo el error de utilizar el modo incrustado de Apache/mod_wsgi? Leer:

http://blog.dscpl.com.au/2009/03/load-spikes-and-excessive-memory-usage.html

asegurarse de que usa modo demonio si se utiliza Apache/mod_wsgi.

+0

Excelente artículo. Gracias. Esto podría terminar haciendo el truco. –

+0

De hecho, voy a aceptar este enlace como la mejor respuesta, ya que el problema parece ser un problema de ajuste de Apache. –

1

Puede considerar un sistema de cola con métodos de notificación AJAX.

Siempre que haya una solicitud para su recurso costoso, y ese recurso necesita ser generado, agregue esa solicitud a la cola (si no está ya allí). Esa operación de cola debe devolver una ID de un objeto que puede consultar para obtener su estado.

A continuación, tiene que escribir un servicio en segundo plano que activa los hilos de los trabajadores. Estos trabajadores simplemente dequeuean la solicitud, generan los datos y luego guardan la ubicación de los datos en el objeto de solicitud.

La página web puede hacer llamadas AJAX a su servidor para conocer el progreso de la generación y para dar un enlace al archivo una vez que esté disponible.

Así es como funcionan los sitios de medios GRANDES, los que tienen que lidiar con el video en particular. Sin embargo, podría ser excesivo para su trabajo en MP3.

Alternativamente, busque ejecutar un par de máquinas para distribuir la carga. Sus hilos en Apache seguirán bloqueándose, pero al menos no consumirá recursos en el servidor web.

+0

Estamos sirviendo segmentos pequeños y arbitrarios de un inventario fijo de archivos MP3 más grandes. El modelo es, hacer una solicitud GET a una URL que especifique qué segmentos desea, obtener una transmisión 'audio/mpeg' en respuesta, por lo que AJAX no funcionará. :) –

+1

Bueno, entonces volvemos a mi segundo punto: distribuir la carga. Las máquinas Linux son baratas. –

0

Parece que está haciendo las cosas bien, solo le falta potencia de CPU: ¿puede determinar cuál es la carga de la CPU en el proceso de generar estos MP3?

Creo que lo siguiente que tienes que hacer es agregar más hardware para renderizar los MP3 en otras máquinas. O eso o encontrar una manera de entregar MP3 pre-renderizado (¿quizás puede comprar algunos de sus medios?)

BTW, escalar para la web fue el tema de una conferencia magistral de Jacob Kaplan-Moss sobre PyCon Brasil este año , y está lejos de ser un problema cerrado. La pila de tecnologías que uno necesita manejar es bastante impresible (aunque no pude encontrar una copia en línea de la presentación). Lo siento por eso.

+0

Definitivamente no necesitábamos más hardware cuando atendíamos a Tornado. El problema puede ser simplemente afinar Apache. –

2

¿Has probado Spawning? Es un servidor WSGI con una variedad flexible de modos de enhebrado.

+0

Interesante. Tendré que investigarlo. –

1

Defina "carga en cascada", ya que no tiene un significado común.

Su problema más probable será si está ejecutando demasiados procesos de Apache.

Para una carga como esta, asegúrese de estar utilizando prefork mpm y asegúrese de limitarse a un número adecuado de procesos (no menos de uno por CPU, no más de dos).

+0

Por "carga en cascada" quiero decir que Apache estaba generando procesos de cualquier manera. Perdón por la ofuscación. El vínculo de Graham parece explicar la situación bastante bien. –

Cuestiones relacionadas