[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