2009-12-18 14 views
5

Abbiamo un servizio Web che serve piccoli segmenti arbitrari di un inventario fisso di file MP3 più grandi. I file MP3 sono generati al volo da un'applicazione python. Il modello è, fai una richiesta GET a un URL che specifica quali segmenti vuoi, ottieni uno stream audio/mpeg in risposta. Questo è un processo costoso.Esiste un modo migliore per servire i risultati di un costoso processo Python bloccante su HTTP?

Stiamo utilizzando Nginx come gestore di richieste front-end. Nginx si occupa delle risposte alla cache per richieste comuni.

Inizialmente abbiamo provato a utilizzare Tornado sul back-end per gestire le richieste da Nginx. Come ci si aspetterebbe, l'operazione di blocco MP3 ha impedito a Tornado di fare la sua cosa (I/O asincrono). Quindi, siamo passati al multithreading, che ha risolto il problema del blocco e si sono comportati abbastanza bene. Tuttavia, ha introdotto una condizione di gara sottile (sotto carico del mondo reale) che non siamo ancora stati in grado di diagnosticare o riprodurre. Le condizioni della gara corrompono la nostra uscita MP3.

Così abbiamo deciso di impostare la nostra applicazione come un semplice gestore WSGI dietro Apache/mod_wsgi (sempre con Nginx in primo piano). Questo elimina il problema di blocco e la condizione di competizione, ma crea un carico a cascata (ad esempio Apache crea troppi processi) sul server in condizioni reali. Stiamo lavorando alla messa a punto di Apache/mod_wsgi in questo momento, ma ancora in fase di prova ed errori. (Aggiornamento: siamo tornati a Tornado. Vedi sotto.)

Infine, la domanda: ci manca qualcosa? Esiste un modo migliore per servire le risorse costose della CPU su HTTP?

Aggiornamento: Grazie all'articolo informato di Graham, sono abbastanza sicuro che si tratta di un problema di ottimizzazione di Apache. Nel frattempo, siamo tornati a utilizzare Tornado e stiamo cercando di risolvere il problema della corruzione dei dati.

Per coloro che sono stati così veloci da gettare più ferro sul problema, Tornado e un po 'di multi-threading (nonostante il problema dell'integrità dei dati introdotto dalla filettatura) gestisce il carico in modo accettabile su un'istanza Amazon EC2 di piccole dimensioni (single core) .

risposta

1

Stai commettendo l'errore di utilizzare la modalità incorporata di Apache/mod_wsgi? Leggi:

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

Assicurarsi di utilizzare modalità demone se si utilizza Apache/mod_wsgi.

+0

Eccellente articolo. Grazie. Questo potrebbe finire per fare il trucco. –

+0

In effetti, accetterò questo collegamento come la risposta migliore, poiché il problema sembra essere un problema di ottimizzazione di Apache. –

1

È possibile prendere in considerazione un sistema di accodamento con i metodi di notifica AJAX.

Ogni volta che viene richiesta una risorsa costosa e tale risorsa deve essere generata, aggiungere tale richiesta alla coda (se non è già presente). Quella operazione di accodamento dovrebbe restituire un ID di un oggetto che è possibile interrogare per ottenere il suo stato.

Successivamente devi scrivere un servizio in background che fa girare i thread di lavoro. Questi lavoratori semplicemente deselezionano la richiesta, generano i dati, quindi salva la posizione dei dati nell'oggetto richiesta.

La pagina Web può effettuare chiamate AJAX sul server per scoprire lo stato di avanzamento della generazione e per fornire un collegamento al file una volta disponibile.

Questo è il modo in cui GRANDI siti multimediali funzionano - quelli che devono occuparsi in particolare del video. Potrebbe essere eccessivo per il tuo lavoro MP3 comunque.

In alternativa, esaminare l'esecuzione di un paio di macchine per distribuire il carico. Le discussioni su Apache continueranno a bloccarsi, ma almeno non consumerai risorse sul server web.

+0

Stiamo servendo segmenti piccoli e arbitrari di un inventario fisso di file MP3 più grandi. Il modello è, fai una richiesta GET a un URL che specifica quali segmenti vuoi, ottieni un flusso 'audio/mpeg' in risposta, quindi AJAX non funzionerà. :) –

+1

Bene, allora siamo di nuovo al mio secondo punto: distribuire il carico. Le macchine Linux sono economiche. –

0

Sembra che tu stia facendo le cose a posto - manca solo la potenza della CPU: puoi determinare quale è il carico della CPU nel processo di generazione di questi MP3?

Penso che la prossima cosa da fare sia aggiungere altro hardware per il rendering degli MP3 su altre macchine. Oppure, o trova un modo per consegnare MP3 pre-renderizzati (forse puoi cahce alcuni dei tuoi media?)

BTW, il dimensionamento per il web è stato il tema di una conferenza di Keynote di Jacob Kaplan-Moss su PyCon Brasil quest'anno ed è ben lungi dall'essere un problema chiuso. La pila di tecnologie che è necessario gestire è abbastanza convincente - (non sono riuscito a trovare una copia online della presentazione, però - -dispondi per questo)

+0

Non avevamo sicuramente bisogno di più hardware quando stavamo servendo da Tornado. Il problema potrebbe semplicemente essere la regolazione di Apache. –

2

Hai provato Spawning? È un server WSGI con un assortimento flessibile di modalità di threading.

+0

Interessante. Dovrò esaminarlo. –

1

Si prega di definire "carico a cascata", in quanto non ha un significato comune.

Il problema più probabile sarà se si stanno eseguendo troppi processi Apache.

Per un carico di questo tipo, assicurarsi di utilizzare prefork mpm e assicurarsi di limitare a un numero appropriato di processi (non meno di uno per CPU, non più di due).

+0

Con "caricamento a cascata" intendo che Apache stava generando processi, volenti o nolenti. Ci scusiamo per l'offuscamento. Il collegamento di Graham sembra spiegare abbastanza bene la situazione. –

Problemi correlati