Interazione con i dati utilizzando più database / server


18

Tutti i progetti che ho dovuto affrontare finora hanno richiesto solo un singolo database su un singolo server. Sono interessato a saperne di più su come i progetti che devono scalare si spostano su più database e / o server per aiutare a gestire il carico. Sono a conoscenza dell'alta scalabilità , ma sono particolarmente interessato ad alcuni esempi di codice o risorse aggiuntive in cui potrei leggere di più sull'argomento.

Per esempio:

  • Come vengono creati i join tra due tabelle su più database? (Un esempio di codice qui sarebbe utile).
  • Esistono strategie speciali per tenere traccia di quali tabelle si trovano in quale database?
  • Il codice dell'applicazione deve sapere che uno o più database sono distribuiti su più server? In caso contrario, a quale livello vengono filtrate le richieste?
  • Quando è il momento di passare oltre una configurazione di 1 database / 1 server? Quanto è comune fare questo?

È possibile rispondere meglio a questa domanda sugli amministratori del database . Nulla di veramente sbagliato, comunque, quindi cercherò solo con le mod DBA. Se è adatto lì, vorresti che fosse migrato?
Adam Lear

@AnnaLear - Immagino che dipenda dalle risposte. A questo punto, sono più interessato al lato applicativo del problema, quindi per ora, penso che potrebbe essere meglio qui.
VirtuosiMedia,

@AnnaLear ack, concorda con l'OP se desidera un codice specifico per l'app.
jcolebrand,

Risposte:


13

Ok, scomponiamo:

  • Come vengono creati i join tra due tabelle su più database? (Un esempio di codice qui sarebbe utile).

Questo è piuttosto semplice. Gli oggetti SQL hanno ovunque una convenzione di denominazione da una a quattro parti:

Servername.databasename.schemaname.tablename

Se tutte le tue tabelle si trovano sullo stesso server sullo stesso database, con lo stesso proprietario / schema, puoi semplicemente ignorare le prime tre parti e utilizzare ciò a cui sei maggiormente abituato:

Select a.*,b.* from 
tableA a inner join 
tableB b on a.col1=b.col1

Se una delle tue tabelle si trova in un database diverso ed entrambi utilizzano lo schema predefinito per i loro database, aggiungi semplicemente il database alla seconda tabella:

Select a.*,b.* from 
tableA a inner join 
databaseC..tableB b on a.col1 = b.col1

Se ti capita di trovarti in un terzo database diverso da uno di quelli che stai interrogando, usi esplicitamente entrambi i nomi di database:

Select a.*,b.* from 
databaseD..tableA a inner join 
databaseC..tableB b on a.col1 = b.col1

Se finisci per usare schemi e / o proprietari diversi, puoi aggiungerli in:

Select a.*,b.* from 
databaseD.john.tableA a inner join 
databaseC.accounting.tableB b on a.col1 = b.col1

Infine, se fai molta attenzione e hai un'ottima ragione, puoi unirti a una tabella (di solito piccola) su un altro server:

Select a.* from 
databaseD.john.TableA a inner join 
ATLANTA.databaseC.accounting.tableB b on a.col1 = b.col1
  • Quando è il momento di passare oltre una configurazione di 1 database / 1 server? Quanto è comune fare questo? Esistono strategie speciali per tenere traccia di quali tabelle si trovano in quale database?

Combinerò questi due perché vanno insieme. Stai quasi sempre bene iniziare partendo dal presupposto che un database e un server sono sufficienti fino a quando i tuoi vincoli di progettazione / business / tecnici ti costringono a usarne di più.

Quindi, per rispondere prima alla tua seconda domanda, dal momento che in genere hai un motivo per avere database separati, dovrebbe essere abbastanza ovvio dal conoscere il design del tuo sistema in cui si trova qualcosa.

Per quanto riguarda quando / perché è necessario spostarsi oltre un singolo database. Di solito è un mix di regole aziendali, politica e / o ragioni tecniche.

