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
_______________________________________________
Python mailing list
Python@lists.python.it
http://lists.python.it/mailman/listinfo/python