PDA

View Full Version : [Python][Google App Engine]Interazione tra gli utenti


ingframin
11-06-2011, 18:49
Ciao gioventù,
ho bisogno di capire una cosa e non so davvero dove sbattere la testa.
Sto scrivendo un'app per google app engine e avrei bisogno di fare interagire gli utenti che visitano una pagina tra di loro.
L'unica cosa che mi è venuta in mente è ogni utente a turno scrive sulla base di dati e l'altro prima di fare il suo turno legge dalla base di dati.
Però mi sembra un'assurdità... Una chat tipo quella di facebook come funziona?
Ma anche una chat qualunque come funziona?
Se io volessi implementare che ne so... una partita a scacchi, come faccio a far vedere all'utente B che l'utente A ha mosso?
Tutto qui, non mi serve che mi scriviate il codice (sempre ben accetto, per carità :D ) ma più che altro vorrei capire il meccanismo e dove posso cercare informazioni in merito.
Grazie mille ^_^

WarDuck
11-06-2011, 19:28
Beh la scacchiera è un qualcosa di condiviso fra gli utenti, per cui nel momento in cui un utente fa la mossa cambia lo stato e questo per entrambi (stato che potrebbe stare benissimo in memoria lato server, credo).

Ovviamente se parliamo di applicazioni web questo vuol dire che la pagina dovrà essere aggiornata con una certa frequenza, presumo usando AJAX.

Tuttavia sono ignorante in materia per cui delego a qualcuno più esperto di dare una risposta più esauriente.

Comunque sono interessato anche io alla questione, in particolar modo come fare per conservare lo stato di molti utenti e farlo evolvere anche se questi non sono connessi (ad esempio un personaggio guidato da computer che interagisce con i personaggi degli utenti anche se questi ultimi non sono connessi).

nico159
12-06-2011, 10:37
Puoi usare benissimo l'approccio di un database, è la soluzione più semplice al tuo problema

Per far vedere gli aggiornamenti, dovrai richiedere ogni tot secondi lo stato della tua app

E' una approccio che si adatta benissimo ai principi di App Engine

Come funziona la chat di Facebook?
La chat è divisa in servizi ognuno dej quali si prende carico di un determinato compito
Vista molto dall'alto:
- Un sistema scritto in Erlang che si prende carico di tenere le code dei messaggi da inviare e che il browser riceve tramite long polling/comet
- Un sistema scritto in C++ che mantiene nella ram lo stato dell'utente incluso quello di tutta la sua lista amici (è la parte più complessa di tutta la chat)
- Un sistema di logging dei messaggi
- L'interfaccia web (php)
Ognuno di questi servizi è distribuito su centinaia di nodi

nico159
12-06-2011, 10:54
EDIT: doppio

ingframin
12-06-2011, 11:24
Ma se uso l'approccio del database significa che ogni utente per ogni azione che compie fa una scrittura e gli altri una lettura.
Non richiede una marea di risorse fare una chat così?
E un gioco?
Non c'è nessun altra via meno "consumona"?

WarDuck
12-06-2011, 12:00
Ma se uso l'approccio del database significa che ogni utente per ogni azione che compie fa una scrittura e gli altri una lettura.
Non richiede una marea di risorse fare una chat così?
E un gioco?
Non c'è nessun altra via meno "consumona"?

Se non hai bisogno della persistenza IMHO puoi anche salvare lo stato in RAM (in un buffer che tenga traccia degli ultimi N update ad esempio), volendo puoi fare in modo che ogni tot lo stato venga salvato su un DB, in maniera tale che in caso di crash del server venga ripristinata la sessione.

nico159
12-06-2011, 12:43
Ma se uso l'approccio del database significa che ogni utente per ogni azione che compie fa una scrittura e gli altri una lettura.
Non richiede una marea di risorse fare una chat così?
E un gioco?
Non c'è nessun altra via meno "consumona"?
Devi sempre contestualizzare i tuoi problemi

Il contesto è una webapp con bacino d'utenza sicuramente minore a 100 giocatori contemporanei con mosse che si susseguono nell'ordine di almeno 10s l'una dall'altra

