2012-10-17 6 views
6

Il nostro sistema ha un modello strutturato (circa 30 diverse entità con diversi tipi di relazioni) interamente conservato in memoria (circa 10 Gb) per motivi di prestazioni. Su questo modello che dobbiamo fare 3 tipi di funzionamento:Si dovrebbe usare Disruptor (LMAX) con un grande modello in memoria e CQRS?

  1. aggiornamento uno o pochi soggetti
  2. query per un particolare di dati (questo di solito richiede di leggere migliaia di entità)
  3. ottenere dati statistici (quanta memoria viene utilizzata, quante query per genere ecc.)

Attualmente l'architettura è piuttosto standard, con un pool di thread per servlet che utilizzano un modello condiviso. All'interno del modello ci sono molte raccolte simultanee, ma ci sono ancora molte attese perché alcune entità sono "più calde" e la maggior parte delle discussioni vuole leggerle/scriverle. Si noti inoltre che le query di solito sono molto più efficienti in termini di CPU e tempo rispetto alle scritture.

Sto studiando la possibilità di passare a un'architettura Disruptor mantenendo il modello in un singolo thread, spostando tutto il possibile (controlli di validità, auditing, ecc.) Dal modello in consumatori separati.

La prima domanda è: ha senso?

Secondo domanda: idealmente le richieste di scrittura dovrebbero avere la precedenza su quelle di lettura. Qual è il modo migliore per avere una priorità nel disgregatore? Stavo pensando ai buffer a 2 anelli e poi provo a leggere da quello più in alto uno più spesso rispetto a quello a bassa priorità.

Per chiarire la domanda è più architettonico rispetto al codice effettivo di LMAX Disruptor.

aggiornamento con maggiori dettagli

dei dati è un dominio complesso, con molte entità (> 100k) di molti tipi diversi (~ 20) collegate tra di loro in una struttura ad albero con molte collezioni differenti.

