Strategie di architettura per un complesso sistema di punteggio della competizione

2

Descrizione della competizione:

  • Ci sono circa 10 squadre in competizione l'una contro l'altra per un periodo di 6 settimane.
  • Il punteggio totale di ogni squadra (su un totale di 1000 punti disponibili) si basa sul totale dei suoi punteggi in circa 25.000 diversi elementi di punteggio.
  • La maggior parte degli elementi di punteggio vale una piccola frazione di punto e ci saranno circa 10 X 25.000 = 250.000 punti di dati di input grezzi totali.
  • I punti per alcuni elementi di punteggio vengono assegnati a intervalli regolari frequenti durante la competizione. I punti per gli altri elementi di punteggio vengono assegnati a intervalli di tempo irregolari o in un solo istante.
  • Esistono circa 20 diversi tipi di elementi di punteggio.
  • Ciascuno dei 20 tipi di elementi di punteggio ha un diverso insieme di input, un diverso algoritmo per calcolare il punteggio guadagnato dagli input grezzi e un diverso numero di punti totali disponibili. Gli algoritmi più semplici richiedono un input e un semplice calcolo. Gli algoritmi più complessi consistono in centinaia o migliaia di input grezzi e un calcolo più complicato.
  • Alcuni tipi di input non elaborati vengono generati automaticamente. Altri tipi di input non elaborati vengono inseriti manualmente. Tutti gli input grezzi sono soggetti a possibili aggiustamenti retroattivi manuali da parte dei funzionari della concorrenza.

Requisiti principali:

  • L'interfaccia utente del sistema di punteggio per i concorrenti e gli altri follower della competizione mostrerà i punteggi totali attuali e storici della squadra, le classifiche della squadra, i punteggi delle squadre per elemento di punteggio, i dati grezzi di input (a diversi livelli di aggregazione, ad esempio giornalieri, settimanali, ecc.), e altre metriche.
  • Ci saranno grafici, tabelle e altri widget per la visualizzazione di input e punteggi storici dei dati grezzi.
  • Ci sarà una dashboard quasi in tempo reale che mostrerà i punteggi attuali e gli input dei dati grezzi.
  • I punteggi aggregati dovrebbero essere aggiornati / aggiornati ogni volta che arrivano nuovi input di dati grezzi o se vengono modificati gli input di dati grezzi esistenti.
  • Ci sarà una "UI scorekeeper" per l'immissione manuale di nuovi input, la regolazione manuale degli input esistenti e la regolazione manuale dei punteggi calcolati.

Le decisioni:

  • I calcoli del punteggio devono essere eseguiti sul livello del database (T-SQL / SQL Server, nel mio caso) o sul livello dell'applicazione (C # / ASP.NET MVC, nel mio caso)?
  • Quali sono alcuni approcci consigliati per calcolare i punteggi complessivi della squadra aggiornati ogni volta che arrivano nuovi input grezzi? Calcolando il punteggio totale di ciascuno dei team da zero ogni volta che arriva un nuovo input probabilmente rallenterà il sistema. Ho considerato una sorta di approccio "diff", ma questo approccio potrebbe porre problemi per le query ad-hoc e alcuni aggettivi. Sto provando a disegnare alcune analogie sportive, ma è difficile perché la maggior parte dei giochi consiste di non più di 20 o 30 elementi di punteggio per partita (sto pensando ad una partita di baseball ad alto punteggio, calcio e calcio hanno meno eventi di punteggio per partita) . Forse un'analogia del bilancio finanziario ha più senso perché i calc finanziari "bottom line" possono essere calcolati da 250.000 o più transazioni.
  • Dovrei fare un uso intensivo del caching per questa applicazione?
  • Esistono approcci ovvi o studi di casi simili che potrei ignorare?
posta MikeyWazz 26.09.2013 - 06:01
fonte

4 risposte

1