Ad esempio, dove lavoro, abbiamo 16 database distribuiti su 4 server. Abbiamo un MainDB, ImageDB, referencetableDB, HighvolumeTransactionDB, ReportingDB, StagingDB, ProcessingDB, ArchiveDB, FinancialDB. Per fare alcuni esempi del perché sono diversi:

  • FinancialDB, informazioni sensibili
  • Image DB, requisiti specifici di archiviazione e ripristino diversi
  • Riferimento DB, transazione bassa, lettura alta
  • ReportingDB, lettura molto elevata, deve essere ripristinato / replicato in vari altri ambienti a differenza di molti altri dati
  • StagingDB, niente di permanente, solo un tempdb potenziato su cui abbiamo più controllo
  • MainDB, si interfaccia con tutti gli altri DB ma necessita di backup differenziali quindi ... abbiamo diviso il
  • Tabelle HighVolumeTransaction, (che sono relativamente transitorie), al proprio DB in modo da mantenere una dimensione ragionevole del backup.
  • Archivio, Molti degli stessi dati da Principale e Rapporti, ma con periodi di conservazione più lunghi e query di risposta più difficili che scavano in profondità nei dati. Se questo fosse ancora combinato con Main / Reporting, il sistema si bloccherebbe.

Il codice dell'applicazione deve sapere che uno o più database sono distribuiti su più server? In caso contrario, a quale livello vengono filtrate le richieste?

In senso lato, probabilmente lo fanno. Come minimo devono sapere a quale server stanno puntando nella stringa di connessione al database. Elaborazione, reportistica, principale, ecc.

Da lì, hanno bisogno di un contesto di database per eseguire sotto. Generalmente quello sarebbe il più usato per l'applicazione, forse anche quello originale dall'un database / un server giorni dell'applicazione. È possibile che l'applicazione cambi esplicitamente il contesto del database ad ogni chiamata, ma ciò rende molto difficile regolare il database senza modificare l'app.

Il solito approccio (o almeno il MIO solito) è quello di accedere sempre attraverso uno o forse due database principali.

Quindi creare viste in altri database, se necessario, in combinazione con l'interfaccia con il database attraverso procedure memorizzate.

Quindi per illustrare:

Supponiamo che tu voglia ottenere le informazioni demografiche di un cliente, i dati di vendita e il saldo del credito e che si sviluppa su tre tabelle originariamente tutte nel MainDB.

Quindi scrivi una chiamata dalla tua app:

Select c.ClientName, c.ClientAddress, s.totalSales,f.CreditBlance from
Clients c join Sales s on c.clientid = s.clientid inner join AccountReceivable f on 
c.clientid=f.clientid where c.clientid = @clientid

Eccezionale. Tuttavia, ora ogni volta che cambiamo un nome di colonna, o rinominiamo / spostiamo una tabella, devi aggiornare il codice dell'app. Quindi invece facciamo due cose:
Creare viste Clienti, Vendite, AccountRicevibili (non useresti Seleziona * ma sto dimostrando qui)

Use MainDB
GO
Create view v_Clients as select * from Clients
Create view v_Sales as select * from Sales
Create view v_AccountReceivable as select * from AccountReceivable
Go

Quindi creeremmo anche una procedura memorizzata, spGetClientSalesAR

Create proc spGetClientSalesAR @clientID int
as
Select c.ClientName as ClientName, 
       c.ClientAddress as ClientAddress, 
       s.totalSales as TotalSales, 
       f.CreditBlance as CreditBalance 
from
v_Clients c join v_Sales s 
    on c.clientid = s.clientid 
inner join v_AccountReceivable f 
    on c.clientid=f.clientid 
where c.clientid = @clientid

E chiedi alla tua app di chiamarla così.

Ora, purché non modifichi l'interfaccia su quel proc memorizzato, posso praticamente fare tutto ciò che devo fare sul database back-end per ridimensionare o ridurre.

In estrema misura, potrei persino rendere il mio vecchio MainDB solo un mucchio di stored procedure e viste sgusciate tali che sotto quelle viste che abbiamo creato sembravano così:

Create view v_Clients as select * from ServerX.DatabaseY.dbo.Clients
Create view v_Sales as select * from ServerQ.DatabaseP.dbo.Sales
Create view v_AccountReceivable as select * from ServerJ.DatabaseK.dbo.AccountReceivable

