Elaborato finale in Basi di Dati
NoSQL Database: Cassandra
Anno Accademico 2015/2016
Candidato:
Stefano Cutillo
matr. N46001738
Indice
Introduzione
2
1 NoSQL Database
1.1 Differenze con i RDBMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Teorema CAP e proprietà BASE . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
4
5
2 Classificazione dei NoSQL
2.1 Column Family . . . . .
2.2 Key/Value . . . . . . . .
2.3 Document stores . . . .
2.4 Graph stores . . . . . .
DB
. . .
. . .
. . .
. . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
8
8
9
10
10
3 Apache Cassandra
3.1 Architettura . . . . . . . . . . .
3.2 Data Model . . . . . . . . . . .
3.2.1 Column e Supercolumn
3.2.2 KeySpace . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
12
13
17
18
20
4 Applicazioni Cassandra
4.1 KeySpace . . . . . . .
4.1.1 Replication . .
4.1.2 Durable writes
4.2 Column Families . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
21
21
22
22
24
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Conclusioni
28
Bibliografia
29
1
Introduzione
Per anni il modello relazionale dei Database, introdotto da Edgar F. Codd nel 1970, strutturato
intorno al concetto matematico di relazione, è stato dominante nell’ambito dei sistemi di gestione di basi di dati.
Negli anni 2000, la nascita del Web 2.0 provoca una diminuzione dei costi dei sistemi di memorizzazione e una diffusione dell’ e-Commerce e dei social media con una conseguente crescita
esponenziale dei dati prodotti.
A questo punto la scalabilità dei sistemi RDBMS distribuiti non è più sufficiente per stare al
passo con la velocità desiderata di produzione e consumo dei dati. Nascono quindi i database
NOSQL per rispondere alle esigenze che con i RDBMS non potevano affrontare, ovvero la necessità di una alta scalabilità orizzontale invece che una scalabilità verticale (limitata) tipica dei
RDBMS.
Il termine NOSQL fu introdotto da Carlo Strozzi nel 1998 per indicare il suo database relazionale open-source che non aveva una interfaccia SQL standard. Il termine attualmente indica
tutti quei database che sono: non relazionali, distribuiti, open-source (spesso) e scalabili orizzontalmente. All’opposto di quanto si potrebbe pensare, il movimento NOSQL non è contrario
all’utilizzo di database relazionali. Il termine NOSQL infatti è acronimo di Not Only SQL, per
indicare che esistono diversi casi d’uso per i quali il modello relazionale non è più efficiente, ma
tanti altri per i quali tale modello è ancora la soluzione migliore. Nonostante il termine sia stato
introdotto nel 1998, solo nel 2009 i database NoSql hanno acquisito un’importanza rilevante. I
precursori di questo movimento sono Google con il progetto BigTable e Amazon che ha implementato DynamoDB.
Nel primo capitolo verranno descritti in breve i database non relazionali, evidenziandone le
principali differenze con gli RDBMS. Inoltre sarà enunciato il Teorema CAP, elencandone poi
proprietà e caratteristiche.
Nel secondo capitolo verranno distinti i diversi tipi di database non relazionale analizzandone le
principali peculiarità.
Nel terzo capitolo ci concentreremo in particolare su Apache Cassandra, descrivendone la storia,
le principali caratteristiche, l’architettura e la struttura del modello dei dati.
Infine nel quarto capitolo verranno riportati degli esempi di applicazioni pratiche con Cassandra,
in particolare utilizzando la shell cqlsh, che verrà poi approfondita, utile per effettuare query in
CQL, un linquaggio fornito da Cassandra.
2
Capitolo 1
NoSQL Database
La crescità esponenziale nell’utilizzo di internet, il boom globale dei social media, come Facebook, e lo sviluppo crescente di applicazioni mobile e servizi di cloud computing, hanno portato
alla necessità di trovare nuovi strumenti e tecnologie per gestire una quantità di dati in continua
crescita, indicati con il nome di BigData.
Per questo motivo i tradizionali database relazionali non furono più considerati l’unico modello
da prendere in considerazione, ma si è iniziato a studiare metodi differenti in modo da ottenere
un modello dei dati più flessibile che sia in grado di fornire alte prestazioni per le elaborazioni
su grandi volumi di dati.
Le costanti ricerche hanno portato allo sviluppo di un nuovo tipo di database non relazionali
(NRDBMS), i cosidetti NoSQL.
Si parla di Big Data quando si fa riferimento a dati che superano le capacità di elaborazione dei sistemi di database convenzionali. Si tratta di dati che sono troppo estesi, che si evolvono
troppo velocemente o che non soddisfano le strutture del database progettato. Le aziende si
trovano ad affrontare una serie di difficoltà legate alla creazione, manipolazione e organizzazione
di Big Data. Infatti si era iniziato a lavorare con dataset talmente grandi da richiedere strumenti
non convenzionali per estrapolare, gestire e processare informazioni entro un tempo ragionevole.
I Big Data risultano essere un problema specifico dell’analisi aziendale, poiché gli strumenti e le
procedure standard non sono progettati per cercare e analizzare dataset di tali dimensioni.
Non esiste una dimensione di riferimento, ma questa cambia sempre, poiché le macchine sono
sempre più veloci e i dataset sono sempre più grandi. Secondo uno studio del 2001, l’analista Doug Laney aveva definito il modello di crescita come tridimensionale (modello delle 3V),
affermando che con il passare del tempo aumentano volume, velocità e varietà dei dati.
• Volume: rappresenta la dimensione effettiva del dataset; l’ampio volume di dati che è
possibile raccogliere oggi potrebbe apparentemente rappresentare un problema. In realtà
quello del volume dei Big Data è un falso problema, in quanto cloud e virtualizzazione
aiutano nella gestione del grosso volume di dati disponibili, semplificando i processi di
raccolta, immagazzinamento e accesso ai dati. Con i big data la mole dei dati è dell’ordine
degli Zettabyte, ovvero miliardi di Terabyte. Quindi si richiede una potenza di calcolo
parallelo e massivo con strumenti dedicati eseguiti su decine, centinaia o anche migliaia di
server. Tale volume rappresenta la sfida principale alle convenzionali strutture tecnologiche,
richiedendo l’utilizzo di una tecnologia scalabile e distribuita per far fronte alle richieste.
• Velocità: si riferisce alla velocità di generazione dei dati; Il flusso di dati scorre a una
velocità senza precedenti e deve essere gestito in modo tempestivo. Tag RFID, sensori e
contatori intelligenti guidano in tempo reale la necessità di gestione di questo flusso. La
sfida di molte organizzazioni è proprio quella di reagire abbastanza velocemente da riuscire
3
a governare la velocità dei dati, tendendo ad effettuare analisi dei dati in tempo reale o
quasi.
• Varietà: riferita alle varie tipologie di dati, che sono di natura diversa, e quindi non
adattabili alle classiche strutture relazionali. Quindi non soltanto i dati strutturati, come i
database, ma anche non strutturati, come immagini, email, dati GPS, transizioni bancarie
o informazioni prese dai social network. Gestire, acquisire e governare un’ampia varietà di
dati sono temi con i quali le organizzazioni si devono confrontare.
La definizione di Big Data è stata poi arricchita con i concetti supplementari di Veridicità e
Valore, la prima riferita alla correttezza e affidabilità dei dati, la seconda riferita alla capacità
dei dati reperiti di portare un reale beneficio nel processo di analisi.
1.1
Differenze con i RDBMS
Le caratteristiche in cui si evidenziano le maggiori differenze tra i due tipi di database sono:
Struttura e tipi di dato memorizzati:
I sistemi RDBMS richiedono un processo di normalizzazione sui dati che consente di evidenziare le caratteristiche essenziali dei dati e le relazioni che tra essi intercorrono e che
determina la necessità di utilizzare. Il risultato è un modello astratto dei dati, detto schema, che definisce univocamente la struttura e il tipo dei dati e li separa in tabelle. Inoltre
lo schema si presenta rigido, in quanto possono essere memorizzati solo i dati conformi allo
schema e per aggiungere un campo o una relazione è necessario bloccare l’intero database
fino al completamento della modifica. I sistemi NoSQL non nascono con l’obiettivo di rinunciare alle relazioni tra i dati ma, al contrario, dal desiderio di avere la massima libertà
possibile di modificare ed alterare nel tempo sia la struttura dei dati che le relazioni che
tra essi intercorrono. Per questo motivo sono caratterizzati da:
1. Leggerezza computazionale : i database NoSQL non prevedono operazioni di aggregazione sui dati, in quanto tutte le informazioni sono già raccolte in un unico
documento associato all’oggetto da trattare. Dato che un elemento contiene tutte
le informazioni necessarie non serve usare i dispendiosi (in termini di performance)
JOIN come invece avviene per i database relazionali.
Negli ambienti SQL la complessità di queste operazioni, e quindi il peso computazionale, cresce con l’ingigantirsi della base di dati, del numero di tabelle e delle informazioni
da trattare. Nel NoSQL, Le informazioni quindi non troveranno più posto in righe
elencate in tabelle, ma in oggetti completamente diversi e non necessariamente strutturati e quindi non ci saranni più limiti di dimensioni in questo senso. Lo svantaggio
che provoca tutta questa flessibilità è la duplicazione delle informazioni, anche se in
realtà, i costi sempre meno proibitivi dei sistemi di storage rendono questo svantaggio
poco importante.
2. Assenza di schema : i database NoSQL sono privi di schema in quanto il documento
JSON contiene tutti i campi necessari, senza necessità di definizione. In questo modo, possiamo arricchire le nostre applicazioni di nuovi dati e informazioni, definibili
liberamente all’interno dei documenti JSON senza rischi per l’integrità dei dati. I database non relazionali, a differenza di quelli SQL, si rivelano quindi adatti a inglobare
velocemente nuovi tipi di dati e a conservare dati semistrutturati o non strutturati.
Per questo motivo eliminano lo schema rigido (schemaless) in modo da consentire di
aggiungere nuovi dati, anche molto dissimili dai precedenti, e nuove relazioni senza
la necessità di modificare la struttura del database e senza bloccarne l’accesso.
4
La semplicità di questi database, però, porta anche alla mancanza dei controlli fondamentali sull’integrità dei dati. Il compito ricade quindi totalmente sull’applicativo che dialoga
col database che ovviamente dovrebbe essere testato in modo molto approfondito prima
di essere messo in produzione.
Esecuzione di query:
Indipendentemente dalla loro licenze, tutti i database relazionali implementano lo standard
SQL in una certa misura, quindi possono essere interrogati utilizzando lo Structured Query
Language (SQL). Ogni database NoSQL, d’altra parte, implementa un modo tutto suo per
operare con i dati che gestisce.
La mancanza di uno standard universale (come può essere l’SQL) può rappresentare però
uno svantaggio, in quanto ogni database ha le proprie API e il suo metodo di storing e
di accesso ai dati. Di conseguenza se lo sviluppo del database sul quale abbiamo basato il
nostro applicativo venisse interrotto, il passaggio ad un altro database non sarebbe una cosa
immediata, ma richiederebbe alcuni cambi più o meno radicali da apportare all’applicativo.
Scalabilità Orizzontale:
Entrambe le soluzioni sono facili da scalare verticalmente (aumentando cioè le risorse di
sistema). Tuttavia, essendo applicazioni più moderne (e più semplici), le soluzioni NoSQL
offrono di solito mezzi grazie ai quali è molto più facile scalare orizzontalmente (cioè con la
creazione di un cluster di più macchine). Partizionare orrizontalmente significa partizionare
le enormi tabelle su database e server differenti. Per quanto rigurada i database relazionali questo però introduce degli svantaggi in quanto per consultare le tabelle c’è bisogno
necessariamente del JOIN. Inoltre occorre prestare attenzione durante il partizionamento
per organizzare e coordinare le query in modo adeguato per far si che non si sovrappongano tra loro nelle varie entità. Le funzioni disponibili saranno quindi limitate. L’assenza
di aggregazione dei dati e di uno schema definito a priori offre l’opportunità di scalare
orizzontalmente i database NoSQL senza difficoltà e senza rischi operativi e soprattutto
evitando le operazioni di giunzione (join).
Affidabilità:
Quando si tratta dell’affidabilità dei dati e della sicurezza che le transazioni effettuate
siano garantite, i database SQL sono ancora la soluzione migliore.
Supporto:
I DBMS relazionali hanno una storia lunga decenni. Sono estremamente popolari e sono
facili da trovare sia con supporto gratuito che a pagamento. Se si verificasse un problema,
sarà quindi molto più facile da risolvere rispetto ai recenti database NoSQL.
Le caratteristiche ed i punti di forza dei sistemi RDBMS vengono spesso sintetizzate con l’acronimo ACID, ossia Atomicità, Consistenza, Isolamento e Durabilità. Nei sistemi NoSql queste
caratteristiche sono sostituite da proprietà meno stringeti, che sono alla base del teorema CAP
e che sono rappresentate dall’acronimo BASE.
1.2
Teorema CAP e proprietà BASE
All’inizio degli anni 2000 a Berkeley, l’univerità della California, lo scienziato informatico Eric
Brewer formulò una congettura matematica al simposio Principles of Distributed Computing(PODC).
Nel 2002 Seth Gilbert e Nancy Lynch del MIT, hanno pubblicato una dimostrazione di tale congettura, definendola quindi un teorema.
Il Teorema CAP, anche conosciuto quindi come teorema di Brewer, afferma che non è possibile fornire simultaneamente totale coerenza dei dati (Consistency), continua disponibilità
5
(Availability) e tolleranza alle partizioni (Partition tolerance), quando si progetta un sistema
distribuito.
• Consistency : Un sistema è definito completamente coerente quando è in grado di garantire che una volta memorizzato un nuovo stato nel sistema, questo è utilizzato in ogni
operazione successiva fino alla successiva modifica dello stesso. Pertanto, tutte le richieste
dello stato del sistema, nell’arco di tempo che intercorre tra uno stato e quello successivo,
forniscono il medesimo risultato.
• Availability : Un sistema è detto continuamente disponibile quando è sempre in grado di soddisfare le varie richieste/erogare i propri servizi. la strategia standard utilizzata
per ottenere la continua disponibilità consiste nel ricorrere ad un’opportuna ridondanza. Ciò, oltre a richiedere opportuni meccanismi per garantire la consistenza, aumenta le
problematiche relative alla tolleranza alle partizioni.
• Partition tolerance : Gilbert e Lynch hanno definito la tolleranza alle partizioni come
la proprietà di un sistema di continuare a funzionare correttamente anche in presenza di
una serie di fallimenti dell’infrastruttura fino a che l’interno network fallisca.
Teorema CAP
Quindi è necessario stabilire, di volta in volta in funzione ai requisiti, quale soluzione di compromesso accettare tra le seguenti coppie possibili: CA, AP e CP.
1. CA: elevata coerenza/alta disponibilità. Si tratta del compromesso tipicamente offerto dai
RDBMS. I dati sono mantenuti in modo coerente in tutti i nodi del cluster, a patto che
ovviamente tali nodi siano disponibili. È sempre possibile leggere e/o scrivere su qualsiasi
nodo ed essere sicuri che il nuovo dato sia propagato a tutti i nodi del cluster. Non vi è
6
quindi la possibilità che alcuni nodi abbiano delle versioni dei dati non aggiornate. Tuttavia,
la totale coerenza può incidere sulle performance (latenza) e sulla scalabilità.
2. CP: elevata coerenza/tolleranza alle partizioni. Questo compromesso è quello preferito da
soluzioni quali MongoDB, HBase, BigTable, Terrastore, Redis e altri. I dati sono mantenuti in maniera coerente in tutti i nodi del cluster, e viene garantita la tolleranza partizione
per evitare che dati possano desincronizzarsi. Tuttavia si possono avere problemi di disponibilità quando un nodo diventa non raggiugibile. Quasi tutte le soluzioni prevedono una
configurazione in cui un nodo agisce come master e gli altri come slave.
3. AP: continua disponibilità/tolleranza alle partizioni. Questo compromesso è stato prescelto da soluzioni quali Apache Cassandra, CouchDB, DynamoDB e Riak. I nodi restano
on-line anche nelle situazioni in cui non possono comunicare tra loro. È poi compito del
processo di risincronizzazione dei dati risolvere eventuali conflitti. Chiaramente non è possibile avere garanzia che tutti i nodi abbiano gli stessi dati con gli stessi valori durante la
partizione e la relativa risoluzione. Soluzioni AP tengono a presentare migliori prestazioni
in termini di latency e a scalare in modo più lineare.
Il Teorema CAP sostanzialmente dimostra che è impossibile garantire le proprietà ACID1 in
un sistema distribuito e scalabile orizzontalmente. Quindi affinche si voglia costruire un sistema
distribuito, è d’obbligo adottare una versione "rilassata" delle proprietà ACID che favoriscono la
replicazione dei dati per aumentare la scalabilità orizzontale e la disponibilità del dato a scapito
della consistenza (in senso ACID). Queste proprietà sono sintetizzate dall’acronimo : BASE =
Basically Available, Soft state, Eventual consistency.
1. Basically Available . L’approccio NoSQL predilige la disponibilità del dato anche in
presenza di molteplici errori. Viene ottenuto utilizzando un approccio altamente distribuito
replicando i dati su un gran numero di sistemi di memorizzazione. Quindi ci sarà una
risposta a qualsiasi richiesta, anche se la risposta potrebbe ancora essere un fallimento o
una impossibilità a rispondere.
2. Soft state . Si abbandona la consistenza nel senso delle proprietà ACID. Lo stato del
sistema può quindi variare nel tempo, anche in periodi di tempo senza input. La consistenza
dei dati diventa un problema da risolvere da parte dello sviluppatore e non deve essere
gestita dal database.
3. Eventual consistency . Significa che in un qualche istante futuro i dati arriveranno in
uno stato consistente (nel senso ACID). Non ci sono garanzie su quando ed in quanto
tempo questo avverrà. Questo perchè quando nuovi dati vengono aggiunti al sistema essi
si propagano gradualmente, in maniera asincrona e un nodo alla volta, fino a far diventare
consistente l’intero sistema.
1
Atomicità: la transazione è indivisibile nella sua esecuzione e non sono ammesse esecuzioni parziali;
Consistenza: Durante la transazione il sistema non deve violare eventuali vincoli di integrità, quindi non devono
verificarsi contraddizioni (inconsistenza) tra i dati archiviati nel DB;
Isolamento: ogni transazione deve essere eseguita in modo isolato e indipendente dalle altre transazioni, l’eventuale
fallimento di una transazione non deve interferire con le altre transazioni in esecuzione;
Durabilità: una volta modificata una transazione, i cambiamenti apportati non dovranno essere più persi.
7
Capitolo 2
Classificazione dei NoSQL DB
Proprio perché i database NOSQL sono incentrati sui dati, ne esistono diverse tipologie ed esistono diverse varianti all’interno della stessa tipologia. I criteri fondamentali in base ai quali
possiamo suddividere i diversi Database NoSQL sono scalabilità, prestazioni(in termini di latency) e consistenza.
Le quattro tipologie principali di database NOSQL sono:
• Coloumnfamily : i dati sono organizzati in righe e colonne, ma le righe possono avere
quante colonne si vogliono e non c’è bisogno di definire le colonne come prima cosa.
• Document store : I dati, a differenza dei normali database relazionali, non vengono
immagazzinati in tabelle con dei campi fissi, ma vengono messi in un documento che può
contenere illimitati campi di illimitata lunghezza.
• Graph : i dati vengono immagazzinati sotto forma di strutture a grafi,per favorirne
l’accesso da applicativi orientati agli oggetti.
• Key/Value : i dati vengono immagazzinati in un elemento che contiene una chiave assieme
ai dati veri e propri.
2.1
Column Family
I database Column family si ispirano all’articolo di Google nel quale descriveva il suo database
Bigtable, definendolo una sparsa, distribuita e persistente mappa ordinata multi-dimensionale.
Altri esempi di DB column family sono Hbase, Hypertable e Cassandra. Column family store
indica che il database è organizzato per colonne invece che per righe come nei RDBMS. Contrariamente ai normali database relazionali nei quali, durante la lettura dei dati si potrebbero
leggere dati non necessari, nei column family store vengono letti soltanto i dati di interesse,
rendendoli più veloci e scalabili. Tuttavia la scrittura di una tupla richiede accessi multipli a
differenza dei database row-stores caratterizzati dalla semplicità di aggiungere o modificare un
record.
Inoltre, per evitare la presenza di dati null, ogni riga può avere un numero differente di colonne,
che possono essere aggiunte o eliminate all’occorrenza, cosa che di fatto rende questo database
una matrice multidimensionale sparsa. I column family si dividono in: Standard column family
e Super column family.
• Standard column family : La row key (la chiave più "esterna") identifica l’aggregato,
che a sua volta contiene una o più famiglie di colonne dove possono essere presenti diversi
valori associati ad una diversa column key.
8
Standard Column family
• Super column family : E’ un’estensione dello standard column family che aggiunge un
ulteriore livello di indicizzazione, detta appunto super column, fra la row key e l’insieme
delle colonne. Questa chiave viene utilizzata per raggruppare attributi correlati fra di loro,
appartenenti allo stesso aggregato. L’estensione presenta diversi vantaggi, in quanto rende
i dati più ordinati ed utilizzabili dalle applicazioni e la scalabilità orizzontale (sharding)
più efficiente.
Super Column family
I Column family database apportano numerosi benefici:
1. I valori in una singola colonna sono memorizzati in maniera contigua e conservati in specifici
column datafile.
2. I dati all’interno di ciascun column datafile sono dello stesso tipo, questo li rende ideali
per la compressione.
3. La memorizzazione per colonna permette di migliorare le performance delle query in quanto
permette l’accesso diretto alle colonne.
2.2
Key/Value
I Key-Value stores puntano sugli aspetti di Availability e Partition Tolerance (AP) del teorema
CAP e prendono origine dall’articolo di Amazon dove descriveva il suo database Dynamo, sviluppato nel 2007. Lo scopo di Amazon era quello di avere un database altamente scalabile dove
9
si potesse accedere ai dati in modo affidabile il più velocemente possibile in quanto i database
relazionali non scalavano alla velocità necessaria.
Altri eseempi di database sono Voldemort (Linkedin), MemcacheDB, Riak, e BerkleyDB.
I database Key-Value stores sono la più semplice tipologia di database NOSQL. I dati vengono
memorizzati in coppie chiave/valore, infatti ogni chiave identifica un blob binario "oscuro" che
può contenere qualsiasi tipologia di dato (stringa di testo, documento, immagine, video).
Il vantaggio è che si ha una struttura altamente scalabile, grazie all’assenza di legami tra le varie
coppie key/value, che potranno essere distribuite su server differenti.
Questo tipo di database può essere visto come una hash table, che consente quindi le seguenti
operazioni: si può aggiungere una coppia key/value, recuperare un blob data la sua chiave, cancellare una chiave per rimuovere un elemento o modificare il valore associato ad una chiave.
Le differenze principali rispetto al modello relazionale sono che una query restituisce un solo
elemento e che i value possono contenere qualsiasi tipo di dato.
Questo rappresenta uno svantaggio, poichè non c’è nessun modo di eseguire query basate sul
contenuto del valore in quanto i blob sono "oscuri".
Per questo motivo tale metodo, nonostante la semplicità di implementazione, non è ideale se
si vuole aggiornare solo parte del valore associato alla chiave o se si vuole fare una query sul
database.
2.3
Document stores
I Document stores sono orientati alla conservazione di documenti, quindi a differenza di quanto
accade con i Key-Value stores, il contenuto non è una black-box ma è accessibile ed indicizzabile.
Esempi di DB: MongoDB, CouchDB, Couchbase.
Lo scopo di questa tipologia di database è quella di archiviare in modo efficiente sia i documenti che il loro contenuto, per questo è possibile recuperare i documenti effettuando non solo la
ricerca per chiave, come avviene dei database key/value, ma anche in base al loro contenuto,
metadati o combinazioni di essi. Inoltre, gli indici sono quasi sempre realizzati simili a quelle
tipiche dei sistemi RDBMS che consentono ricerche per uguaglianza, intervallo, indici su più
attributi e riferimenti ad altri documenti.
I dati non sono memorizzati in tabelle con campi uniformi per ogni record, ma questi ultimi
vengono memorizzati come documenti, ognuno con le proprie caratteristiche ai quali poter aggiungere un diverso numero di campi, con lunghezze anche differenti in modo tale da non avere
campi vuoti all’interno dei documenti.
A differenza degli RDBMS, I JOIN non sono presenti, ma i riferimenti verso altri documenti
possono essere visti come una sorta JOIN. Inoltre i documenti non hanno uno schema e quindi
possono essere costituiti da coppie key/value, coppie key/array, o anche documenti annidati.
I valori memorizzati provvedono alcune strutture di codificazione e gestione dati: Il formato più
utilizzato per la codifica è il JSON, gli altri formati utilizzati sono XML, YAML e BSON. Questo
è dovuto principalmente anche alla forte integrazione che questi database hanno con Javascript.
Inoltre, la possibilità di ottenere modelli di dati complessi senza rinunciare alle performance, li
ha resi molto diffusi per siti web e di e-commerce, e gestione documentale.
10
Document stores
2.4
Graph stores
I Graph stores sono ispirati dalla teoria dei grafi, infatti non vengono utilizzati i formati rigidi
di SQL o la rappresentazione a colonne o tabelle, ma è utilizzata una rappresentazione tramite
grafi flessibili che rientra perfettamente nelle richieste specifiche di scalabilità. E’ la tipologia di
database ideale per la gestione di social network e simili, nonché sistemi intelligenti che facciano
uso di clustering e generazione di regole.
Una base di dati a grafo usa nodi e archi per rappresentare e archiviare l’informazione . La
rappresentazione dei dati mediante grafi, nei quali i nodi del grafo sono dati che possiedono coppie
key/value e gli archi sono le relazioni che intercorrono tra essi, offre un’alternativa al modello
relazionale che fa uso di tabelle, o ai database orientati al documento (che usano documenti).
I database a grafo sono spesso più veloci di quelli relazionali nell’associazione di set di dati, e
mappano in maniera più diretta le strutture di applicazioni orientate agli oggetti. Scalano più
facilmente a grandi quantità di dati e non richiedono le tipiche e onerose operazioni di unione
(join). Dipendono meno da un rigido schema entità-relazione e sono molto più adeguati per
gestire dati mutevoli con schemi evolutivi. Al contrario, i database relazionali sono tipicamente
più veloci nell’eseguire le stesse operazioni su un grande numero di dati.
Graph stores
11
Capitolo 3
Apache Cassandra
Con l’avvento del Web 2.0 la rete ha sperimentato per la prima volta le criticità legate alla
gestione infrastrutturale di un ambiente che dovesse sostenere ed accentrare le attività tipiche
di una community. In particolare era diventato necessario un massiccio miglioramento nei tempi
di risposta e la gestione di grossissimi volumi di dati.
Il codice di Cassandra è stato inizialmente sviluppato all’interno di Facebook, dove già MySql
veniva utilizzato in modo poco ortodosso, per potenziare la ricerca all’interno del sistema di
posta e per migliorare la tecnica di memorizzazione dei messaggi nella Inbox. La progettazione
iniziale si deve a Avinash Lakshman(uno degli sviluppatori di Amazon Dynamo) e Prashant
Malik. In seguito nel luglio del 2008, Cassandra è stato rilasciato come progetto open source,
rendendo disponibili i sorgenti, su Google Code. Dal marzo 2009 è entrato a far parte del progetto Incubator di Apache Software Foundation1 , data in cui l’intero progetto ha iniziato a essere
distribuito sotto la Apache License 2.
L’architettura di Cassandra privilegia alta disponibilità e tolleranza al partizionamento (AP)
trascurando appunto la totale consistenza. Da notare che una delle scelte più frequenti nella
progettazione dei sistemi NoSQL, consiste nella rinuncia della coerenza totale a favore di forme
più blande, tanto che da qualche tempo si è iniziato a parlare di eventual consistency("coerenza
finale"). Sistemi a consistenza finale garantiscono che, qualora non vi siano nuovi aggiornamenti
per un certo lasso di tempo relative a un determinato dato, alla fine tutti le richieste dello stesso
restituiscono il medesimo valore, risultato dell’ultimo aggiornamento. Cassandra è appunto una
soluzione a coerenza finale.
Apache Cassandra è un database open source, fault-tolerant, distribuito e decentralizzato, per
1
ASF (nata nel 1999) è una fondazione no-profit ed una comunità di sviluppo di progetti software come il web
server Apache (il progetto principale) e la suite da ufficio Apache OpenOffice
12
la gestione di grandi quantità di dati strutturati sparsi in tutto il mondo.
E’ stato progettato per funzionare su hardware di largo consumo a basso costo ed è caratterizzato da una grandissima velocità di esecuzione e scrittura, in quanto è in grado di memorizzare
centinaia di terabyte di dati, senza sacrificare l’efficienza di lettura.
Oltre a Facebook, Cassandra riscontra un grande bacino di utenze, ad esempio:
Twitter passa a Cassandra perché può essere eseguito su diversi cluster server ed è capace di
mantenere un’innumerevole quantità di dati;
Digg , che è il maggiore sito di social news, ha annunciato l’utilizzo di Cassandra dal 9 settembre
2009;
Netflix usa Cassandra per gestire i dati dei suoi sottoscrittori.
3.1
Architettura
Il database Cassandra è distribuito su numerose macchine che operano insieme. Il contenitore
esterno è noto come il Cluster, nel quale i nodi, ai quali vengono assegnati i dati, sono organizzati
in un formato ad anello (ring network).
L’anello rappresenta l’andamento ciclico dello spazio dei token, che vengono generati in base
alla chiave di riga e servono ad individuare in quale nodo è memorizzato il dato. Ad ogni nodo
è assegnata una posizione nell’anello basata sui token che deve gestire. ad ogni operazione di
inserimento verrà attribuito un determinato valore che permetterà di determinare su quale nodo
della rete andrà collocato, ottenendo così una facile distribuzione dei dati mediante una funzione
di hash.
Per mappare le chiavi di riga nello spazio dei token viene usato un partitioner che è una
funzione che stabilisce un token per una data riga in ingresso a partire dalla sua chiave di partizione, tipicamente mediante un hash table. Ogni riga di dati inserita viene distribuita attraverso
il cluster in base al valore del token. I partitioner in Cassandra sono:
1. RandomPartitioner : è la soluzione di default per le versioni di cassadra precedenti alla
1.2. Il token viene generato attraverso una funzione hash MD5 e i dati vengono distribuiti
nel cluster basandosi sui valori di questa funzione hash, non mantenendo quindi l’ordine
delle chiavi. Questo permette di bilanciare il carico fra i nodi.
2. Murmur3Partitioner : è il partitioner di default per le versioni di Cassadra successive
alla 1.2. Funzionalmente è lo stesso del Random partitioner, con la differenza che utilizza
una funzione hash chiamata Murmur3, molto più veloce di MD5.
3. ByteOrderedPartitioner : effettua una distribuzione ordinata dei dati basata sul lessico
per bytes di chiave. Non è consigliato.
4. OrderPreservingPartitioner : in questo caso viene assunto che le chiavi siano stringe
UTF8 (Unicode). E’ 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). Questa
soluzione non è consigliata poichè può portare ad avere uno sbilanciamento di informazioni
fra i nodi, in quanto le partizioni vicine tra loro avranno più attività di altre e quindi il
nodo che le ospita tenderebbe a sovraccaricarsi. Tuttavia questa soluzione consente di
ottimizzare gli accessi nel caso in cui si debbano recuperare i dati ordinati.
All’interno di Cassandra tutti i nodi in un cluster hanno gli stessi compiti e funzionalità, in
questo modo non esiste all’interno del cluster una specificità critica che in caso di malfunzionamento possa rendere inoperante il database, ossia non esiste un nodo master (la comunicazione
13
è peer-to-peer). Per questo motivo si dice che Cassandra non ha alcun single-point-of failure (ha
un’architettura decentralizzata e distribuita) ed è continuamente disponibile per le applicazioni
business-critical che non possono permettersi un fallimento.
Cassandra è scalabile ed elastico (elastic scalability), in quanto il modello di distribuzione
peer-to-peer permette di aggiungere e/o rimuovere nodi senza problemi (con strategia di replica
adeguata) a seconda del requisito. 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. Quindi l’aumento di nodi è seguito da un aumento delle
performance, che scalano in maniera lineare, in modo che i dati siano sempre distribuiti in modo
bilanciato e che si abbiano tempi di risposta rapidi.
Scalabilità
Un’altra caratteristica importante di Cassandra è la Failure Tolerance. I dati sono automaticamente duplicati su più nodi, per garantire che, all’eventuale crash di un elemento dell’insieme,
non debba necessariamente seguire la perdita di informazioni importanti o lo stallo dell’intera
istanza. Questo è realizzabile indicando nel keystore il replica factor, che indica il numero dei
nodi nel quale deve essere mantenuto il dato. Si noti che i nodi sono successivi secondo la topologia dell’anello.
Le strategie di replication esistenti sono due:
1. SimpleStrategy : si ha un solo datacenter, specifica un fattore di replica semplice e i
dati sono memorizzati in nodi successivi sull’anello. Si segue, all’aumentare del replication
factor, la circolarità dell’anello fino alla memorizzazione di tutte le copie.
2. NetworkTopologyStrategy : i dati possono essere trasmessi su più datacenter e in ognuno di essi i dati sono memorizzati in nodi successivi in senso orario, in base al partitioner
selezionato su quel datacenter, fino al raggiungimento del primo nodo del rack successivo.
Utilizzando questa opzione, è possibile impostare il fattore di replica per ogni datacenter in
modo indipendente. In questo caso si da priorità alla distribuzione su vari anelli poichè ci
si aspetta che nodi appartenenti allo stesso rack abbiano più probabilità di fallire, a causa
di problemi di elettricità o alla rete, piuttosto che nodi inseriti in anelli diversi, tenendo
anche in considerazione la vicinanza
fisica delle macchine.
Oltre al replica factor, l’altro fattore importante per la memorizzazione dei dati in Cassandra è
la consistency che si riferisce a come sono aggiornate e sincronizzate le righe dei dati su tutte le
14
repliche. Questa è modificabile e regolabile a run-time sia in lettura che scrittura: aumentando
il numero di nodi da leggere, così come aumentando quelli da scrivere per quanto riguarda le
funzioni di write, si ottiene un lineare miglioramento nella consistenza del dato a scapito delle
performance. E’ quindi importante decidere con attenzione quale sia il miglior compromesso per
la propria applicazione.
Le possibili strategie sono:
• ANY (solo in scrittura): La scrittura deve avvenire almeno su un nodo. Se nessun nodo
è disponibile, il coordinatore si fa carico di mantenere i dati fino a quando uno dei nodi
contenente la replica non è recuperato.
• ONE : in scrittura il nodo coordinatore (quello a cui si è collegato il client) deve scrivere
sul commit log e memtable di almeno un nodo in cui risiede la replica.
In lettura il nodo coordinatore legge il dato dal nodo più vicino (determinato dal coordinatore) che contiene la replica. Di default, viene effettuata la riparazione in background
per rendere le altre repliche consistenti.
• ALL : La scrittura deve avvenire sul commit log e memtable di tutti i nodi nel cluster
contenente una replica della riga.
In lettura restituisce il record con il timestamp più recente, dopo che tutte le repliche
hanno risposto. L’operazione di lettura fallisce se una delle repliche non risponde.
• QUORUM : La scrittura deve avvenire sul commit log e memtable in un QUORUM di
nodi contenenti una replica. In particolare EACH QUORUM si riferisce ad un QUORUM
di nodi in tutti i datacenter e LOCAL QUORUM ad un quorum di nodi appartenenti allo
stesso datacenter del nodo coordinatore. Per quanto riguarda il LOCAL QUORUM, in
scrittura il nodo coordinatore scrive in tutti i nodi appartenenti al suo stesso data center
(quorum di nodi) dove risiede la replica del dato e aspetta l’ack dal quorum dei nodi per
rispondere al client mentre gli ack degli altri nodi arrivano in maniera asincrona. Il valore
del quorum è dato da: replication factors/2+1 arrotondato per difetto.
In lettura il nodo coordinatore, appena ha avuto risposta dal quorum dei nodi, tramette al
client il dato più aggiornato (timestamp più recente) e aggiorna il dato memorizzato nelle
repliche.
NetworkTopolgyStrategy
15
Cassandra utilizza il protocollo Gossip in background per consentire ai nodi di comunicare tra
loro e rilevare eventuali nodi difettosi nel cluster.
Gossip è un protocollo di comunicazione peer-to-peer in cui i nodi scambiano periodicamente
informazioni sul loro stato e sui nodi di cui hanno informazioni. La procedura di gossip viene
eseguita periodicamente ogni secondo e consente lo scambio di messaggi di stato al massimo a 3
nodi del cluster. La comunicazione avviene iniziando una gossip session, composta da tre scambi
di messaggi simile a quanto avviene nella procedurathree-way handshake nel protocollo TCP.
I nodi scambiano informazioni su se stessi e sui nodi con cui hanno già scambiato messaggi Gossip, quindi in modo rapido tutti i nodi avranno informazioni su tutti gli altri nodi del cluster.
Ogni messaggio di gossip ha una versione (timestamp) associata con esso, quindi durante l’operazione di scambio dei messaggi, le vecchie informazioni memorizzate nel nodo vengono sovrascritte
da quelle più recenti ricevute.
Quando un nodo è avviato per la prima volta ottiene due informazioni necessarie all’avvio dal file
di configurazione (Cassandra.yaml): la prima è il nome del cluster di appartenenza e la seconda
è la lista dei nodi detti Seeds, da contattare per ottenere le informazioni relative agli altri nodi
del cluster.
Il primo avvio è ovviamente quello più critico e, per evitare problemi di partizionamento, tutti
i nodi del cluster hanno la stessa lista di nodi Seeds nel file configurazione; inoltre un nodo
memorizzerà per default i nodi con cui ha scambiato informazioni di gossip nei riavvii successivi.
Mediante lo stato determinato dai messaggi di gossip, è possibile effettuare l’operazione di failure detection ovvero la determinazione dello stato di un altro nodo del sistema, per verificare
se questo è attivo o meno. Tale meccanismo è utilizzato inoltre da Cassandra per evitare che le
richieste di un client vengano instradate verso un nodo non raggiungibile. Cassandra inoltre fa
sì da non inviare richieste a nodi che sono attivi, ma le cui prestazioni non sono efficienti. Le informazioni che gossip ottiene sull’attività dei nodi possono essere dirette (comunicazione diretta
con il nodo interessato) e indiretta (nodi secondari o terziari che vengono informati sullo stato
del nodo). Invece di avere un semplice meccanismo di soglia per la determinazione di fallimento
di un nodo, Cassandra utilizza un sistema d’individuazione ad accumulo per calcolare una soglia
per-nodo che tiene in considerazione le condizioni di rete, il carico del nodo e altre informazioni
che possono influire sulla percezione dello stato del nodo. Durante l’operazione di gossip, ogni
nodo mantiene una sliding window di arrivo dei messaggi di gossip dagli altri nodi del cluster; il
valore di tale finestra è stabilito da un parametro di configurazione detto "phi convict threshold"
che, variato, cambia la sensibilità del failure detector.
Quando un client si connette a un nodo e richiede un’operazione di lettura o scrittura, quel
nodo funge da coordinatore per quell’operazione del client. Il compito del coordinatore è quello
di agire come un proxy tra l’applicazione client e i nodi che contengono i dati richiesti (o una
loro replica); la determinazione di quale nodo nel ring debba gestire la richiesta è decisa dalla
configurazione del partizionatore e dalla strategia di replicazione del Cluster.
I componenti chiave di Cassandra per le operazioni di lettura e scrittura sono i seguenti:
• CommitLog : uno specifico registro su disco, in cui vengono scritte inizialmente tutte le
operazioni di write.
• Mem-Table : una struttura dati residente in memoria. Dopo che sono stati scritti nel
CommitLog, i dati vengono memorizzati nella MemTable, a cui Cassandra accede tramite
una chiave.
• SSTable : è un file su disco nel quale vengono memorizzati i file, una volta che la MemTable è piena, svuotandola tramite un’operazione di flushing. I dati conservati nel commit
16
log vengono eliminati nel momento in cui i corrispondenti dati nella Memtable subiscono
l’operazione di flush e quindi la funzione del commit log è solo quella di recuperare i dati
conservati nella Memtable nell’eventualità di problemi hardware. Le SSTables sono immutabili: Non è possibile effettuarci operazioni di sovrascrittura dopo il flush da Memtable.
Operazione di write
• Filtro Bloom : Si tratta di particolari tipi di cache, nelle quali vengono eseguiti rapidi
algoritmi per testare se un elemento è membro di un insieme, che si attivano ad ogni query
per le operazioni di read. Quindi una volta consultato il filtro Bloom, Cassandra accede
all’ SSTable opportuna con i dati richiesti dalla query.
Operazione di read
3.2
Data Model
Cassandra come già accennato in precedenza, appartiene alla categoria dei database NoSQL column family. Quindi le colonne sono raggruppate in insiemi chiamate famiglie (column families),
le quali si dividono in tipo semplice e tipo super. Il tipo super column può essere rappresentato
come una famiglia contenuta in un’altra famiglia e la radice è chiamata Keyspace.
Cassandra gestisce mappe di 4 oppure 5 dimensioni, a seconda se si tratti di column o super
column.
Una tabella in Cassandra è una mappa multi-dimensionale, distribuita, indicizzata da una chiave; il valore è un oggetto altamente strutturato. La tupla in una tabella è una stringa senza
restrizioni sulla lunghezza, tipicamente lunga da 16 a 36 byte.
17
Ogni operazione per ogni singola tupla è atomica, a prescindere da quante colonne o righe saranno lette o modificate.
Essenzialmente è un aggregato di Hash e Array che però rivestono, a seconda della loro posizione,
ruoli e funzioni ben distinte.
Data Model
3.2.1
Column e Supercolumn
Una column è un Hash formato dalle chiavi name, value e timestamp che sono stabilite a priori.
I valori delle chiavi name e value sono considerati da Cassandra come array di byte e quindi
possono contenere praticamente qualsiasi cosa, a differenza del timestamp, che è per necessità
un campo intero (i64). Esempi di column sono:
{
name : " age " ,
value : "26" ,
timestamp : 123456743
}
{
name : " f u l l n a m e " ,
v a l u e : " Sandro P a g a n o t t i " ,
timestamp : 836123423
}
La column dei NoSQL database è paragonabile ad una cella all’interno di un record che a sua
volta è contenuto in una tabella, per quanto riguarda i database relazionali.
Gruppi di column possono essere raggruppati all’interno di supercolumn, che possono essere viste
come column il cui campo value contiene un array di column. Spesso sono usate per raggruppare
colonne con attributi correlati fra di loro, appartenenti allo stesso aggregato. Attualmente però
le SuperColumn in Cassandra sono sempre meno usate in quanto non molto performanti a causa
dell’impossibilità di indicizzare le subcolumn all’interno di una super column.
Un esempio di supercolumn potrebbe essere il seguente:
18
{
}
name : " t e l e p h o n e number " ,
value : {
{
name : " p r e f i x " ,
value : "349" ,
timestamp : 123123141241
},
{
name : " number " ,
value : "0516558976" ,
timestamp :
231231231434
}
}
Si nota che un’altra piccola differenza tra column e supercolumn è l’assenza in queste ultime del
campo timestamp.
Column e supercolumn vengono raccolte in strutture chiamate rispettivamente columnfamily
e supercolumnfamily che si sostituiscono al costrutto "tabella" dei database relazionali.
La supercolumn family è un’estensione dello standard column family che aggiunge un ulteriore
livello di indicizzazione, detta appunto super column, fra la row key e l’insieme delle colonne.
Una columnfamily è contraddistinta da un nome che la identifica e da un array di coppie chiave
valore; ogni elemento di questo array è chiamato row ed è paragonabile al concetto di record dei
RDBMS.
La chiave di una row funge da identificatore mentre il valore è a sua volta un array di tutti gli
attributi del record in questione. Tali attributi possono essere soltanto column, nel caso in cui si
stia definendo una columnfamily, o soltanto supercolumn, nel caso in cui il costrutto sia di tipo
supercolumnfamily. Ecco un esempio di columnfamily:
User = {
sandropaganotti : {
age : " 2 6 " ,
e m a i l : " s a n d r o . p a g a n o t t i @ g m a i l . com " ,
g e n d e r : " male " ,
username : " spx2 "
},
jason : {
age : " 2 0 " ,
job t i t l e : " p r o f e s s i o n a l biker "
}
}
Non esiste nessuno schema predefinito per le singole row, ne in senso assoluto ne tra le row di
una stessa family.
Inoltre è necessario inserire e documentare le column e supercolumn family all’interno del file
iniziale di configurazione, e quindi non è possibile crearle a runtime.
19
Le differenze sostanziali con il modello relazionale sono:
1. Modello Relazionale : Lo schema nel modello relazionale è fisso. Una volta deinite le
colonne per una tabella, durante l’inserimento, in ogni riga tutte le colonne devono essere
riempite da almeno un valore NULL.
Le tabelle relazionali definiscono solo le colonne, mentre l’utente riempie la tabella con i
valori.
2. Cassandra : In Cassandra, sebbene le column families sono definite, le colonne non lo
sono. Si può liberamente aggiungere qualsiasi colonna a qualsiasi column family, in qualsiasi
momento.
Una tabella contiene colonne, o può essere definita come una super column family.
3.2.2
KeySpace
L’ultimo gradino in questa gerarchia di strutture dati è occupato dal keyspace, che è il contenitore più esterno dei dati in Cassandra. Ricopre lo stesso ruolo assegnato al database per
quanto riguarda il modello relazionale e deve essere creato prima di poter effettuare qualsiasi
operazione.
Esso è un namespace che definisce come i dati vengono replicati nei nodi.
Gli attributi di un keyspace in Cassandra sono:
1. Fattore di replica : come già detto, è il numero di macchine nel cluster che ricevono la
copia dello stesso dato.
2. Strategia di replica : indica il tipo di strategia con cui sistemare le repliche nell’anello.
Le possibili strategie sono la SimpleStrategy e la NetworkTopologyStrategy, descritte in
precedenza.
3. Column families : è il contenitore di una collezione di righe. ogni riga, a sua volta,
contiene colonne ordinate. Ogni keyspace ha almeno una (spesso molte) column family.
In particolare conterrà tutte le singole tabelle le quali erediteranno tutti gli attributi (replica
factor e column families) definiti sul KeySpace che le contiene.
Tipicamente in un cluster esiste un solo keyspace per applicazione e ogni keyspace contiene
il set di columnfamily specifico di un’applicazione. Anche questo tipo di struttura deve essere
dichiarata nel file di configurazione all’interno del tag KeySpaces, ecco un esempio:
<Keyspace Name=" I n v e n t a r i o ">
<ColumnFamily CompareWith="BytesType " Name=" S c a f f a l e "/>
<ColumnFamily CompareWith="BytesType " Name=" Oggetto "/>
<ColumnFamily CompareWith="BytesType " Name=" T i p o l o g i e "/>
</Keyspace>
L’attributo CompareWith indica il metro di ordinamento, sempre sulla chiave, mai sul valore,
delle column/supercolumn all’interno delle singole row.
20
Capitolo 4
Applicazioni Cassandra
A differenza di molti altri database NoSQL Cassandra dispone di un proprio linguaggio di query
detto Cassandra Query Language (CQL). L’assonanza nel nome vuole richiamare le forti similitudini con SQL.
Gli utenti interagiscono con Cassandra attraverso i suoi nodi, utilizzando questo particolare linguaggio, che tratta il database (keyspace) come un contenitore di tabelle.
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 ed è stata rimossa a partire dalla versione 3.x di Cassandra. Il CQL può essere utilizzato via API o attraverso
una shell chiamata cqlsh. In Cassandra ogni operazione di write è inizialmente scritta in uno
specifico registro detto CommitLog. In seguito i dati passano dal CommitLog alla MemTable,
una struttura dati residente in memoria. Quando la MemTable è piena, i dati verranno scritti
in un file su disco detto SSTable.
Per le operazioni di read, Cassandra prende i valori nella MemTable, e consulta un particolare
filtro detto filtro Bloom. Si tratta di particolari tipi di cache che si attivano ad ogni query, nelle quali vengono eseguiti rapidi algoritmi per testare se un elemento è membro di un insieme.
Quindi una volta consultato il filtro Bloom, Cassandra accede all’ SSTable opportuna con i dati
richiesti dalla query.
Per i nostri esempi utilizzeremo un particolare programma rilasciato da datastax detto DataStax Distribution of Apache Cassandra (DDC). In particolare verrà utilizzata la Community
Edition, che contiene un terminal Cassandra, in cui è possibile formulare le query CQL grazie
alla shell cqlsh, ed inoltre è fornito di un DataStax OpsCenter con cui poter gestire e modificare
i differenti clusters e i loro nodi tramite una pagina web.
4.1
KeySpace
La sintassi per la creazione di una Keyspace è:
CREATE KEYSPACE < identifier > WITH < properties >
In particolare, il comando CREATE KEYSPACE ha due proprietà: replication e durable writes.
21
CREATE KEYSPACE " KeySpace Name "
WITH replication = { ’ class ’: " Strategy name " , ’ replication_factor ’ :
" No . Of replicas "}
AND durable_writes = " Boolean value ";
Si noti che però in caso di più datacenter (con la NetworkTopologyStrategy) questa scrittura
non è più adatta in quanto bisogna specificare il fattore di replica per ognuno dei datacenter
presenti nel cluster:
CREATE KEYSPACE " KeySpace Name "
WITH replication = { ’ class ’: " Strategy name " , ’ datacentername1 ’ :
" No . Of replicas " , ’ datacentername2 ’ :
" No . Of replicas " ,..}
AND durable_writes = " Boolean value ";
4.1.1
Replication
Lo scopo della replicazione è di specificare la strategia di replica, che abbiamo elencato in precedenza, e il numero di repliche del dato richieste.
Esempio
In questo esempio vogliamo creare, tramite la shell CQL fornita da DataStax Community
Edition, un keyspace chiamato "persone", utilizzando la prima strategia (SimpleStrategy)
e scegliendo il fattore di replica per 3 copie.
Create Keyspace
E’ possibile inoltre verificare se la tabella viene creata, utilizzando il comando DESCRIBE
keyspaces. Così facendo verranno mostrati tutti i keyspace creati.
4.1.2
Durable writes
Utilizzando questa opzione, è possibile istruire Cassandra se utilizzare commitlog per gli aggiornamenti sulla keyspace corrente. Come si nota dall’esempio precedente, di default la proprietà
22
durable writes di una tabella è impostata su true, ma può anche essere settata a false. Inoltre
per questa proprietà non è possibile utilizzare la SimpleStrategy.
Esempio
Vogliamo creare un keyspace di nome "prova" che abbia la proprietà di durable writes
settata a false. Si noti che in questo caso, per specificare il numero di repliche dobbiamo
specificare il nome del datacenter considerato. È possibile verificare se la proprietà durable
writes è stata impostata su false, interrogando il keyspace di sistema. Questa query ti da
tutte le KeySpaces con le loro proprietà.
cqlsh > SELECT * FROM system . schema_keyspaces ;
Che presenterà un output di questo tipo:
Se volessimo modificare le proprietà dello spazio delle chiavi, il comando da utilizzare è ALTER
KEYSPACE. Cosi come CREATE KEYSPACE, anche questo comando agisce su due proprietà:
replica e durable writes. La sintassi è la seguente
ALTER KEYSPACE < identifier > WITH < properties >
vale a dire:
23
ALTER KEYSPACE " KeySpace Name "
WITH replication = { ’ class ’: " Strategy name " , ’ replication_factor ’ :
" No . Of replicas2 };
Esempio
Nell’esempio che segue prendiamo in considerazione il keyspace di nome "prova", creato
precendentemente, modificando la proprietà di durable writes da false a true:
Alter Keyspace
Inoltre è possibile eliminare un spazio delle chiavi utilizzando lo spazio delle chiavi comando
DROP. La sintassi è la seguente:
DROP KEYSPACE < identifier >
4.2
Column Families
Per popolare i keyspaces precedentemente creati con delle column families la sintassi è molto
simile al linguaggio SQL. Prima di tutto però bisogna scegliere il keyspace in cui inserire le
tabelle, questo è possibile grazie al comando USE, la cui sintassi è:
USE < identifier >
In particolare nell’esempio che verrà trattato, sarà considerato il keyspace "persone" creato in
precedenza: E’ possibile creare una column family utilizzando il comando CREATE TABLE,
la cui sintassi è:
24
CREATE TABLE tablename (
column1 name datatype PRIMARYKEY ,
column2 name data type ,
column3 name data type ,
PRIMARY KEY ( column1 )
)
La chiave primaria è una colonna che viene utilizzata per identificare in modo univoco una
riga, pertanto è obbligatorio definirla durante la creazione di una tabella. Una chiave primaria
è costituita da una o più colonne di una tabella.
Esempio
In questo esempio si vuole creare una tabella "studenti" popolata con gli attributi id, nome
e email. Inoltre si considerano come chiavi primarie sia l’id che l’email dello studente. Per
verificare che la tabella è stata creata si utilizza il comando DESCRIBE TABLE.
Create Table
Anche per quanto riguarda le operazioni di scrittura e lettura delle tabelle la sintassi è molto
simile a quella del linguaggio SQL. In particolare per la scrittura si utilizza il comando INSERT
come segue:
INSERT INTO table_name
( column_name , column_name ...)
VALUES ( value , value ... )
Per le query di lettura si utilizza il comando SELECT:
SELECT column_name FROM table_name
25
Esempio
Si vuole popolare la tabella studenti creata in precedenza con degli studenti e i loro attributi. Per quanto riguarda la lettura, si verifica prima se l’inserimento è andato a buon
fine, selezionando tutta la tabella, e poi si esegue una query in particolare.
Esempi di query
Se si volessero eseguire più query nello stesso momento, basta far precedere le stesse dal
comando BEGIN BATCH e al termine delle query aggiungere: APPLY BATCH.
Per gestire e modificare i diversi cluster e i nodi contenuti in esso, DataStax mette a disposizione
un OpsCenter la cui interfaccia è mostrata in seguito:
OpsCenter
Come si può notare da qui si possono monitorare sia il numero di nodi e datacenter appartenenti
al cluster, sia una grade varietà di grafici che mostrano il traffico di dati avvenuto in un determinato periodo. Ad esempio nell’immagine sopra si può notare come il grafico Write Request
testimoni la scrittura del keyspace e delle tabelle, fatta negli esempi precedenti.
26
Per gestire il cluster, ad esempio aggiungendo nodi, basta andare su cluster actions e selezionare
add node.
Inoltre l’OpsCenter fornisce una soluzione alternativa alla shell cqlsh di cassandra utilizzata
in precedenza. Infatti accedendo alla sezione data si possono comodamente creare e gestire keyspace e tabelle come mostrato in figura.
Per poter modificare un keyspace precedentemente creato, basta cliccare sullo stesso ed andare nella sezione edit. In questo modo si possono modificare numero e strategia di replica e la
proprietà di durable_writes, oppure eliminare l’intero keyspace.
27
Conclusioni
In questo elaborato abbiamo messo in luce come il modello relazionale, che fino a pochi anni fa
sembrava un modello insostituibile per la rappresentazione dei dati, nell’era dei Big Data, ha
iniziato a mostrare le sue debolezze di fronte alle dimensioni e alla variabilità delle informazioni.
Infatti, sebbene rimanga ancora il modello più diffuso, il modello E-R non si è dimostrato il più
adatto quando si ha a che fare con domini molto dinamici, caratterizzati da dati non strutturati
e da moli di informazioni con rapidi incrementi che è opportuno affrontare con sistemi flessibili
in grado di scalare orizzontalmente, senza compromettere i dati esistenti.
Si è giunti, pertanto, alla nascita dei cosiddetti database NoSQL dei quali abbiamo inanzitutto
elencato le principali differenze con i RDBMS, per sottolinearne vataggi e svantaggi.
Si noti che i NoSql database, nonostante siano stati introdotti solo agli inizi degli anni 2000,
abbiano già avuto un massiccio sviluppo e abbiano riscontrato un grandissimo bacino di utenze,
come alcuni dei principali social network (Facebook e Twitter), oppure aziende che forniscono
un servizio efficiente di streaming (Netflix).
Con l’avanzare degli anni e quindi con l’incremento delle tecnlogie informatiche, si può dedurre
che la mole di dati da gestire crescerà eponenzialmente, portando i NoSql database ad essere i
modelli maggiormente usati in quest’ambito. Questo anche grazie al fatto che i modelli sviluppati sono numerosi e ognuno di essi è idoneo a soddisfare dei requisiti specifici.
Tuttavia, come già accennato nell’elaborato, il tradizionale modello relazionale non è destinato a scomparire, in quanto ci sono ancora molte applicazioni in cui il modello E-R è ancora
la soluzione migliore.
28
Bibliografia
[1] https://docs.datastax.com/en/cassandra.
[2] http://www.w3ii.com/it/cassandra/cassandra_referenced_api.html.
[3] http://www.datastax.com/.
[4] http://cassandra.apache.org/.
[5] http://dassia.crs4.it/wp-content/uploads/2014/11/04_CASSANDRA.pdf
[6] http://www.html.it/articoli/introduzione-a-apache-cassandra-1/
[7] http://www.html.it/articoli/sql-e-nosql-a-documenti-il-confronto-2/
[8] https://wiki.apache.org/cassandra/
[9] http://dassia.crs4.it/wp-content/uploads/2014/11/01_NOSQL.pdf
29