I miei pensieri, basati sul non conoscere i tuoi attuali algoritmi:

  • Esegui il punteggio nel codice dell'applicazione, a meno che non sia molto semplice
  • Mantieni informazioni in esecuzione che ti aiuteranno a generare punteggi velocemente
    • Ad esempio, se hai bisogno di una media, puoi mantenere la somma e contare e calcolare la media secondo necessità. (Nota, per cose semplici come la media, puoi semplicemente usare il Database)
    • Inoltre, dai un'occhiata alle medie mobili ( link ) che possono consentirti di memorizzare pochissimi dati sul passato e mostra ancora informazioni storicamente utili
  • Non mi preoccuperei troppo della memorizzazione nella cache dei dati, piuttosto penserei di mantenere le informazioni in esecuzione e di poter calcolare rapidamente il risultato. Tuttavia, se disponi di molti visualizzatori per gli stessi valori, puoi avviare la memorizzazione nella cache.

Se il numero totale di punti dati è 250k, puoi fare un bel po 'di matematica su questo in pochissimo tempo.

Non sono sicuro di cosa pensi di fare per l'architettura delle app Web, ma probabilmente scriverei l'applicazione che descrivi come app web a singola pagina con il minor numero di punti API del server per ottenere i dati come JSON. Quindi farei il grafico / display tutto sul browser in JavaScript usando qualcosa come D3, Raphael o un'altra libreria di grafici.

    
risposta data 26.09.2013 - 08:06
fonte
1

Ho scritto qualcosa di molto simile a segnare eventi sportivi in diretta per diversi sport, dove è ciò che ha funzionato per me.

  • Ho trovato che il livello dell'applicazione era il posto migliore per eseguire calcoli di punteggio per due motivi: 1: eravamo in grado di esprimere la logica in c # rispetto a SQL. 2: Stavamo usando NHibernate quindi sembrava più naturale non farlo nel database e lavorare con il nostro modello di dominio. Dove abbiamo avuto bisogno di esporre la logica ad applicazioni esterne abbiamo usato un livello di servizio WCF.

  • Il modello del processo di punteggio effettivo di ogni partita abbiamo usato l'idea di una partita, consistente in due squadre che giocano l'una contro l'altra, come una timeline con ogni elemento di punteggio e qualsiasi altra pietra miliare correlata, ad es. metà tempo, fallo, essendo un elemento sulla timeline.

ogni elemento di punteggio, che nell'implementazione consisteva in un oggetto comando, aggiornava quindi lo stato di corrispondenza, ad es. il punteggio, fase di gioco, ma conterrebbe anche la logica / i dati necessari per ripristinare la modifica dello stato, se necessario. a volte questo consisteva nel dover salvare l'intero stato della partita ogni volta che veniva inserito qualcosa di nuovo sulla linea del tempo.

ogni voce di linea temporale o raccolta di voci è stata tracciata con un Guid che rappresentava una transazione nel nostro sistema. La classe di corrispondenza aveva quindi una logica che consentiva di ripristinare l'ultima transazione in qualsiasi punto precedente della corrispondenza.

Ogni importante entità su cui abbiamo bisogno di rapporti nel nostro sistema, ad es. giocatore, squadra, campionato, stagione, avrebbe una propria classe di report che verrebbe aggiornata da un trigger attivato ogni volta che è stata effettuata una voce della linea temporale, ciò che è stato aggiornato dipenderà dalla voce della timeline ma il risultato è stato il report memorizzato nella cache oggetti che hanno sempre ricevuto le informazioni più recenti.

Non abbiamo trovato alcuna soluzione valida per gestire le query ad-hoc

  • Cache state / timeline delle partite in corso, memorizza anche i tuoi dati del rapporto e invia gli aggiornamenti ad esso anziché aggiornarli periodicamente.

    • Se hai la tua logica di punteggio su un server e il tuo software client di punteggio deve collegarsi in remoto da una struttura sportiva, l'accodamento dei messaggi è tuo amico, perderai la connessione ad un certo punto e l'accodamento affidabile dei messaggi assicurerà che ogni messaggio , nel mio caso ogni voce della linea temporale passerà e sarà in ordine.
risposta data 26.09.2013 - 15:02
fonte
0

