[Python] web: sync vs. async
Daniele Varrazzo
piro a develer.com
Ven 2 Dic 2011 16:18:44 CET
On Fri, 2 Dec 2011 15:36:50 +0100, Alessandro Dentella wrote:
> un cliente mi ha chiesto di aiutare a capire come rendere più veloce
> una
> applicazione web che raccoglie dati da molti utenti differenti in
> contemporanea (qualche centinaio) e si ingolfa in particolari momenti
> del mese di maggior accesso.
>
> Attualmente usano Tornado [1], un incrocio fra un server web ed un
> piccolo
> framework (che tramite un decoratore permette di rendere una funzione
> asincrona).
>
> Non ho alcuna esperienza di Tornado, qualche esperienza con twisted e
> qualche dubbio sul fatto che quel particolare problema abbia grandi
> vantaggi
> dall'approccio asincrono. L'applicazione lato client usa intensamente
> ajax e
> molte chiamate al server che fanno pochi conti ed una manciata di
> select
> semplici o di piccole join. La macchina ha 4 processori e 4 GB di RAM
> (principalmente libera). Ogni chiamata dallo stesso client cambia
> dati nella
> sessione che devono quindi essere sincronizzati fra una chiamata e
> l'altra.
>
> Mi pare di capire che non tutte le applicazioni beneficiano del fatto
> di
> funzionare in modalità asincrona: qui non esiste tempo di attesa
> significativo di dati dalla rete e pare poco (forse migliorabile in
> ogni
> caso) dal database. Avete qualche suggerimento? Qualche opinione (o
> link
> utile) sulla opportunità di usare un server così rispetto ad una
> configurazione classica apache + mod_wsgi? Chiaramente l'obiettivo è
> di
> distribuire il carico di lavoro su tutti i processori e
> successivamente su
> più macchine.
Io ho risolto da poco un problema del genere su un server che non ce la
faceva più a scalare.
Prima nota che, sync con multithread, o async con green thread, più di
una cpu non riesci a usarla bene in Python. Con i green thread la usi
meglio che con i thread se il problema è I/O bound, ma resti sempre in
un processo singolo.
Io ho messo 4 server in ascolto su 4 porte diverse: il primo sulla
standard https 443 e altre 8444, 8445, 8446 (la bella copia sarebbe
avere 4 sub-domain, ma per ora abbiamo solo un certificato ssh).
Quando un utente si connette, viene rediretto ad un certo nodo (id
utente % n. nodi, per esempio). Da lì in poi tutti i link del programma
sono relativi, per cui una volta che è andato sul server
https://host:8445, ci resta. Il suo nodo di appartenenza è anche
memorizzato al momento del login nella sua sessione del server: ad ogni
richiesta viene controllato che sia sul server giusto e, se non lo è,
gli viene servito un redirect per mandarcelo.
Questa soluzione consente di usare tutte le cpu sulla macchina nella
maniera migliore possibile: con diversi processi. Perché funzioni si
assume che gli utenti non si scambino dati tra loro se non attraverso il
database. Invece poiché un utente resta sempre sullo stesso server, i
suoi dati di sessione sono sempre disponibili. Per scalare di più
possiamo aggiungere nuovi processi (la nostra macchina ha 16 cpu) o
anche aggiungere nuove macchine.
Abbiamo messo in piedi il tutto in brevissimo tempo, senza modificare
l'architettura di un applicativo che è un mammuth e nel quale ogni
utente ha uno stato complicatissimo. È una soluzione completamente priva
di magie (tipo sperare che la parola magica async risolva tutti i
problemi...)
--
Daniele Varrazzo - Develer S.r.l.
http://www.develer.com
Maggiori informazioni sulla lista
Python