Sono nel caso peggiore 100 scritture al secondo, una fesseria ;)

Per ottenere lo stato invece considerando un poll di ogni due secondi, sono meno di 50 query ricorrenti ogni secondo, ancora più una fesseria

Puoi anche effettuare il carching tramite memcache di queste query, ma poi devi gestire l'invalidazione della cache. Devi valutare se ne valga la pena

Se il tuo contesto è invece creare una chat, devi contestualizzare anche gli utenti online e una media di messaggi che questi utenti connessi e il contesto della chat (una chat applicata ad un gioco sarà meno attiva di un IM)
E cosa più importante devi gestire la loro presenza e la presenza di eventuali stanze o contatti

Se non hai bisogno della persistenza IMHO puoi anche salvare lo stato in RAM (in un buffer che tenga traccia degli ultimi N update ad esempio), volendo puoi fare in modo che ogni tot lo stato venga salvato su un DB, in maniera tale che in caso di crash del server venga ripristinata la sessione.
Si potrebbero sfruttare i Backends di App Engine, ma questo porterebbe a dei costi aggiuntivi senza una reale motivazione dietro
Altrimenti si potrebbe pensare ad usare le api per memcache che fornice App Engine

dierre
12-06-2011, 12:48
Devi usare una tecnologia tipo Comet. In poche parole i tuoi utenti fanno una subscribe ad un channel(che sarebbe la pagina) e sarà il channel ad aggiornare i client che quindi non avranno bisogno di "refreshare". Così ti eviti il db.

nico159
12-06-2011, 12:49
Devi usare una tecnologia tipo Comet. In poche parole i tuoi utenti fanno una subscribe ad un channel(che sarebbe la pagina) e sarà il channel ad aggiornare i client che quindi non avranno bisogno di "refreshare". Così ti eviti il db.
Non si può fare su App Engine
Il server deve rispondere entro il limite massimo dei 30 secondi. Inoltre sarebbe impossibile gestirne lo stato dato che su App Engine forza l'app ad essere (giustamente, se si vuole una webapp scalabile) stateless
Solo i Backends (costo aggiuntivo, non sono scalabili dopo un certo limite) non hanno limite e possono conservare al loro interno uno stato

EDIT: mi scuso per la mia risposta, App Engine finalmente supporta anche il long polling:
http://www.youtube.com/watch?v=oMXe-xK0BWA

dierre
12-06-2011, 13:04
Non si può fare su App Engine
Il server deve rispondere entro il limite massimo dei 30 secondi. Inoltre sarebbe impossibile gestirne lo stato dato che su App Engine forza l'app ad essere (giustamente, se si vuole una webapp scalabile) stateless
Solo i Backends (costo aggiuntivo, non sono scalabili dopo un certo limite) non hanno limite e possono conservare al loro interno uno stato

Eh io non conosco appengine. Lui chiedeva come faceva facebook. Possible che appengine non abbia una tecnologia publish subscribe?

ingframin
12-06-2011, 13:09
Allora, vi racconto un po' cosa sto cercando di fare.
Sto cercando di mettere in piedi un browser game in cui ci sono:
1) Un sito normalissimo con aggiornamenti, news, ecc... banale
2) Un forum. Non banalissimo ma se ne trovano a bizzeffe di esempi,
devo solo adattare alle mie esigenze quello che voglio fare.
3) Una chat room. La prima cosa che mi è venuta in mente è crearla io e ho esposto il problema, ma forse potrei pensare di costruire un piccolo client IRC tipo quello in java di azzurra.
4) Una sorta di stanza dove gli utenti si sfidano e a turno fanno le loro mosse.
Ora i problemi che non riesco a sormontare sono 2:
1) avere più repliche della "stanza dei duelli" ciascuna in cui possono interagire n giocatori (sempre in numero pari).
2) fare in modo che se il giocatore A fa una mossa il giocatore B la veda e contrattacchi.

