caricato da Utente8325

Architettura Cockroach

annuncio pubblicitario
2.2. Architettura
Per utilizzare CockroachDB non è affatto necessario conoscere la struttura
esatta e il suo modo di procedere. Comunque dalla documentazione ufficiale,
per chi ne fosse interessato, è possible conoscere in dettaglio l’architettura di
CockroachDB.
L’architettura del Database può essere visto come una struttura a livelli, dove
ogni livello vede quello sottostante come una scatola nera da poter utilizzare,
mentre quelli sottostanti sono ignari di quelli superiori.
La struttura viene divisa in 5 livelli
1) Livello SQL: permette all’utente di potersi connettere al database ed
effettuare query Sql. In questo livello principalmente le query vengono
tradotte in operazioni KV(chiave-valore)
2) Livello Transizionale: permette il supporto alle transizioni che rispettano le
proprietà Acid, attraverso il coordinamento di operazione concorrenti
1
3) Livello Distributivo: permette di avere informazioni su come sono
strutturati i dati del cluster.
4) Livello Di Replicazione: ha il compito di gestire le repliche dei range e di
gestire come essi interagiscono attraverso il protocollo raft.
5) Livello di Memorizzazione: è il livello responsabile della scrittura e lettura
dei dati.
2.2.1 Livello SQL
Per potersi connettere a CockroachDB c’è bisogno solo di una connessione ad
un nodo e delle query SQL.
Uno sviluppatore può mandare una richiesta a qualsiasi nodo. Il nodo a cui si
manda la richiesta funziona come nodo di gateway.
Le query SQL raggiungono il proprio cluster attraverso il protocollo PostgreSql
wire Protocol. CockroachDB permette un utilizzo dello Standard Ansi SQL
attraverso le sue API SQL. Una volta ricevuta una query CockroachDb la
analizza e crea un piano di esecuzione:
• Parsing
Quando arriva una query essa viene analizzata e confrontata con un file,
YACC1 e converte ogni stringa in un AST, Abstract syntax tree.
• Pianificazione Logica
Poi la AST viene convertita in un piano di esecuzione attraverso 3 fasi
1) nella prima fase viene convertita in un piano di esecuzione ad alto livello
oltre a quello viene eseguito un’analisi semantica, che include il
controllo della validità della query.
2) il piano logico viene poi semplificato attraverso delle trasformazioni che
permettono di ottimizzare la query.
3) il piano logico viene ottimizzato ultimando un algoritmo di ricerca che
valuta i modi possibili di eseguire una query e seleziona il piano
d’esecuzione con costo minore.
• Pianificazione Fisica
2
La pianificazione fisica determina quali nodo parteciperanno
all’esecuzione
della query, sulla base della località dei range coinvolti, Infatti molto spesso
CockroachDB decide dove mandare le query in base a dove le computazioni
sono minori.
• Esecuzione
Vari componenti del piano fisico vengono inviati a uno o più nodi per
l'esecuzione. Su ciascun nodo, CockroachDB genera un processore logico per
calcolare una parte della query. I processori logici all'interno o tra i nodi
comunicano tra loro attraverso un flusso logico di dati. I risultati combinati della
query vengono rinviati al primo nodo in cui è stata ricevuta la query, per essere
inviati ulteriormente al client SQL.
DistSQL
CockroachDB essendo un database distribuito, è stato sviluppato uno
strumento di ottimizzazione Distributed SQL (DistSQL) per alcune query, che
può velocizzare notevolmente le query che coinvolgono molti range.
Nel caso in cui una query sia ottimizabile da DistSQL ciascun nodo esegue
delle operazioni sulle righe e manda soltanto i risultati, invece delle intere righe,
al nodo coordinatore, riducendo cosi il tempro per servire l’interrogazione.
2.2.2 Livello Transizionale
La proprietà principale per un database è la consistenza. Per offrire
consistenza CockroachDb il livello transizionale gestisce ogni
statement come transizione.
Per la funzione di scrittura non vengono inseriti direttamente sul
disco, ma il livello transizionale origina:
1) Lock Replicati, o meglio conosciuti come “intent di
scrittura”, per convenzione li scriveremmo come write
intent, che mantiene un valore provvisorio ed a
differenza del MVCC2 contiene anche un puntatore al record
di transizione.
3
2) Record di transizione: cioè un record che contiene
informazione sullo stato della specifica transizione. Una
transizione si può trovare nello stato di pending, staging ,
committed o aborted.
Se la transizione si trova nello stato di aborted essa dovrà essere
generata di nuovo, al contrario se sta nello stato di commited si
dovrà notificare all’utente l’esito dell’operazione.
Una volta terminata la transizione, quindi passa dallo stato di
staging a commited, il nodo coordinatore ha il compito di rendere le
write intents come valori MVCC, rimuovendo il puntatore alla record
di transizione.
Se una transizione di sola lettura incontra dei valori solo MVCC
allora la lettura può essere eseguita in modo normale. Altrimenti, se
incontra una write intent, viene generato un conflitto di transizione,
che dovrà essere risolto.
Principalmente ci cono due tipi di conflitti:
1)Write/Write quando due transizioni nello stato
pending creano degli write intents per la stessa
chiave.
2)Write/read quando una read incontra una write
intent con una timestamp minore del suo.
Per risolvere i conflitti, CockroachDB procede nel seguente
modo:
1) Se una transizione ha una priorità impostata (alto o
basso) la transizione con la priorità più bassa viene abortita
(nel caso write/write) oppure la sua timestamp viene
spostata in avanti (Read/Read).
2) se una Transizione è scaduta, passa nello
stato di aborted
4
3) considerando TxnA come una transizione e
TxnB la transizione che incontra le write intent di TxnA
TxnB viene messo in una coda di attesa e attende
che TxnA viene completata.
Poi se ci sono dei deadlock tra le transizioni, quindi nessuna delle
transizioni può proseguire per colpa delle altre, ne viene scelta una
a caso e viene abortita.
2.2.3 Distribution Layer
Per rendere i dati accessibili da qualsiasi nodo del cluster
CockroachDb conserva i dati attraverso una mappa
ordinata (Monolithic sorted map).Tale struttura permette di
identificare facilmente dove i vari dati sono localizzati
all’interno del cluster.
La mappa è composta da due elementi fondamentali:
• I dati di sistema, Incluso nei Meta ranges che
descrivono. la locazione dei dati all’interno del cluster
• I data utente, che conservano i dati delle tabelle del
cluster.
Le posizioni di tutti i range nel cluster sono archiviati in un
indice a due livelli, noto come meta range, dove il primo
livello ci indirizza al secondo e il secondo ci indirizza ai dati
del cluster. Ciascun Nodo consente di poter ritrovare dove
è posizionato il primo meta range, ovvero meta1, il quale
viene definito come il suo range descriptor. Invece i meta
5
range di secondo livello vengono definiti come Meta2 e
loro ci indirizzano ai dati del cluster.
Dopo i meta Range dei nodi, ci sono i dati KV(chiave
valore) che il cluster salva.
I meta range sono strutturati come una coppia KV.
Entrambi i meta range hanno una simile struttura.
metaX/successorKey -> LeaseholderAddress, [lista di altri nodi che
contengono i dati]
MetaX definisce a quale livello di meta range siamo 1 o 2.
Successor Key la prima chiave più grande del range , ad
esempio se il range va da [A-M)
metteremo M, di solito
viene utilizzato MaxKey per indicare la fine dello spazio
delle chiavi.
LeaseHolderAddress indirizzo del nodo che gestisce le
varie repliche.
Esempi:
Meta1 contiene l’indirizzo per i nodi che contengono le
repliche meta2
# Points to meta2 range for keys [A-M)
meta1/M -> node1:26257, node2:26257, node3:26257
# Points to meta2 range for keys [M-Z]
meta1/maxKey -> node4:26257, node5:26257, node6:26257
Meta2 contiene gli indirizzi per i nodi contenente le repliche
di ciascun range nel cluster, la prima è il leaseholder
6
meta2/M -> node1:26257, node2:26257, node3:26257
Struttura della Tabella-Dati
I dati chiave-valore, rappresentano i dati nella
tabella
utilizzando la seguente struttura:
/<table Id>/<index id>/<indexed column values> -> <non-indexed/
STORING column values>
O più nello specifico
CREATE TABLE users (id INT PRIMARY KEY, name STRING, email STRING);
INSERT INTO users (11, "Domenico", “[email protected]”);
INSERT INTO users (13, "Carlo", “[email protected]“);
/<tableid>/0/11/0 -> <empty>
/<tableid>/0/11/1 -> "Domenico"
/<tableid>/0/11/2 -> "[email protected]"
/<tableid>/0/13/0 -> <empty>
/<tableid>/0/13/1 -> "Carlo"
/<tableid>/0/13/2 -> "[email protected]"
Range Descriptors
Ciascun Range all’interno di CockroachDB contiene metadati, conosciuti come range descriptor. Il range descriptor
è strutturato nel modo seguente:
• Id del Range
• il keyspace, ovvero lo spazio delle chiavi
• Gli indirizzi delle sue repliche e nello specifico il suo
leaseholder.
7
2.2.4. Livello di replicazione
Il livello di replicazione ha il compito di dover creare le
repliche e distribuirle nei vari nodi all’interno del cluster.
Il modo in cui vengono gestite le varie repliche fanno si che
quando un nodo “cade” il sistema mantiene comunque il
suo funzionamento.
Quindi per poter garantire la disponibilità, CockroachDB
permette comunque di poter lavorare nonostante un nodo
sia andato offline. Per determinare il numero di fallimenti
tollerati basta determinare questo valore (Replication
factor3- 1)/2.).
Ovviamente anzitutto deve essere assicurata la
consistenza e per fare ciò CockroachDB utilizza un
algoritmo di “consenso” chiamato Raft per far si che le
varie repliche si concordino sul cambiamento di un range,
prima che i essi vengono salvati.
Raft organizza tutti i nodi che contengono le repliche di un
range all’interno di un gruppo.
Di queste repliche viene scelto un leader e quelle restanti
diventano suoi follower. Il leader è responsabile poi di
gestire tutti i write & read. Nel caso poi non ci dovessero
essere delle risposte da parte del Leader, tutti i follower
diventerebbero potenziali canditati a essere eletti come
nuovo leader attraverso un sistema di votazione.
8
Quando un nodo riceve una BatchRequest per il range che
esso contiene converte le operazioni KV in commandi Raft
e poi le manda al leader del Raft.
Tutti i commandi che sono stati mandati vengono inseriti
nel Log del Raft. Il log consente ad un nodo che sia andato
offline per un determinato periodo di tempo di essere
aggiornato sullo stato del range senza dover aver bisogno
di uno Snapshot[link] di una replica.
Uno dei Nodi del cluster poi viene definito come come
“LeaseHolder” ed è l’unico nodo che consente le read e
propone le richieste di write al leader raft. Il ruolo del
leaseHolder è importante nel caso delle read, infatti i write
devono prima passare per il leaseholder, quindi l’ultimo
write comittato è ancora valido e cosi quando c’è bisogno
di una read non devono attendere i tempi di attesa del
protocollo raft. Per poter poi migliorare le prestazioni
conviene che il leaseHolder e leader siano lo stesso nodo.
2.2.4. Livello di memorizzazione
Prima di introdurre il livello di memorizzazione o storage,
vorrei introdurre RocksDB attraverso il quale CockroachDB
conserva i dati.
https://github.com/facebook/rocksdb/wiki/RocksDBBasics
9
RocksDB venne creato da Facebook e sviluppato in c++,
ed è una fork della levelDB di Google. Viene considerato
come un Database NoSql embedded.
Infatti essendo un Database embedded CockroachDB lo
può utilizzare come un storage engine(come tradurre).
https://thenewstack.io/cockroachdb-unkillable-distributedsql-database/
CockroachDB contiene degli “store” attraverso i quali gli è
consentito di poter leggere e scrivere i dati dal disco. In
ogni store possono trovarsi tanti range. I dati vengono
salvati come una coppia chiave e valore utilizzando
RockDB. Ogni store può essere visto come 2 istanze di
RockDB dove:
1) viene utilizzato per conservare i dati temporanei SQL
distribuiti
2) per conservare altri dati all’interno del nodo.
Anche i Dati MVCC vengono salvati con RockDB.
Poi per poter gestire i vari store c’è una cache per tutti gli
store del nodo.
Ogni store poi come vedremo avrà delle repliche e ogni
replica sarà di un range diverso.
10
11
Scarica