E la tua app non saprebbe mai la differenza (supponendo tra l'altro veloci pipe e dati ben organizzati).

Ovviamente è estremo e mentirei se dicessi che tutto è stato pianificato in questo modo, ma l'uso di procedure / viste memorizzate anche se lo fai mentre il refactoring ti consentirà molta flessibilità man mano che la tua app cresce dal suo umile un database / un server inizio.


TetonSig - Grazie per la risposta. Non sono stato in grado di tornare alla domanda in tempo per assegnarti la generosità completa (ero in viaggio), ma ho creato una nuova generosità per la domanda e sarò in grado di assegnartela entro 24 ore.
VirtuosiMedia,

Wow grazie. Lo apprezzo. È stato molto divertente rispondere alla domanda.
TetonSig,

5

Il modo principale in cui ho incontrato più server di database nel mondo web (poiché la domanda è contrassegnata con PHP) sono le configurazioni in cui esisteva un database "master" (scrittura) e quindi uno o più database "slave" (leggi) replicati . Le scritture del database vengono eseguite sul database "master". Il contenuto di quel database viene replicato nei server "slave" quasi in tempo reale. Le query, in particolare i report intensivi, vengono quindi eseguite su uno dei database "slave" per spostare il carico su tali server. Tieni presente che quella particolare configurazione è la migliore per le applicazioni che hanno molte letture, ma non molta scrittura. Non è affatto l'unico modo per organizzare le cose.


3

Come vengono creati i join tra due tabelle su più database? (Un esempio di codice qui sarebbe utile).

Loro non sono. I database NoSQL non fanno affatto "join" e anche se si potesse fare un join SQL su server RDBMS, non si vorrebbe valutare il rendimento (cfr. Errori del calcolo distribuito ).

Esistono strategie speciali per tenere traccia di quali tabelle si trovano in quale database?

In un database relazionale / SQL, il partizionamento viene normalmente eseguito all'interno dei confini di un singolo server / database, utilizzando file diversi posizionati su dischi diversi. Quasi per definizione una soluzione di ridimensionamento orizzontale significa che tutti i database dispongono di tutte le tabelle e si dispone di una sorta di mirroring transazionale, replica o soluzione personalizzata di coerenza finale per assicurarsi che tutti i dati arrivino dove dovrebbero.

Se stai effettivamente suddividendo il database logicamente e non solo fisicamente, le mappature definite nel tuo DAL o ORM dichiareranno quali tabelle si trovano in quale database.

I database NoSQL sono un mix di soluzioni di partizionamento. A volte sono le "tabelle" (o più comunemente le "raccolte") a essere partizionate. Altre volte sono le "righe" (o "documenti"). In alcuni casi sono in realtà le colonne , come in un database orientato alle colonne come HBase. Dipende totalmente dalla tecnologia che stai utilizzando. L'unica cosa che tutti questi hanno in comune è che il motore stesso tiene traccia di tutto, quindi tutto ciò che devi fare è richiedere un documento o una riga.

Questo ovviamente presuppone che tu stia effettivamente utilizzando le funzionalità di sharding e non solo creando un sacco di database diversi. Se stai facendo quest'ultimo, allora sei da solo.

Il codice dell'applicazione deve sapere che uno o più database sono distribuiti su più server? In caso contrario, a quale livello vengono filtrate le richieste?

Se si tratta di database logici diversi , sì. Se sono distribuiti solo fisicamente, allora no - supponendo che il tuo database specifico supporti nativamente lo sharding o usi una soluzione di bilanciamento del carico (per database SQL). Supponendo anche che tutte le operazioni siano apolidi; se vuoi il ridimensionamento orizzontale, dovrai rinunciare all'ACID.

Quando è il momento di passare oltre una configurazione di 1 database / 1 server? Quanto è comune fare questo?

È giunto il momento in cui hai ottimizzato tutto ciò che è possibile su un unico server e non riesci ancora a ottenere prestazioni sufficienti a causa dei vincoli sul carico I / O. Se devi porre la domanda, è troppo presto.

Si noti che i problemi di prestazioni in un decente prodotto RDBMS (Oracle, SQL Server) sono più frequentemente dovuti a design scadente, indicizzazione scadente, query scadenti, conflitto di blocco e così via; questi prodotti possono ridimensionarsi verticalmente in misura ridicola. Quindi, dovresti considerare di "andare oltre una configurazione di 1 database / 1 server" quando sei assolutamente certo che i tuoi problemi di prestazioni sono dovuti a limitazioni hardware e non solo a una progettazione / implementazione scadente.

Oppure, suppongo, un altro motivo per cui alcune persone passano a database distribuiti è quando non sono disposti a pagare molto (o alcuno) denaro in commissioni di licenza e vogliono abbandonare SQL come una scelta consapevole per scambiare il basso costo per una maggiore complessità dell'applicazione. Motivo totalmente valido se si è un avvio del software ma di solito non applicabile nel settore aziendale.


+1 - Non stavo davvero prendendo in considerazione NoSQL, ma questo è comunque utile. Grazie.
VirtuosiMedia,

1

Esistono tre tipi principali di configurazioni di replica per i database:

  • Master-Slave
  • Master-master
  • Consenso

Esempio Master-Slave: master MySQL + slave MySQL, MongoDB

Esempio Master-Master: CouchDB, Cassandra, Riak

Esempio di consenso: ScalienDB

...per dirne alcuni.

Questi hanno caratteristiche diverse. Le configurazioni master-slave consentono ai nodi slave di raggiungere il master alla massima velocità mentre soddisfano molto rapidamente le richieste di lettura, mentre il server master è responsabile dell'integrità dei dati. Poiché tutte le scritture vanno al master, non esiste mai una contesa bloccata perché un singolo writer relativamente lento sta bloccando molti lettori, ma d'altra parte i server slave alla fine sono coerenti e non si ottengono le garanzie di isolamento delle transazioni che si avrebbero dalla lettura solo dal maestro. (ulteriori letture; ACID vs BASE, livelli di isolamento delle transazioni, replica del database, MVCC / isolamento: istantanea, replica transazionale)

Master-Master consente sempre le scritture, quindi avresti più autorità su ciò che è vero. Questo può essere o non essere un problema, a seconda di cosa sta facendo la tua applicazione, ma se scrivi dati contrastanti potresti ottenere più risultati la prossima volta che leggi quella chiave / riga / colonna che dovrai unire con la logica dell'applicazione e salvare di nuovo nel database. (ulteriori letture: teorema CAP, replica CouchDB, replica Riak, hashing coerente, Bitcask e StormDB, Quorum-w / MongoDB su split di rete, unisci strategie di risoluzione)

Database basati sul consenso con replica su nodi, come Scalien sarebbero sempre coerenti nelle scritture, ma a costo di scambiare più messaggi prima di ACK scrivere. Questo non è un grosso problema se si dispone di una rete Ethernet veloce e non è necessario scrivere su disco prima di ACKing, che non sarà necessario se almeno tre server si trovano su rack di server diversi con alimentatori separati (uno muore; gli altri due si assicurano di aver salvato sul disco). (ulteriori letture; PAXOS, PAXOS COMMIT, commit a due fasi con transazioni distribuite, commit a tre fasi)

Altre letture varie: (libro: "Elements of Distributed Computing", orologi vettoriali, vettori di versione, vettori di matrice, orologi logici, algoritmo da forno, orologi ad albero ad intervalli, attori e programmazione e reattori reattivi, memoria transazionale del software, transattori, AKKA, Stact, errori di calcolo distribuito, protocolli di gossip, estensioni del protocollo di gossip anti-entropia di Cassandra, tabelle hash distribuite, documenti sulla fusione dei dati in un ambiente distribuito, architettura ZooKeeper, presentazione InfoQ su "protocollo asincrono", architettura HBase, carta MapReduce, carta Amazon Dynamo che ha avviato tutte le attività NoSQL, accodamento, clustering ad alta disponibilità di rabbitmq)

Spero di aver dato qualche spunto di riflessione :). Puoi seguirmi su Twitter @henrikfeldt se vuoi anche tweet su queste cose.


