Gestire la latenza dei dati quando si lavora con un database di sola lettura?

3

La nostra app Web API è C # / MS-SQL e i nostri DBA ci chiedono di utilizzare due database, uno scrivibile e uno di sola lettura. Il database per le scritture verrà replicato nella copia di sola lettura. Questa domanda può essere applicata anche ad altre lingue.

Il motivo di ciò (dagli amministratori di database) era che le prestazioni non venivano influenzate se / quando le tabelle sono bloccate durante una scrittura.

Stiamo provando a determinare il modo migliore per utilizzare i metodi Show / Get in Readonly, assicurandoci tuttavia se ci fosse solo un'operazione di scrittura, abbiamo dati nuovi. Un suggerimento era avere una connessione ReadOnlyToWritableData, ma allora perché avere il database di Readonly.

Quali sono alcune soluzioni già in uso? Ho cercato in giro e non ho trovato nulla di definitivo.

AGGIORNAMENTO: mi è stato comunicato che il nostro patter DB è un "Always On Availability Group". link Potrei aver bisogno di fare ulteriori ricerche.

    
posta M Kenyon II 17.05.2017 - 20:27
fonte

4 risposte

2

Questa è una configurazione del gruppo di disponibilità in cui l'applicazione scrive su un'istanza del database e le letture da un'altra istanza. È una condivisione di database, che non è una pratica rara ed è qualcosa che si vedrà per i database con un numero estremamente elevato di operazioni di lettura e scrittura. Ecco come mantenere la scalabilità per applicazioni Web su larga scala (e-commerce).

Un esempio di questo problema potrebbe essere visto con i carrelli. Un utente aggiunge un articolo al proprio carrello, viene salvato nel database, quindi inoltrato alla pagina successiva che legge il carrello e mostra gli articoli. Se c'è un ritardo con la sincronizzazione, questo potrebbe essere un problema. Mentre il ritardo (se l'ambiente è impostato correttamente) può essere solo un paio di millisecondi, se c'è un problema nel database secondario, la lettura potrebbe estrarre i dati prima che i nuovi dati fossero effettivamente sincronizzati.

Ci sono solo due possibilità:

1 - Usa l'intento dell'applicazione sul listener del database e sulla stringa di connessione. Ho sentito, tuttavia, che il driver SQL per .net non ha implementato in modo affidabile questa funzione (Microsoft non funziona bene con Microsoft). Non so se questo è ancora vero però. L'intenzione dell'applicazione passerà automaticamente da rw a ro. Tuttavia, anche l'implementazione di questo non risolverà il possibile problema.

2 - Usa una procedura memorizzata per i tempi in cui sai che ti serviranno immediatamente i dati. Nell'esempio del carrello, una procedura per aggiungere un articolo potrebbe quindi restituire un recordset con tutti gli articoli attualmente nel carrello.

Ciò che l'OP sta chiedendo è questo: c'è un modo per farlo nel codice? Qualcuno ha fatto questo in codice (non la risposta alla stored procedure)?

    
risposta data 17.05.2017 - 23:53
fonte
1

Invece di connettersi a un'istanza di database specifica (server), l'applicazione si connetterà al cluster HA (High Availability). Il cluster ti indirizzerà automaticamente all'istanza disponibile (primaria o secondaria).

Quindi la tua applicazione dovrebbe essere trasparente alla latenza. Nota, se il primario va giù, c'è un po 'di latenza per passare al secondario, ma ancora una volta l'applicazione va contro il cluster non è un'istanza specifica, quindi il cluster gestirà il re-direct per il tuo automaticamente.

    
risposta data 17.05.2017 - 21:47
fonte
1

Mi sembra che, se sei preoccupato per le prestazioni, gli oggetti che leggono dal database dovrebbero anche mantenere una cache in modo che più letture possano portare a un solo viaggio nel database. Se lo costruisci, tutto ciò che devi fare è codificare gli oggetti che scrivono nel database per aggiornare anche la cache. In questo modo la prossima operazione di lettura colpirà la cache e otterrà i dati più recenti.

    
risposta data 17.05.2017 - 23:48
fonte
0

