Cassandra
Transcript
Cassandra
Cassandra Cassandra Introduzione Nasce inizialmente all'interno di Facebook per gestire le ricerche fra i messaggi. Attualmente open-source, è uno dei database NoSQL più diffusi. E' incluso tra i database NOSQL Column family perché ha un datamodel ispirato a BigTable, tuttavia presenta delle differenze sostanziali rispetto ad HBase. Infatti, Cassandra : ● oltre alla column family ha anche le super column family; ● ha un'infrastruttura ispirata a Amazon Dynamo (key-value store); ● è decentralizzato, ovvero ogni nodo del cluster ha lo stesso ruolo; ● si può scegliere il livello di consistenza dei dati (teorema CAP); ● ha un proprio linguaggio di interrogazione stile SQL: il CQL. Cassandra Data Model Il datamodel di Cassandra è abbastanza simile a quello HBase per il modello base di column family, che illustriamo nuovamente qua sotto per comodità: Column family Una colonna avrà quindi una key (row + column family), un valore ed un timestamp. Cassandra Data Model A differenza di HBase, però, Cassandra ha anche le Super Column Family. Queste permettono di aggiungere una ulteriore dimensione alla mappa e rappresentano un gruppo di colonne correlate fra di loro come illustrato quando abbiamo introdotto i DB NoSQL. Attualmente però le SuperColumn in Cassandra sono sempre meno usate in quanto non molto performanti e l'impossibilità di indicizzare le subcolumn all'interno di una super column. Per superare questo problema sono state introdotte le composite column che vedremo più avanti quando parleremo di CQL. Cassandra Data Model Nel datamodel di Cassandra, individuiamo 4 entità ben definite che sono: Nome Definizione breve Analogia RDBMS Keyspace Una collezione di Column Family. Database Column Family Un insieme di row. Tabella Row Un insieme ordinato di Column. Riga Column Una coppia chiave/valore con timestamp associato. Colonna Il keyspace è un namespace che definisce come i dati vengono replicati nei nodi. Tipicamente in un cluster esiste un solo keyspace per applicazione. Vedremo maggiori dettagli su queste entità quando più avanti descriveremo il CQL. Cassandra Architettura Cassandra ha un'architettura completamente distribuita e decentralizzata. Con decentralizzata si intende che non esiste un “single point of failure”. Tutti i nodi in un cluster Cassandra hanno gli stessi compiti e funzionalità (“server simmetry”), ad esempio non esiste un nodo specifico che si occupa di coordinare le attività del cluster. La decentralizzazione ha due vantaggi: è più semplice da usare rispetto ad una architettura master/slave (la comunicazione è peer-to-peer) e permette di evitare disservizi (indisponibilità) in maniera più semplice. Cassandra Architettura Il modello di distribuzione peer-to-peer permette di aggiungere e/o rimuovere nodi senza problemi (con strategia di replica adeguata). Quando un nodo viene aggiunto al cluster per prima cosa individua la topologia dello stesso e riceve i dati per i quali sarà responsabile, successivamente potrà accettare le richieste dai client. In questo modo si ottiene una elastic scalability con performance che scalano in maniera lineare ed i dati sono sempre distribuiti in modo bilanciato. Cassandra Architettura I cluster in Cassandra sono anche detti ring per l'architettura ad anello che li caratterizza. L'anello rappresenta l'andamento ciclico dello spazio dei token, il token viene generato in base alla chiave di riga e serve ad individuare in quale nodo è memorizzato il dato. Ad ogni nodo è assegnata una posizione nell'anello basata sui token che deve gestire. Ciascun nodo è responsabile per tutti i token fra il suo token iniziale ed il token iniziale del nodo più vicino nell'anello. Cassandra Architettura Per mappare le chiavi di riga nello spazio dei token viene usato un partitioner. I partitioner di base sono due: un random partitioner ed un order preserving partitioner. Nel primo caso il token viene generato attraverso una funzione hash MD5 e le chiavi vengono distribuite nel cluster non mantenendo l'ordine delle chiavi (è il partitioner di default). Questo permette di bilanciare il carico fra i nodi. Se invece si opta su un order preserving partitioner in questo caso viene mantenuto l'ordine fra le chiavi anche nei token. Ad esempio se le chiavi sono A, B e C allora si deve avere che token(A) < token(B) < token(C). Questo può portare ad avere uno sbilanciamento di informazioni fra i nodi, ma consente di ottimizzare gli accessi nel caso in cui si debbano recuperare i dati ordinati. Cassandra Architettura Un'altra caratteristica importante di Cassandra è la Failure Tolerance. Questa può essere impostata indicando il replica factor nel keystore. Il replica factor indica il numero dei nodi nel quale deve essere mantenuto il dato. Si noti che i nodi sono successivi secondo la topologia dell'anello. Cassandra Architettura Le strategie di replication esistenti sono due: ● SimpleStrategy: si ha un solo datacenter, i dati sono memorizzati in nodi successivi sull'anello; ● NetworkTopologyStrategy: si hanno più datacenter, i dati sono trasmessi a tutti i datacenter, in ognuno di essi i dati sono memorizzati in nodi successivi in base al partitioner selezionato su quel datacenter. Si noti che i datacenter sono fra di loro “indipendenti” nel senso che possono avere parametri ed impostazioni differenti (ad esempio possono avere un replica factor diverso). Cassandra Architettura Oltre al replica factor, l'altro fattore importante per la memorizzazione dei dati in Cassandra è la consistency. Questa è modificabile a run-time sia in lettura che scrittura. Le strategie possibili sono: ● ANY (Solo in scrittura) ● ONE ● TWO ● THREE ● QUORUM ● LOCAL_QUORUM (quorum all'interno dello stesso datacenter) ● EACH_QUORUM (quorum in tutti i datacenter) ● ALL Cassandra Architettura Consistency ONE. Scrittura Il nodo coordinatore (quello a cui si è collegato il client) scrive in tutti i nodi dove risiede la replica del dato; aspetta l'ack del primo nodo per rispondere al client; gli ack degli altri nodi arrivano in maniera asincrona. Lettura Il nodo coordinatore legge il dato dal nodo più veloce che contiene la replica. Cassandra Architettura Consistency QUORUM (maggioranza assoluta fra le repliche) Scrittura Il nodo coordinatore (quello a cui si è collegato il client) scrive in tutti i nodi dove risiede la replica del dato; aspetta l'ack dal quorum dei nodi per rispondere al client; gli ack degli altri nodi arrivano in maniera asincrona. Lettura Il nodo coordinatore legge il dato dal nodo più veloce e chiede un digest alle repliche; appena ha avuto risposta dal quorum dei nodi restituisce il dato più aggiornato; aggiorna il dato memorizzato nelle repliche. Cassandra Architettura La consistency può essere diversa fra lettura e scrittura. Vediamo meglio con un esempio di cosa succede in diverse combinazioni. RF = 3, write ONE, read ONE Write ONE: V1 Node 1 V1 Read ONE: V0 Replication in progress Node 2 Node 3 V0 V0 Cassandra Architettura RF = 3, write ONE, read Quorum Write ONE: V1 Node 1 V1 Read Quorum: V0 Replication in progress Node 2 Node 3 V0 V0 Cassandra Architettura RF = 3, write ONE, read ALL Write ONE: V1 Node 1 V1 Read ALL: V1 Replication in progress Node 2 Node 3 V0 V0 Cassandra Architettura RF = 3, write Quorum, read ONE Write Quorum: V1 Read ONE: V0 Node 1 Node 2 V1 V1 Replication in progress Node 3 V0 Cassandra Architettura RF = 3, write Quorum, read Quorum Write Quorum: V1 Read Quorum: V1 Node 1 Node 2 V1 V1 Replication in progress Node 3 V0 Cassandra Architettura RF = 3, write Quorum, read ALL Write Quorum: V1 Read ALL: V1 Node 1 Node 2 V1 V1 Replication in progress Node 3 V0 Cassandra CQL A differenza di molti altri database NoSQL Cassandra dispone di un proprio linguaggio di query, in versione beta sin dalla versione 0.8.0. Il Cassandra Query Language, CQL3, è arrivato alla sua terza versione ed è diventato l'API di interrogazione dei dati predefinita e la precedente API, la CLI, è ormai deprecata e verrà rimossa a partire dalla versione 3.x di Cassandra. L'assonanza nel nome vuole richiamare le forti similitudini con SQL. Il CQL può essere utilizzato via API o attraverso una shell cqlsh. Cassandra CQL – Creare un DB Semplificando, un DB è una collezione di tabelle; l'equivalente in Cassandra prende il nome di keyspace, che inoltre definisce anche una strategia di replica dei dati: il keyspace è un namespace che definisce come i dati vengono replicati nei nodi Esistono due strategie a seconda che si utilizzi un solo cluster (SimpleStrategy) o più cluster (NetworkTopologyStrategy). La sintassi per creare un keyspace è la seguente CREATE KEYSPACE [keyspace_name] WITH REPLICATION = {'class' : 'Strategy', [datacenter_name] : n }; Dove keyspace_name è il nome che si vuole dare al keyspace ed n indica il numero di repliche di dati che deve essere presente nel cluster. Cassandra CQL – Creare un DB Nel caso di un solo datacenter non è necessario assegnargli un nome e la stringa associata CREATE KEYSPACE keyspace_name WITH REPLICATION = {'class' : 'SimpleStrategy', 'replication_factor' : n }; Nel caso di più datacenter è necessario specificare il nome del datacenter ed il replica_factor per ciascuno di essi: CREATE KEYSPACE keyspace_name WITH REPLICATION = 'NetworkTopologyStrategy', 'dataprim' : 3 , 'datas' : 2 }; {'class' : Cassandra CQL – Lavorare con un Keyspace E' possibile selezionare un keyspace per lavorare solo con le tabelle di un particolare DB: USE keyspace_name; oppure modificarlo, ad esempio per cambiare il replication factor od aggiungere datacenter, attraverso il comando ALTER KEYSPACE che segue la sintassi di CREATE KEYSPACE. Inoltre è possibile ottenre l'elenco di tutti i keyspace con il comando DESCRIBE KEYSPACES; o alternativamente interrogando la tabella system (che contiene i metadati ) : SELECT * FROM system.schema_keyspaces; Cassandra CQL – Creare una Tabella Lo sviluppo di Cassandra sta procedendo a ritmi serrati ed è in corso una grande rivoluzione concettuale per trasformarlo in uno strumento di facile utilizzo per chi si occupa di analisi di dati ma non è interessati ai dettagli implementativi. Per questo è in corso una forte trasformazione del CQL per renderlo sempre più simile al SQL e farlo diventare l'unico sistema di interrogazione dati. Ad esempio “di fatto” è stato deprecato l'uso delle Super Column Families perché rendevano complicata ed inefficiente la costruzione di indici secondari ed altre ottimizzazioni, e si sta mascherando l'uso delle Column Families con l'analogia Column Family == SQL Table Cassandra CQL – Creare una Tabella La sintassi per la creazione di tabelle (ovvero le column family) è la seguente: CREATE TABLE keyspace_name.table_name ( column_definition, column_definition, ...) WITH property AND property .. Il keyspace_name può essere omesso se si deve creare una tabella nel keyspace attualmente in uso; e column_definition può seguire uno dei seguenti formati : ● column name cql_type ● column name cql_type PRIMARY KEY ● PRIMARY KEY (partition key) ● column name collection_type Cassandra CQL – Tipi di Dati I cql_type e collection_type supportati sono: Cassandra CQL – Collection Types La collection_type sono di tre tipi : ● LIST <cql_type> ● SET <cql_type> ● MAP <cql_type, cql_type> Le collection non possono essere annidate, ovvero non può esistere una lista di liste. Sono utili per gestire associazioni multiple (es. più indirizzi email, i tag di una foto) e consentono delle semplici denormalizzazioni sui dati; ma la dimensione del loro contenuto è limitata a 64K. Quindi non sono adatte per dati che possono crescere indefinitamente come ad esempio tutti i post di un utente o gli eventi registrati da un sensore. In questi casi è necessario utilizzare le compound primary key che vedremo a breve. Cassandra CQL – Primary Key La primary key (ovvero la row key, quella con cui saranno indicizzati i dati di una tabella) può essere specificata in due modi : ● column name cql_type PRIMARY KEY ● PRIMARY KEY (partition key) I dati di tutte le colonne saranno memorizzati garantendo la loro prossimità su disco; che schematicamente si può rappresentare nel seguente modo: Table (column family) Primary key (row key) Column name 1 Column data Column name 2 Column data Column name 3 Column data Column name 4 Column data Cassandra CQL – Compound Primary Key Se si specificano più primary key separate da “,” si parla di compound primary key. ● PRIMARY KEY (partition key, clustering column, ...) In questo caso la prima chiave sarà la partition key e le altre sono chiamate clustering column. Su disco le colonne che hanno la stessa partition key sono fisicamente memorizzate nello stesso nodo e le clustering column sono utilizzate per clusterizzare i dati ovvero i dati vengono memorizzati in modo ordinato rispetto alle clustering column. Table (column family) Partition key Cluster Col Val1 : Column name 1 Column data Cluster Col Val1 : Column name 2 Column data Cluster Col Val1 : Column name 3 Column data Cluster Col Val2 : Column name 1 Column data Cassandra CQL – Compound Primary Key Un esempio più dettagliato è il seguente CREATE TABLE Posts (email_id text, post_id timeuuid, name text, body text, posted_at timestamp, PRIMARY KEY (email_id,post_id)) Se inserisco dei dati questi verranno memorizzati così: Posts Partition key: 20150218_132000 : name [email protected] 20150218_132000 : body Nicola Bla bla bla …. 20150218_132000 : posted_at 2015-02-18 13:20:00 20150216_112012 : name Maurizio 20150216_112012 : body Bla2 bla2 bla2 …. 20150216_112012 : posted_at 2015-02-16 11:20:12 Cassandra CQL – Composite Partitition Key Il vincolo di dover memorizzare su uno steso nodi tutti i dati appartenenti ad una stessa partition key può essere limitante per la distribuzione dei dati. Per superare questo limite si possono usare anche le composite partition key che consentono di suddividere la row key in due parti: PRIMARY KEY ((partition key1, partition key2), clustering column, …) in questo modo solo le colonne con gli stessi valori di (key1, key2) dovranno trovarsi su uno stesso nodo, mentre tutti le altre potranno essere distribuite su nodi diversi . Cassandra CQL – Inserimento Dati Per inserire dei dati all'interno delle tabelle dobbiamo utilizzare il comando INSERT INSERT INTO keyspace_name.table_name ( column_name, column_name...) VALUES ( value, value ... ) USING option AND option I valori devono rispettare la tipologia specificata per la colonna, se si tratta di dati testuali devono essere racchiusi fra apici. Una operazione di INSERT inserisce una o più colonne in una tabella di Cassandra in maniera atomica ed isolata (nel senso delle proprietà ACID). Cassandra CQL – Inserimento Dati Per inserire dati nelle collection i valori devono essere specificati all'interno di parentesi [] nel caso di liste, {} di set e mappe. LIST SET MAP → → → [value, value …] {value, value …} {value_key : value, value_key : value …} E' bene precisare che in CQL: ● le list servono per memorizzare valori univoci e ordinati; i valori possono essere inseriti in qualunque ordine e verranno restituiti secondo il loro ordinamento naturale (es. alfabetico); ● i set consentono di inserire duplicati ed i valori verranno restituiti secondo l'ordine di inserimento; Cassandra CQL – Timestamp e TTL In Cassandra ad ogni dato memorizzato è associato un timestamp (in microsecondi) che indica l'istante di creazione, se non specificato viene utilizzato quello effettivo di inserimento della colonna. Inoltre è possibile associare un time to leave (TTL) in secondi che indica dopo tempo il dato potrà essere automaticamente cancellato (utile ad esempio per la creazione di tabelle temporanee o viste sui dati) INSERT INTO Hollywood.NerdMovies (user_uuid, fan) VALUES (cfd66ccc-d857-4e90-b1e5-df98a3d40cd6, 'johndoe') USING TTL 86400; Cassandra CQL – Aggiornamento dei Dati Per aggiornare dei dati si può usare il comando UPDATE. UPDATE keyspace_name.table_name USING option AND option SET assignment, assignment, … WHERE row_specification Le option che si possono specificare sono timestamp e time to leave. Nel caso di list e set è possibile anche aggiungere elementi, mentre nel caso di map questa collection può essere solamente sostituita con una nuova. UPDATE table_name SET set_name = set_name + {'value'} UPDATE table_name SET list_name = list_name + ['value'] Cassandra CQL – Ricerca e selezione dei Dati Per interrogare i dati si utilizza il comando SELECT. SELECT selector FROM keyspace_name.table_name WHERE relation AND relation ... ORDER BY ( clustering_column ( ASC | DESC )...) LIMIT n ALLOW FILTERING Il selector può essere la combinazione di questi elementi column name Uno o più nomi di colonne da visualizzare separati da virgola COUNT (*) Conteggio degli elementi restituiti WRITETIME (column_name) Timestamp associato alla colonna TTL (column_name) Time to leave della colonna Cassandra CQL – Batch Operations Un'altra funzionalità interessante di Cassandra sono le Batch operations. Queste permettono di raggruppare operazioni di Data Manipulation Language (INSERT, UPDATE, DELETE) ed eseguirle in un solo passo, in maniera simile alle transazioni RDBMS. Infatti, le operazioni batch sono atomiche, quindi o vengono eseguite tutte con successo oppure i dati non vengono manipolati. Inoltre, tutte le operazioni all'interno di un batch avranno lo stesso timestamp (ma possono avere TTL diverso). Cassandra CQL == SQL ? Quindi col CQL posso sostituire SQL? Attualmente no! Il CQL è in rapida evoluzione e si avvicinando sempre più al SQL, ma è ancora molto distante in quanto: ● È privo di funzionalità di aggregazione (es. GROUP BY) ● Il WHERE non è libero, ma posso usare solo certi operatori di filtraggio e solo su colonne particolari (es. >=, <= possono essere usati solo sulle clustering column) ● Sulla partition key posso usare solo la condizione di uguaglianza ● Non esiste DISTINCT o costrutti simili ● Etc...