1

OK, quindi ecco un altro punto di vista sulla scalabilità.

Discutiamo cosa significa che le cose sono dati, cosa significa avere un comportamento e cosa significa avere una logica applicativa.

Normalmente, quando ci si avventura nella terra delle applicazioni aziendali e simili, si sarebbe esposti all'idea di stratificazione. Naturalmente, la stratificazione è ovunque nei computer, come nello stack di rete (modello ISO), nella grafica (Photoshop) o nella SOA (i servizi possono chiamare fratelli o figli, ma mai genitori).

Tuttavia, il tipo specifico di stratificazione che è stato abusato indipendentemente da ciò che è mai stato quello della "GUI", "Business Logic Layer" e quindi "Data Access Layer". Voglio dire, sì, l'idea è buona in linea di principio, come il comunismo è buono in linea di principio, ma in realtà non lo è.

Diamo un'occhiata al perché. L'argomento che userò riguarda l'accoppiamento; punti da un livello che tocca punti in un altro livello. Ogni volta che inizi a creare un'app a più livelli aka layer nella modalità enterprise predefinita in cui le persone entrano, creano moltissimi punti di contatto tra i layer.

Nel suo nucleo, l'idea è che i livelli siano intercambiabili; ma non lo sono! Perché? A causa di tutto l'accoppiamento del sito di chiamata.

