Sto costruendo una webapp (frontend angolare, Groovy / Spring / Hibernate / MySQL backend) che permetterà agli utenti di competere l'uno contro l'altro su determinate attività. Ogni attività avrà 1 vincitore e 1 perdente. Voglio un sistema di classificazione degli utenti dal vivo che classifica gli utenti (dal primo all'ultimo posto) a seconda del loro record / cronologia di vincita / perdita. Il punteggio e amp; la classifica è in realtà basata sul sistema di valutazione ELO ed è molto simile al sapore dell'ELO utilizzato dalla comunità di scacchi. Lo dico solo perché il calcolo del punteggio di prestazione individuale di ciascun utente / punteggio ELO è un calcolo abbastanza complicato e non è così semplice come semplicemente sommando il numero di vittorie che hanno ottenuto finora o qualcosa di così semplice.
È anche importante ricordare che il ranking di un utente è qualcosa che deve essere memorizzato nel database e non può essere semplicemente ottenuto da: (1) l'ordinamento di tutti gli utenti in base alla valutazione del rendimento punteggio, (2) individuazione di un particolare utente nell'elenco ordinato, (3) posizionamento == posizione nell'elenco ordinato. La classifica deve essere mantenuta nel DB e aggiornata frequentemente.
Quindi questo sistema di classificazione utenti live deve:
- Attiva ogni volta che due utenti competono uno contro l'altro e l'attività determina un vincitore / perdente; e poi
- Prendi i risultati di quell'attività / competizione e applica un algoritmo matematicamente abbastanza complesso per determinare il nuovo punteggio di rendimento (punteggio complessivo) di entrambi gli utenti; e poi
- Aggiornare la loro classifica in alcune tabelle DB (ordinando, il punteggio di rendimento più alto è al primo posto, il punteggio di rendimento più basso è all'ultimo, ecc.). Questo processo è chiamato ri-ranking e riguarda tutti gli utenti (spostandoli su / giù).
I primi due elementi sopra riportati sono piuttosto semplici: li posso gestire facilmente nel livello backend / middleware. Poiché il ri-ranking potrebbe richiedere, diciamo, 30 - 60 secondi se abbiamo un numero elevato di utenti, probabilmente renderò la segnalazione dei risultati della competizione / attività in modo asincrono dal ri-ranking di tutti gli utenti. Significa che il backend riceve i risultati della competizione e li memorizza, quindi pubblica un messaggio a un broker che deve essere eseguita una ri-classifica. Un consumatore che ascolta quel broker reagisce quindi al messaggio attivando un nuovo ranking.
Tuttavia, il terzo elemento, che esegue il ri-ranking, è dove prevedo possibili problemi di prestazioni. Questo perché se la mia app ha centinaia di migliaia di utenti e ancora una volta ri-classifica prende, ad esempio, fino a 60 secondi per l'esecuzione, quindi ogni volta che due di questi utenti competono l'uno contro l'altro i ranking di tutti gli utenti saranno interessati e tutti gli utenti verrà spostato su / giù da un certo numero di classifiche. È inoltre del tutto possibile che 2 set di utenti competano uno contro l'altro nello stesso momento e attivano più re-rankings nello stesso momento).
In questo scenario sono preoccupato per la contesa di scrittura / blocco quando il DB aggiorna tutte le classifiche di tutti gli utenti, ma nel frattempo l'app non può essere in uno stato di attesa (in attesa di aggiornamento delle classifiche) e dovrà leggere le tabelle utente / classifica, anche se sono state scritte.
Quindi chiedo: quali trucchi posso utilizzare (struttura della tabella o ottimizzazioni, o forse trucchi di programmazione in una stored procedure, o forse qualcosa nel livello di dati JPA / Hibernate / JDBC, ecc.) in modo che una ri-classifica può avvenire in qualsiasi momento ( live classifiche utente) senza bloccare le tabelle utente / classifica? In altre parole, è perfettamente OK se la tabella delle classifiche riporta che l'utente 12345 ha un punteggio di 45 (45 ° posto) anche se è in corso una ri-classifica che, una volta completato, farà balzare l'utente 12345 fino al grado 44. Io non faccio altro non voglio bloccare / contendere.