Suggerisco caldamente di lasciare i calcoli al livello del database. Il database è molto più adatto alla gestione dei calcoli e alla manipolazione di set di dati di grandi dimensioni, oltre a memorizzarli in un modo che è più efficiente da recuperare. Per non parlare, se lo fai a livello di applicazione ti servirà un modo per gestire contese e fallimenti, se due utenti iniziano i calcoli in una volta o se si verifica un errore.

Suggerirei di archiviare i dati grezzi nelle tabelle e creare un livello di visualizzazione per aggregare i dati. Sono più familiare con le visualizzazioni materializzate di Oracle, ma SQL Server offre un costrutto simile chiamato Visualizzazioni indicizzate. Queste viste si comportano come tabelle e sono perfette per funzioni aggregate come i calcoli di cui si sta parlando. E queste viste indicizzate possono essere aggiornate automaticamente quando i dati vengono modificati nelle tabelle sottostanti.

    
risposta data 26.09.2013 - 18:04
fonte
0

Ecco le mie opinioni su questo sistema.

  1. Il numero di elementi di punteggio sembra essere molto grande e io tendo a vedere che sono indipendenti l'uno dall'altro (in caso contrario, è necessario pensare a pre-processare i grandi input raw in modo che diventino indipendenti). Questo è il segnale di chiamata per trasformare il tuo sistema in un sistema distribuito. Avrai più peer ciascuno con il proprio database SQL in esecuzione e ognuno con un livello di servizio in esecuzione sul database SQL.
  2. Ci sono due scelte per il sistema distribuito. Uno gerarchico (ovvero esiste un nodo specializzato principale per coordinare e più nodi di sub-coordinamento) o uno peer-to-peer. Ti suggerirei di utilizzare il modello peer-to-peer poiché hanno diversi vantaggi:

    • Questo è molto robusto e in questo modello hai essenzialmente un sistema di backup integrato se permetti alcuni dati ridondanti su ciascun nodo peer
    • Se è possibile rendere indipendenti gli input non elaborati o se sono intrinsecamente indipendenti, non è necessario raggruppare l'input raw dipendente in un nodo di coordinamento come nel modello gerarchico
  3. Per salvarti da molteplici mal di testa causati da modifiche simultanee dei dati, assicurati che lo schema dei dati inserisca ulteriori dati di data e ora anziché eliminare / modificare i dati precedenti in una modifica. Avere un sistema di timestamp per ogni pezzo in ingresso pure. Posso pensare di avere 3 tipi di tempo al momento: [1] tempo logico, [2] tempo scaduto, [3] tempo di scrittura. Quando arriva una modifica, si aggiungono nuovi dati con un nuovo tempo di scrittura mentre si mantengono le date logiche uguali. In breve, non eliminare i dati precedenti. Il timestamp è anche una struttura 'diff' parziale per te dato che se una parte dei dati di input non cambia, allora il nodo responsabile di quella parte ha solo bisogno di aggiornare il timestamp

  4. Calcola il punteggio del componente che ogni peer è responsabile ogni volta che arrivano nuovi dati. In questo modo, non dovrai fare molti calcoli quando vuoi ottenere il punteggio (attuale o storico). Se inserisci anche il timestamp per questi punteggi, ottieni anche un tempo di lettura del punteggio storico più veloce. Questa è in teoria una cache per te. Inoltre, fare questo al livello di servizio / applicazione, non farlo nel livello del database SQL. Con il timestamp, non avrai problemi con le query ad hoc.

  5. Devi stare attento con la gestione degli errori e correggere le cose quando qualcosa va storto su qualche nodo quando fai una scrittura. Ciò non sarà banale, ma dovrai fare un po 'di lavoro pesante per te da SQL e dalla coda dei messaggi.

Il protocollo per i dati di timestamping e i punteggi parziali dovranno essere definiti in modo più specifico, ma non vedo nulla che sia fondamentalmente sbagliato in questa architettura. Se vedi, fammi sapere. Mille grazie!

    
risposta data 31.07.2014 - 07:22
fonte

Leggi altre domande sui tag