In giro ho trovato delle chat che sfruttano Ajax e la base di dati.
La chat di facebook era un esempio che rendeva un po'l'idea ma mi rendo conto che quel sistema è iper personalizzato. Io non posso permettermi i miei server :-/
Quindi nisba, userò la base di dati. Se poi il sito avrà così tanto successo che diventerà ingestibile in quel modo, allora valuterò il da farsi, magari mi appoggerò a un esperto.
E poi d'altro canto se uso irc per la chat alleggerisco di molto il carico di lavoro sul mio database. Per un combattimento la base di dati può bastare benissimo.
Spero :s
E in ogni caso mi rimane il problema degli scontri tra giocatori. Come gestisco n stanze? Devo creare un set di tabelle per stanza?

nico159
12-06-2011, 13:10
Eh io non conosco appengine. Lui chiedeva come faceva facebook. Possible che appengine non abbia una tecnologia publish subscribe?
E' stato aggiunto finalmente aggiunta circa 1 anno fa, ho aggiornato il mio reply

ingframin con le "ultime" novità di App Engine ora è facile creare il tuo gioco :ciapet:

http://code.google.com/intl/it-IT/appengine/docs/python/channel/overview.html

C'è tutto ciò che ti serve sapere

WarDuck
12-06-2011, 13:13
Sfrutto l'occasione per farvi una domanda inerente comunque queste problematiche (spero che ingframin non se la prenda per il leggero off-topic)...

Volendo mantenere uno stato persistente, in particolare volendo fare un game web-based in cui il mondo è condiviso da tutti (ed eventualmente alcuni personaggi vengono gestiti dal computer sottoforma di eventi temporizzati), come si potrebbe/dovrebbe fare?

Esistono dei giochi nei quali l'azione richiede del tempo, ad esempio non so se avete mai giocato ad Ogame, quando viene effettuata una qualsiasi azione questa richiede del tempo (es. 2 ore per costruire la fabbrica X piuttosto che per condurre un attacco)... questa cosa ovviamente non è lato client (dunque l'utente può anche spegnere tutto e andarsi a fare una passeggiata).

La mia supposizione è che ci sia una coda degli eventi che viene processata dalla web application... è corretto?

In questo caso come si gestisce un eventuale crash del server? Tutto è gestito dal DB? (coda degli eventi inclusa?).

So anche che esistono dei DB orientati agli oggetti che di fatto memorizzano al loro interno gli oggetti stessi, dunque in linea teorica l'interazione DB-WebApp dovrebbe risultare più semplice, o no?

nico159
12-06-2011, 13:41
Sfrutto l'occasione per farvi una domanda inerente comunque queste problematiche (spero che ingframin non se la prenda per il leggero off-topic)...

Volendo mantenere uno stato persistente, in particolare volendo fare un game web-based in cui il mondo è condiviso da tutti (ed eventualmente alcuni personaggi vengono gestiti dal computer sottoforma di eventi temporizzati), come si potrebbe/dovrebbe fare?

Esistono dei giochi nei quali l'azione richiede del tempo, ad esempio non so se avete mai giocato ad Ogame, quando viene effettuata una qualsiasi azione questa richiede del tempo (es. 2 ore per costruire la fabbrica X piuttosto che per condurre un attacco)... questa cosa ovviamente non è lato client (dunque l'utente può anche spegnere tutto e andarsi a fare una passeggiata).

La mia supposizione è che ci sia una coda degli eventi che viene processata dalla web application... è corretto?

In questo caso come si gestisce un eventuale crash del server? Tutto è gestito dal DB? (coda degli eventi inclusa?).

So anche che esistono dei DB orientati agli oggetti che di fatto memorizzano al loro interno gli oggetti stessi, dunque in linea teorica l'interazione DB-WebApp dovrebbe risultare più semplice, o no?
Mai lavorato ad un game server, ma alla fine http è solo uno dei tanti modi per fare IPC :D

Si tratta solo di costruire un layer web sopra un game server scritto ad esempio in C++

Se dovessi costruire da zero tutto:
Pensare prima di tutto a come partizionare il mondo in modo da associare ad ogni partizione del mondo un determinato server

