Pages: [1]   Go Down
Print
Author Topic: scalabilità e concorrenza  (Read 1530 times)
0 Members e 1 Utente non registrato stanno visualizzando questa discussione.
hukketto
Forumista Esperto
****
Offline Offline

Gender: Male
Posts: 1.000



« on: 01-05-2012, 12:39:56 »

Posto il seguente problema quale approccio usereste?

Una applicazione web permette di modificare dei dati su un database.
l'applicazione è ovviamente multiutente
l'utente Alice vuole modificare i dati relativi al record #100, apre la maschera in visualizzazione, modifica i dati ma non li invia (non fa committ)
l'utente Bob apre i dati relativi al record #100 , apre la maschera in visualizzazione, modifica i dati e li invia (fa un commit)
l'utente Alice adesso decide di inviare i dati da lui modificati e fa commit.
Ovviamente le modifiche dell'utente Bob sono andate perse.
Che approccio usereste sia per mantenere la base di dati in uno stato consistente sia per mantenere l' esperienza utente non troppo spiacevole?

Io ho riflettuto su un paio di approcci ma volevo confrontarmi con voi, magari qualcuno può avere idee migliori.

a) all'apertura della pagina di modifica salviamo un timestamp in sessione, salviamo inoltre sul db un timestamp con l'ultima modifica. al momento del commit verifichiamo che il timestamp salvato sul db sia anteriore al timestamp in sessione. Se è anteriore procediamo al salvataggio altrimenti lo blocchiamo avvertendo l'utente di una probabile inconsistenza (l'utente potrà continuare forzando la sovrascrittura, o annullare ricaricando la pagina perdendo però le proprie modifiche)

b) un ping (ajax) in polling che verifichi continuamente il timestamp e nel caso il timestamp sia cambiato, avvertiamo l'utente chiedendogli se vuole aggiornare la pagina ricaricando i nuovi dati.

questi mi sembrano gli approcci più semplici e meno dispendiosi in termini di risorse, anche se immagino sia abbastanza frustrante per un utente perdere le modifiche che aveva apportato per ricaricare la pagina.

Altre idee mi sembrano più onerose in termini di risorse hw e in termini di implementazione.
come ad esempio la..

c) bloccare la modifica dei dati (verificando che un timestamp lastlock non sia inferiore ad esempio a 1 minuto) finché un utente ha aperta la maschera di modifica. Per ottenere questo risultato bisogna prevedere anche che un utente possa chiudere la pagina di modifica senza notificarne correttamente l'uscita o un utente possa dimenticare la maschera di modifica aperta, bloccando a tutti gli altri l'accesso a quella risorsa.
Per evitare ciò si dovrebbe per questo pensare a un timestamp che si aggiorni in polling sempre con un ping ogni tot secondi solo in presenza di interazioni dell'utente con la UI. Nel caso in cui un utente rimanga per troppo tempo senza fare nulla gli verrà notificato che ha perso troppo tempo e dovrà ricaricare la pagina (e questo è pure abbastanza noioso ...già..)

Quest'approccio eviterebbe la perdita delle modifiche apportate da Alice in presenza di Bob o altri utenti concorrenti, ma mi sembra troppo dispendioso su tutti i fronti.

Ora, escludendo l'update finale relativo a tutti i dati da modificare..

Analizzando l'approccio a)
ipotizzando N utenti che aprono in maniera concorrente la stessa pagina di modifica avremo N scritture in sessione, N select sul db, e 1 solo update.

analizzando l'approccio b)
ipotizzando N utenti che aprono in maniera concorrente la stessa pagina di modifica avremo N scritture in sessione, N * numero di secondi del polling di select sul db, e 1 update. Più dispendioso del precedente caso in termini di risorse, ma se il db si avvale della cache dovrebbe avere un impatto costante.

analizzando l'approccio c)
ipotizzando N utenti che aprono in maniera concorrente la stessa pagina di modifica avremo 0 scritture in sessione, 1 * numero di secondi del polling di update sul db (aggiornamento del timestamp). molto più dispendioso visto che un update equivale ad una select + il vero e proprio update + la riorganizzazione degli indici.