Invece, dai un'occhiata al motivo per cui la rete è disaccoppiata! Perché l'interfaccia è un flusso di byte su un singolo puntatore di file che punta a un socket aperto! Tutti i livelli nei modelli ISO sono come quello che il modello di progettazione chiamato "catena di responsabilità" è orientato agli oggetti! Ogni livello avvolge il livello sottostante, senza conoscere la semantica dei dati in quel livello sottostante.

Man mano che un pacchetto di dati si dirige verso segnali elettrici ethernet e grezzi in fondo, viene continuamente avvolto da strati che conoscono solo la propria specifica busta del messaggio, il suo specifico "batch di byte" che può inviare; e nient'altro. Non è necessario modificare i percorsi di chiamata in base al contenuto del pacchetto.

Contrastalo con n-tier in cui dovresti modificare il percorso di chiamata nei livelli dell'applicazione su una "chiamata" che attraversa i tuoi livelli nel suo percorso verso il database - ad esempio, i "clienti d'oro" sono polimorficamente un superset di "clienti normali" e quindi, poiché usiamo la "tabella per sottoclasse", dobbiamo sapere ora che i dati (entità) attraversano i livelli; sia nel cosiddetto "livello di logica aziendale" che nel livello di dati che sta effettivamente effettuando il salvataggio.

Non è né scalabile né ottimale dal punto di vista informatico.

Perché non è scalabile? Perché l'architettura è accoppiata e quindi sei ancora all'interno dello stesso vecchio DB che stavi cercando di scalare su molti nodi! Ma poiché per questo hai bisogno di ACID, quello e una terza entità (oggetto dati) devi averli in un unico database che esegue le transazioni!

Giustamente, quindi con quello sfogo fuori dai piedi; quali altri modi ci sono?

Bene, c'è l'acronimo odiato chiamato "SOA", ovvero l'architettura orientata ai servizi. Ovviamente, i Tomas Erls del mondo , ti farebbero implementare tutti i tuoi livelli ma con XML e SOAP.

Per tutte le ragioni di cui sopra, questa è la strada sbagliata, perché ti assoceresti a quei proxy XML proprio come se ti accoppiassi ai livelli dell'applicazione come spiegato sopra.

Invece, usa la messaggistica e lascia che qualunque cosa implementi funzionalità per loro, ascoltale. La tua superficie di servizio diventa quindi un elenco di messaggi che puoi inviare e non hai accoppiato le tue operazioni alla facciata del servizio; e non hai nemmeno bisogno di sapere quale applicazione o endpoint implementano queste operazioni, perché tutto ciò che stai facendo è pubblicare un messaggio che alcuni altri meccanismi di routing indirizzeranno al consumatore corretto!

Poiché le facciate dei servizi sono state disaccoppiate dalle operazioni effettive che si desidera eseguire, è ora possibile aggiungere più servizi; in effetti, è così che Netflix lo fa. Dai un'occhiata a queste presentazioni: http://www.slideshare.net/adrianco/global-netflix-platform . http://www.slideshare.net/adrianco/global-netflix-platform . Sono bravi!


0

Esiste un nuovo database SQL (ACID) in beta che si ritiene abbia proprietà di ridimensionamento elastico. È in corso un programma beta gratuito e ti suggerisco di dare un'occhiata, si chiama NuoDB.

Apparentemente supera facilmente MySQL anche su una singola macchina thread, ma si adatta felicemente a oltre 70 istanze in determinati benchmark.


Un singolo thread? Come è quindi un punto di riferimento rilevante?
Henrik,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.