- Un game server "zone" che ci occupa di una determinata parte del gioco che replica i suoi eventi agli altri server "zone" di backup dedicati alla stessa zona (master/slave)
In questa maniera avrai sempre almeno una copia dello stato per quella partizione di gioco immediatamente pronta in caso di down del master - senza dover aspettare l'avvio di nuove istanze del server e la sincronizzazione con il database

- Un server per mantenere lo stato dei client
In questo caso oltre che il classico master/slave salverà i cambiamenti di stato in un database
Puoi partizionare anche questo componente se la mole d'utenza diventa importante

- Un server per la coda degli eventi che fa uso di un albero binario ordinato per data di esecuzione dell'evento quindi con tempi di aggiunta O(Log(N)) e tempi di ricerca del prossimo evento da eseguire O(1)
Ogni evento di aggiunta/rimozione dall'albero binario viene riportato in maniera sincrona a tutti i suoi slave
Il resto del server sarebbe: un semplice loop che ogni tot guarda ritrova il prossimo evento in scadenza e se la sua proprietà DataInCuiEseguire "coincide" lo invia al server che gestisce quella partizione del mondo a cui l'evento fa riferimento e lo rimuove dall'albero
E' la soluzione migliore quando si hanno da gestire così tanti "timer"

Quindi l'architettura della parte "web" sarebbbe:

Server monothread asincrono (a la nginx) che mantiene coda degli eventi ancora non ricevuti dal client e che gestisce la comunicazione tra browser e server web implementando HTTP/Flash Socket/Web Socket
| GET -> Restituisce al client l'ultimo evento da Dizionario<ClientGuid, Queue<Evento>>
| POST-> Router del server di gioco che fa il parsing dell'evento ricevuto e lo invia al server che gestisce una partizione del gioco / server eventi - dovrebbe funzionare anche come supervisore per controllare se utilizzare il master o eleggere a master uno slave
| PUT (solo richieste interne) -> Aggiungi un Evento al client ClientGuid

In questo lo stato è replicato su più server in senza quasi mai l'uso di un database, il gioco è scalabile, l'achitettura alla fine dei conti è semplice

dierre
12-06-2011, 18:17
[....]

In questo caso come si gestisce un eventuale crash del server? Tutto è gestito dal DB? (coda degli eventi inclusa?).

So anche che esistono dei DB orientati agli oggetti che di fatto memorizzano al loro interno gli oggetti stessi, dunque in linea teorica l'interazione DB-WebApp dovrebbe risultare più semplice, o no?

L'uso di db ad oggetti non ti dovrebbe preoccupare più di tanto perché ti sconsiglio di reinventare la ruota ed usare un framework con la sua bella orm libraray per descrivere i tuoi modelli (le tabelle cioè) come classi in relazione tra loro.

Per quanto riguarda la temporizzazione, io lascerei stare il database perché metti che poi devi cambiare il database che fai? Riscrivi tutte le procedure? Meglio appoggiarti ad una soluzione ad alto livello come detto sopra.

Di base devi farti un demone per fare questi controlli. Se vuoi vedila come un loop che ogni secondo controlla gli eventi da assolvere e li assolve perché se ti affidi ad uno scheduler, che sia lato db o lato sistema operativo, ti si potrebbero sovrapporre le esecuzioni.

ingframin
12-06-2011, 18:18
E' stato aggiunto finalmente aggiunta circa 1 anno fa, ho aggiornato il mio reply

ingframin con le "ultime" novità di App Engine ora è facile creare il tuo gioco :ciapet:

http://code.google.com/intl/it-IT/appengine/docs/python/channel/overview.html

C'è tutto ciò che ti serve sapere

*_* mi viene quasi voglia di piangere dalla gioia :D :cry:


Sfrutto l'occasione per farvi una domanda inerente comunque queste problematiche (spero che ingframin non se la prenda per il leggero off-topic)...
Non mi dispiace affatto, l'argomento è molto interessante!
Io sono un appassionato di videogame e anche di come si creano i videgoame.
E poi queste discussioni arricchiscono il forum secondo me :-)