Le query di solito comportano l'attraversamento di migliaia di entità per trovare i dati corretti. Gli aggiornamenti sono frequenti ma abbastanza limitati come 10 entità alla volta, quindi nell'intero i dati non cambiano molto (come il 20% all'ora).

Ho eseguito alcuni test preliminari e sembra che i vantaggi in termini di velocità di interrogare il modello in parallelo superino i ritardi occasionali dei blocchi di scrittura.

+0

Ciao Uberto - Puoi aggiungere qualche dettaglio. Che tipo di domande stai facendo? E l'aggiornamento delle entità sta avvenendo sulle stesse poche entità o su molte entità diverse? Le entità sono collegate tra loro o per lo più indipendenti e in che modo sono correlate? – jasonk

+0

Riguardo alla domanda 2: precisioni delle letture rispetto alle scritture, LMAX è naturalmente adatto per il sourcing di eventi, che dice che si mantengono gli eventi non quei modelli, i modelli attuali (o più ottimizzati che sono super veloci sulle operazioni di lettura) saranno ancora lì non cambi mai mai ciò che è accaduto quando, se hai un'operazione di lettura prima della scrittura, dovresti elaborarla per ottenerla, in modo da poter riprodurre lo stesso stato se riesegui la catena di eventi ... Quindi in In questo caso, questa priorità è errata qui, lo fai quando due thread scrivono in una raccolta, forse ... – vach

risposta

2

"idealmente le richieste di scrittura dovrebbero avere la precedenza rispetto a quelle di lettura".

Perché? I blocchi più veloci come C# ReaderWriterLockSlim fanno il contrario. Una scrittura deve bloccare tutte le letture per evitare letture parziali. Quindi tali blocchi consentono molte letture simultanee sperando che le cose diventino "abbastanza" e poi scrivano .. (La scrittura viene eseguita al suo numero nella coda ma molto probabilmente molte letture che venivano dopo che sono state elaborate prima che si blocchino) ..

Dare la priorità scrive è un buon modo per uccidere la concorrenza ..

Is eventuale concorrenza/CQRS un'opzione?

+0

supponendo che il flusso della query di lettura sia più o meno costante, non vi è alcun guadagno nel ritardare la scrittura. L'aggiornamento del modello prima delle letture ha un vantaggio commerciale. – Uberto

+0

Sì, il motivo per cui le serrature lo fanno è che sperano che il burst di lettura decida quale spesso accade, il flusso continuo verso una singola entità è piuttosto raro (potrebbe essere che si abbia un lock da tavolo che non è una buona idea per alte prestazioni), se il flusso è maggiore di quello che si ha a questo punto e si dovrebbe guardare ad altre cose come la lettura di copie/spinlock, ecc. Stiamo parlando di mili a 1/10 di secondo che importa molto al business, la maggior parte degli affari vive anche con problemi di scrittura parziale quando un'entità da un livello ORM viene modificata e servita allo stesso tempo. – user1496062

+0

Il modo più semplice per farlo è probabilmente avere una coda di comando in memoria e ogni 1-10 ms li inserisce nel buffer circolare con tutte le scritture prima. I disgregatori non sono molti a molti (beh, non ho mai visto nessuno usarli in quel modo quindi id vuole vedere benchmark) ... o leggono da più buffer ad anello, ogni consumatore (dominio) legge da un buffer ad anello ... anche se è possibile avere più domini che leggono da un singolo buffer – user1496062

2

LMAX può essere appropriato ..

La gente LMAX prima implementato tradizionale, poi implementato attori (con code) e ha trovato gli attori hanno trascorso la maggior parte del tempo nelle code. Poi sono passati all'architettura a thread singolo ... Ora che il disruptor non è la chiave dell'architettura, la chiave è un BL a thread singolo. Con 1 writer (thread singolo) e piccoli oggetti si ottiene un high cache hit e nessuna contesa. Per fare ciò devono spostare tutti i codici a lungo termine dal livello Business (che include IO). Ora per fare ciò usano che hanno usato il disruptor, fondamentalmente è solo un ring buffer con un singolo writer, come è stato usato per un po 'nel codice del driver di dispositivo, ma con una scala di messaggi enorme.

Prima ho un disaccordo con questo, LMAX è un sistema di attori .. Dove hai 1 attore per tutti i BL (e gli intralci connettono altri attori) ..Potrebbero aver migliorato il sistema degli attori in modo significativo invece di passare a 1 attore per BL, ovvero

  1. Non ci sono molti servizi/attori, prova ad avere componenti comunemente usati in un servizio. (Questo viene su di volta in volta in SOA/sistemi distribuiti anche)
  2. Quando la comunicazione tra gli attori usano punto a punto le code non molti a 1. (come tutti gli autobus servizi!)
  3. Quando si dispone di un punto all'altro code assicurati che la coda sia un puntatore a un'area di memoria separata. Con 2 e 3 ora è possibile utilizzare code senza blocco e le code/thread hanno solo 1 scrittore (e si possono anche usare non 256 temporanee ma le scritture di bit YMM nella coda). Tuttavia il sistema ora ha più thread (e se hai fatto correttamente 1 una quantità relativamente piccola di messaggi tra gli attori). Le code sono simili ai disturbatori e possono elaborare in batch molte voci e possono utilizzare uno stile buffer ring.

Con questi attori si dispone di un sistema più modulare (e quindi principale tabella) (e il sistema potrebbe lanciare più attori per elaborare le code - nota 1 scrittore!)

re tuo caso penso 20 Il% delle modifiche in un'ora è enorme ... Le query sono sempre attive negli oggetti di memoria? Avete in memoria hash tabelle/indici? Puoi usare le raccolte di sola lettura? È importante che i tuoi dati siano vecchi, ad es. Ebay utilizza un aggiornamento di 1 ora sulla sua collezione di articoli, quindi la raccolta degli articoli è statica. Con una raccolta statica e slip di articoli statici, hanno un indice statico e puoi cercare e trovare gli oggetti velocemente e tutto in memoria. Ogni ora viene ricostruito e una volta completato (potrebbero essere necessari alcuni minuti per ricostruire), il sistema passa ai nuovi dati. Nota che gli oggetti non sono statici.

nel tuo caso con un enorme dominio del singolo thread può ottenere un successo di cache lowish ..che è diverso da LMAX che hanno un dominio più piccolo per ogni messaggio di passare sopra ..

Un agente sistema basato può essere la migliore scommessa è perché un gruppo di entità può essere raggruppato e quindi avere un grande riscontro nella cache. Ma ho bisogno di saperne di più. ad esempio spostare controlli di validità, auditing, registrazione ecc. è probabilmente un buon piano. Meno codice = oggetti più piccoli = hit cache più alto e oggetti LMAX piccoli.

Spero che questo scarico rapido aiuti, ma è difficile solo da un'occhiata.

Problemi correlati