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