I database sono una risorsa condivisa. La maggior parte dei programmatori li considera come proprietà privata. Il mio lavoro di DBA per molti anni è stato quello di "indirizzare il traffico" in questa intersezione trafficata di autostrade dei dati. La risposta di John Wu è sulla strada giusta.

È necessario un livello di codice tra l'applicazione e il database. Quel livello memorizza i dati in entrambe le direzioni. Per l'applicazione, sembra il proprio datastore privato. Al database, sembra uno o un numero molto piccolo di letture e scritture.

Idealmente ... il database otterrebbe 1 SELECT all'inizio della transazione e restituirà tutti i dati da tutte le tabelle di cui l'applicazione ha bisogno. In questo modo, il motore di database molto costoso e incredibilmente ottimizzato può utilizzare la sua conoscenza intima e in continua evoluzione dei dati per recuperare quel sottogruppo infinitesimale di record nel modo più veloce ed efficiente possibile.

Ad esempio, se una tabella ha solo poche migliaia di righe e hai la memoria, salva l'intera tabella nella RAM e fai scansioni complete della tabella. Ignora gli indici poiché i doppi recuperi rallenterebbero le cose.

Se tutte le colonne necessarie sono negli indici, quindi ignorare le tabelle di dati e leggere solo gli indici. Poiché gli indici vengono spesso modificati dagli amministratori di database come parte del processo di ottimizzazione continua, non c'è modo per l'applicazione di trarne vantaggio.

Nessun programmatore, ovunque, indipendentemente dall'abilità, ha la minima possibilità di fare tutto questo meglio perché non possiamo e non possiamo analizzare i dati, in questo momento, come può farlo il motore del database.

Quindi, i dati selezionati verranno memorizzati nella cache e costituiscono l'intero corpo di dati che l'applicazione può manipolare in questa transazione. Se nessun server applicazioni è in uso per eseguire la memorizzazione nella cache, può, e spesso viene fatto utilizzando le stored procedure del database.

Potrebbe anche essere fatto dall'applicazione ... ma in questo modo "ci sono i draghi". Il programmatore dell'applicazione semplicemente non ha accesso a tutte le informazioni necessarie per scrivere un livello "middleware" efficiente ed affidabile. Potrebbe funzionare per database di piccole dimensioni, ma non verrà ridimensionato. Diventerà presto il collo di bottiglia n. 1 nel sistema. Non farlo.

Una volta completate tutte le modifiche ai dati memorizzati nella cache, questo livello intermedio scrive nuovamente i nuovi dati nel database nel modo più efficiente possibile per ottimizzare le prestazioni. È allettante dire che dovrebbe essere 1 in scrittura, ma raramente è saggio ... o addirittura possibile.

L'approccio utilizzato è molto variabile. Dipende dal numero di tabelle coinvolte, dalle peculiarità e dalle funzionalità del motore di database, dal carico corrente sul sistema, dalla volumetrica e dalle regole aziendali per quanto devono essere aggiornati i dati.

Riguardo a quest'ultimo, riconosce che non tutto deve accadere proprio ora. Il modo più efficiente per apportare modifiche al database è con i "batch jobs" durante la notte ... i programmi di lunga durata che eseguono operazioni di inserimento, aggiornamento e cancellazione di massa di tutti i cambiamenti da quel giorno.

(Introduzione a Smoke and Mirrors - Quella 1 query fatta all'inizio? Sotto le copertine ci sarebbero spesso in realtà 2 query: una al database principale e una a una serie di tabelle di transazioni che contengono modifiche recenti che saranno applicato al database principale con un processo a lungo termine più tardi quando non ci sono migliaia di utenti che ci sbattono sopra.)

    
risposta data 27.05.2017 - 15:29
fonte

Leggi altre domande sui tag