Posto che il servizio debba anche scalare sia sul numero di utenti sia sulla mole dei dati da aggiornare, su cosa puntereste? 

(buon primo maggio!)
Logged

LtWorf
Forumista Esperto
****
Offline Offline

Posts: 1.079

Ogni cosa da me scritta è da intendersi come opinione personale e non come dato di fatto. Anche le eventuali dimostrazioni matematiche da me scritte saranno opinioni personali e quindi dovranno venire dimostrate da una terza parte di fiducia


WWW
« Reply #1 on: 13-05-2012, 16:01:17 »

Un timestamp globale per tutto il database non credo ti aiuti molto, dato che non ti dice quale record è stato modificato (magari un altro record che non c'entrava nulla).

Io farei che il client manda le sue modifiche + i valori originari del record, e poi lato server in una transazione fai select per vedere se il record è come ti aspetti che sia e sempre nella transazione fai l'update. Altrimenti notifichi il client che ci sono state delle modifiche e se la vede la persona cosa vuole fare.

I database più evoluti (Mysql NO) supportano lock su intere righe, gruppi di righe o colonne, ma non li ho mai usati, non so se possano essere usati al di fuori di una transazione.
Logged

There are some OO programming languages. I will create the first -_-' language.

LtWorf
hukketto
Forumista Esperto
****
Offline Offline

Gender: Male
Posts: 1.000



« Reply #2 on: 17-05-2012, 19:39:43 »

alla fine ho scelto la soluzione a) ossia usare un timestamp (non globale x tutto il db ma solo sulla riga della entità principale da modificare... nel mio caso un record della tabella 'jobs', che è collegata direttamente e indirettamente ad un altra decina di tabelle).
Per ogni modifica apportata ad un job (e entità collegate) salvo con la tupla anche il timestamp relativo. Poi, sul front end, all'apertura della pagina di modifica, istanzio un timestamp che confronto via ajax in polling ogni 30 secondi (eseguendo una select sull'id lavoro(indice) che mi restituisce solo il timestamp.. veloce si.. ma a meno di non volere mettere memcache pensavo di usare direttamente il filesystem per evitare quei piccoli carichi al db...sull'impronta della filosofia NoSQL Smiley ) . Se la call ajax trova sul db un timestamp più recente allora il job è stato modificato o lo notifico all'utente chiedendogli cosa vuole fare.. se integrare le modifiche, rigettare le proprie o sovrascriverle.
Lo stesso controllo viene comunque eseguito anche al momento in cui l'utente finalizza la modifica .
Il lock viene inserito poi a livello di transazione direttamente sulle tabelle e ahimè so bene che mysql non è il massimo per tanti tanti aspetti (da un po' sono anche abbastanza incuriosito dalla giungla del NoSQL).
A volere rendere comunque il controllo più 'realtime' mi sa che tocca optare per le websockets..un proxy e un infrastruttura un po' più complessa
Logged

LtWorf
Forumista Esperto
****
Offline Offline

Posts: 1.079

Ogni cosa da me scritta è da intendersi come opinione personale e non come dato di fatto. Anche le eventuali dimostrazioni matematiche da me scritte saranno opinioni personali e quindi dovranno venire dimostrate da una terza parte di fiducia


WWW
« Reply #3 on: 17-05-2012, 20:43:40 »

Non capisco come fare richieste continue possa ridurti il carico ma ok...
Logged

There are some OO programming languages. I will create the first -_-' language.

LtWorf
hukketto
Forumista Esperto
****
Offline Offline

Gender: Male
Posts: 1.000



« Reply #4 on: 17-05-2012, 21:09:26 »

no non lo riduce affatto :D ma è richiesto dalle specifiche avere un feedback sullo stato di un job .. 'al più presto possibile' .. quindi il polling mi è sembrato un buon compromesso.
 

Logged

Pages: [1]   Go Up
Print
Jump to: