• Non ci sono risultati.

Design di un sistema Big Data per l'analisi e la gestione dei dati real-time provenienti dagli impianti di produzione delle energie rinnovabili.

N/A
N/A
Protected

Academic year: 2021

Condividi "Design di un sistema Big Data per l'analisi e la gestione dei dati real-time provenienti dagli impianti di produzione delle energie rinnovabili."

Copied!
120
0
0

Testo completo

(1)

l’analisi e la gestione dei dati real-time

provenienti dagli impianti di produzione

delle energie rinnovabili.

Filippo Todeschini

Relatore: Prof. Salvatore Rinzivillo

Dipartimento di informatica

Università di Pisa

Informatica per l’economia e per l’azienda - Business Informatics

Laurea Magistrale

(2)
(3)

L’elaborato tratta l’implementazione e l’analisi delle performance di un sistema Big Data applicato ad un progetto nel contesto delle Energy Renewable; l’obiettivo è quello di creare un sistema che possa gestire in real-time i dati provenienti dai sensori dei device degli impianti di produzione.

Il progetto è stato realizzato utilizzando, in parallelo, due differenti database NoSQL: Apache Cassandra e MongoDB. Ciò ha permesso di valutare quale dei due fosse più adatto alle specifiche del sistema e di analizzarne meglio le performance. Pertanto, le analisi effettuate si concentrano sulle prestazioni dei due database, in termini di operazioni di scrittura e lettura per le varie tipologie di flussi implementate: batch e real-time. Infine, sono state eseguite ulteriori analisi per comprendere meglio la differenza di prestazioni ottenuta tra i flussi batch e real-time.

(4)
(5)

Lo scopo di questa tesi di laurea è quello di presentare un progetto sviluppato presso l’azienda Data Reply per un cliente nell’ambito delle Energy Renewable. Questo consiste nel realizzare un sistema Big Data per la gestione in real time dei flussi di dati provenienti dagli impianti di produzione. Questi ultimi includono impianti idroelettrici, geotermici, solari ed eolici distribuiti negli stati di tutti i continenti del mondo.

Il progetto è stato sviluppato utilizzando alcune delle principali tecnologie e strumenti utilizzati nei contesti Big Data come Cloudera, Datastax, Apache Cassandra, MongoDB, Apache Kafka e Spark. L’obiettivo è quello di implementare i flussi ETL(Extract, Transform, Load) per la trasformazione dei dati provenienti dagli impianti e la loro memorizzazione all’interno di un database NoSQL. Per ciò si è deciso di proporre due soluzioni differenti con due database NoSQL diversi, Apache Cassandra e MongoDB, in modo da poter valutare quale sia la soluzione migliore per le specifiche richieste; il requisito fondamentale è quello di ottenere alte prestazioni per le operazioni di scrittura, in modo da poter sostenere la velocità dei dati in input. Inoltre, si deve implementare anche un flusso che, ogni notte, effettui la copia delle tabelle dei database NoSQL in tabelle o file su Hadoop distribute file system (HDFS) poichè questi dati devono essere analizzati e visualizzati con appositi tool che sono ottimizzati per la lettura da HDFS o Hive.

Nella tesi si è cercato di descrivere in maniera sequenziale tutto il progetto elaborato, descrivendo tutto ciò che è stato implementato, sia le soluzioni base sia quelle più complesse che però hanno delle prestazioni migliori; inoltre sono stati eseguiti anche dei test e del tuning su alcuni parametri al fine di migliorare le performance dei flussi ETL.

Nei primi capitoli della tesi viene introdotta e presentata quella che è stata la "rivoluzione" dei Big Data negli ultimi anni, evidenziandone le motivazioni e le principali innovazioni tecnologiche. In particolare, nel secondo capitolo, si parla più nel dettaglio di una delle innovazioni del contesto Big Data, i database NoSQL. Questi vengono presentati attraverso

(6)

la loro evoluzione nel tempo, le loro principali caratteristiche, le varie tipologie e le principali differenze coi database relazionali. Tra questa serie di nuovi database, vengono analizzati più nel dettaglio Apache Cassandra e MongoDB, perchè sono stati utilizzati all’interno del progetto; di questi ne viene descritta l’architettura, il data model e il linguaggio di iterrogazione.

I capitoli 3 e 4 descrivono il progetto realizzato in tutte le sue sfaccettature. Il capitolo 3 contiene una descrizione delle finalità del progetto, dell’architettura e del sistema realizzato e il data model utilizzato, mentre il capitolo 4 analizza nel dettaglio tutti i flussi ETL con i relativi test e le performance ottenute. Infine il capitolo 5 contiene un confronto delle performance ottenute nei flussi ETL che utilizzano Apache Cassandra come database NoSQL e quelli che usano MongoDB.

La realizzazione di tale progetto è stato possibile grazie ad un percorso di formazione sulle tecnologie da utilizzare. Questo è stato fatto seguendo una serie di corsi online sopratutto per quanto riguarda Apache Cassandra, MongoDB, Spark e per Apache Cassandra ho frequentato anche un corso svoltosi a Parigi organizzato da Datastax.

(7)

Introduzione v

List of figures ix

1 Big Data 1

1.1 Cosa sono i Big Data? . . . 1

1.2 Quali sono le caratteristiche dei Big Data? . . . 2

1.3 Come vengono analizzati? . . . 3

1.4 Quali sono i contesti principali? . . . 5

2 DataBase NoSQL 7 2.1 Introduzione . . . 7

2.2 CAP Theroem . . . 8

2.3 Database relazionali vs NoSQL . . . 10

2.4 Classificazione dei database NoSQL . . . 12

2.4.1 Column Oriented . . . 13

2.4.2 Document Stored . . . 14

2.4.3 Graph Based . . . 15

2.4.4 Key-Value . . . 16

2.4.5 Multi-Model . . . 16

2.5 Altri Database distribuiti: Hive e Impala . . . 17

2.6 Apache Cassandra vs MongoDB . . . 17

2.7 Apache Cassandra . . . 18 2.7.1 CQL . . . 19 2.7.2 Architettura . . . 21 2.7.3 Data Model . . . 30 2.8 MongoDB . . . 34 2.8.1 Architettura . . . 35

(8)

2.8.2 Data Model . . . 39

2.8.3 Query Model . . . 42

3 Big Data al servizio delle energie rinnovabili 49 3.1 Obiettivo . . . 49

3.2 Architettura . . . 50

3.3 Ambiente di Test . . . 51

4 Implementazione del Sistema 53 4.1 Input Data: Producer Kafka and Hdfs . . . 53

4.2 Data Model . . . 55

4.3 Data Ingestion . . . 57

4.4 HDFS to Database NoSQL . . . 61

4.4.1 Apache Cassandra: Data Ingestion from HDFS . . . 62

4.4.2 Apache Cassandra: Writing Performance . . . 64

4.4.3 MongoDB: Data Ingestion from HDFS . . . 73

4.5 Real-Time ingestion: Kafka to Database NoSQL . . . 80

4.5.1 Apache Cassandra: Data Ingestion from Kafka . . . 83

4.5.2 MongoDB: Data Ingestion from Kafka . . . 86

4.6 Database NoSQL to Hive . . . 89

5 Apache Cassandra vs MongoDB 99 5.1 Writing Performance . . . 99

5.2 Reading Performance . . . 100

6 Conclusioni 103

References 105

(9)

1.1 Data Production . . . 1 1.2 MapReduce . . . 4 2.1 NoSQL Evolution . . . 8 2.2 CAP Theorem . . . 9 2.3 NoSQL . . . 10 2.4 Column Oriented . . . 13 2.5 Document Stored . . . 14 2.6 Graph Based . . . 15 2.7 Key-Value . . . 16 2.8 Apache Cassandra . . . 18 2.9 Virtual Nodes . . . 22 2.10 Write Path . . . 24 2.11 Compaction . . . 25 2.12 Read Path . . . 27

2.13 Write Consistency Level . . . 27

2.14 Write Consistency Level . . . 28

2.15 Read Consistency Level . . . 29

2.16 KeySpace . . . 31

2.17 MongoDB . . . 34

2.18 MongoDB: Replica Set . . . 36

2.19 MongoDB: Election . . . 37

2.20 MongoDB: Sharded Cluster . . . 38

2.21 MongoDB: Operation in a Sharded Cluster . . . 39

2.22 MongoDB:Document . . . 40

2.23 MongoDB:Insert operation . . . 42

2.24 MongoDB:Update operation . . . 43

(10)

2.26 MongoDB:Aggregation Framework . . . 46 2.27 MongoDB:Stages . . . 47 2.28 MongoDB:Map Reduce . . . 48 4.1 BatchSize . . . 65 4.2 BatchSize2 . . . 66 4.3 BatchSize3 . . . 67 4.4 BatchSize2 . . . 68 4.5 concurrentWrite . . . 69 4.6 concurrentWrite2 . . . 69 4.7 concurrentWrite3 . . . 70 4.8 concurrentWrite4 . . . 70 4.9 upDataPerf . . . 71 4.10 upDataPerf2 . . . 72 4.11 upDataPerf3 . . . 72 4.12 upDataPerf4 . . . 73 4.13 mongodbIndex . . . 78 4.14 mongodbIndex2 . . . 79 4.15 kafkaCassandra . . . 84 4.16 kafkaCassandra2 . . . 85 4.17 kafkaCassandra3 . . . 85 4.18 kafkaMongoDB . . . 87 4.19 kafkaMongoDB . . . 88 4.20 kafkaMongoDB . . . 88 4.21 hive . . . 96 4.22 hive2 . . . 97 4.23 hive2 . . . 98 5.1 cassandraVsMongoDB . . . 99 5.2 cassandraVsMongoDB2 . . . 101

(11)

Big Data

1.1

Cosa sono i Big Data?

Negli ultimi anni si è assistito ad una forte evoluzione tecnologica sia per quanto riguarda i software sia per l’hardware portando la società odierna ad essere sempre più informatizzata ed automatizzata. Questa evoluzione è stata favorita dalla crescita delle tipologie di device fruibili a tutti, come ad esempio gli smartphone, tablet, dallo sviluppo dell’IoT (“Internet of things”) e nuove tecnologie (come il web 2.0, social ) che vengono utilizzate sia nei contesti lavorativi sia in quelli privati. A questi nuovi dispositivi , va associato lo sviluppo costante delle loro componenti, dei sensori e del software, che permettono di generare, memorizzare ed analizzare nuove informazioni che prima non era possibile ottenere. Per cui la quantità di informazioni che ad oggi sono disponibili sul web, nei nostri dispositivi è estremamente superiore rispetto a quelle di qualche anno fa e la crescita stimata per il futuro seguirà un andamento esponenziale come si può osservare dal grafico 1.1.

(12)

A questa evoluzione è associato il fenomeno dei “Big Data”, con il quale non si vuole intendere solamente il fatto di avere una grande disponibilità di informazioni, ma anche il fatto di saperle memorizzare, gestire, analizzare ed aggregare efficientemente. L’obiettivo finale è sempre quello di avere dei dati, grezzi o aggregati, che possano portare un qualche vantaggio economico, indicare al meglio una decisione da prendere oppure semplicemente fornire un nuovo servizio alla società.

Una prima definizione formale di questo fenomeno è stata data da Douglas Laney nel 2001 nel suo studio “3D Data Management: Controlling Data Volume, Velocity, and Variety”, in cui definisce il mondo dei Big Data attraverso il modello delle 3V. Questo mette in mostra quali siano le 3 caratteristiche fondamentali dei Big Data: Volume, Velocity and Variety. Tuttavia, definire i Big Data solamente attraverso queste tre caratteristiche, non era pienamente condiviso dalla comunità scientifica, per cui nel 2012 la società Gartner aggiornò la definizione in modo:

Big data is high volume, high velocity, and/or high variety information assets that require new forms of processing to enable enhanced decision making, insight discovery and process optimization[2].

In pratica, alla definizione iniziale di Laney è stato aggiunto quello che è l’obiettivo finale di questi dati, ovvero quello di dover essere un valore aggiunto nella presa delle decisioni, é un riferimento al fatto che questi dati necessitano di nuove tecniche di elaborazione. A partire da questa seconda definizione si è arrivati, nel 2016, ad una definizione formale condivisa dalla comunità che riprende appunto il modello delle 3V e il fatto che i Big Data devono essere analizzati mediante tecniche specifiche affinché possano risultare un valore aggiunto per l’azienda e/o per la società .

Big Data represents the Information assets characterized by such a High Volume, Velocity and Variety to require specific Technology and Analytical Methods for its transformation into Value[3]

1.2

Quali sono le caratteristiche dei Big Data?

Le caratteristiche principali dei Big Data sono quelle descritte da Laney nel modello delle 3V:

(13)

• Volume: ovvero la quantità, il volume dei dati generati dai vari devices, software ecc, memorizzati nei sistemi informativi e analizzati con software e tecniche specifiche in ambito big data;

• Velocity: cioè la velocità con cui questi dati vengono generati, e processati per poter soddisfare i requisiti;

• Variety: ossia la grande varietà di dati, informazioni fruibili. Ciò dipende soprattutto dalle fonti che li generano, poiché ognuna potenzialmente potrebbe dare origine a dati differenti, sia come contenuto informativo che come struttura. A sua volta ogni fonte, potrebbe poi dar luogo a dati diversi, perché magari è in grado di generare alcune informazioni solo in seguito ad un evento oppure perché, con l’evoluzione hardware della stessa fonte, oggi sono disponibili dati che nella versione precedente non esistevano.

A queste tre caratteristiche fondamentali, ne vanno aggiunte altre due, Variability e Veracity, che sono state introdotte con le definizioni successive[3]:

• Variability: ovvero il problema che la grande varietà dei dati, strutturati e non, potrebbe portare ad avere delle situazioni di inconsistenza all’interno di un dataset; • Veracity: questa proprietà fa riferimento alla qualità del dato che, in un insieme così

vasto e vario di informazioni, è più difficile da controllare e garantire.

Date queste 5 caratteristiche se venissero utilizzate tecniche di memorizzazione, analisi e visualizzazione tradizionali, cioè quelli che si utilizzano per i datasets “normali”, difficilmente si arriverebbe ad ottenere dei risultati; i due limiti principali sono dati dai tempi di esecuzione e dal costo computazionale degli algoritmi utilizzati per processare i dati. Per cui, per poterli analizzare sono necessari nuovi metodi e nuove soluzioni algoritmiche e architetturali.

1.3

Come vengono analizzati?

L’idea principale per poter analizzare questa grande quantità di dati efficientemente e in tempi ragionevoli, è quella di sfruttare sia la tecnica della programmazione parallela, per poter effettuare più operazioni in contemporanea, sia quella della programmazione distribuita, per poter suddividere su più macchine i dati e il costo computazionale delle operazioni.

(14)

Sulla base di queste due tecniche, la soluzione più innovativa è stata il framework del MapReduce: progettato da Google e descritto nel 2004 in cui pubblicò un paper in cui delinea l’architettura; in pratica, è un framework di programmazione che permette di processare i dati in maniera distribuita e parallela su un cluster composto da n nodi per mezzo di una serie di step:

Fig. 1.2 Step del framework mapReduce [4] 1. Map

I dati in input, che sono nella forma (K,V), vengono divisi e distribuiti sui worker-nodes del cluster a seconda della chiave K associata ad ogni dato in modo da poter aver avere i dati con la stessa chiave sullo stesso nodo. Successivamente, in parallelo, ogni worker-node processa i dati in locale effettuando le opportune trasformazioni definite dall’utente; i dati modificati, ora saranno nella forma (K2,V2), dove i nuovi valori K2 e V2 sono rispettivamente la chiave e il dato associato dopo le varie trasformazioni. 2. Shuffle

Una volta che tutti i dati sono stati processati, questi vengono ridistribuiti sui worker-nodes a seconda della nuova chiave associata (K2), sempre per conservare i dati con la stessa chiave sullo stesso nodo ed eseguire lo step successivo con i dati in locale. 3. Reduce

Infine, per ogni nodo vengono raggruppati, compattati i vari record a partire dai valori delle delle chiavi; alla fine del processo ci sarà un unico output (una record o un insieme di record) per ogni chiave processata.

Questo framework è stato introdotto e adottato all’interno della distribuzione open-source Apache Hadoop, che è la principale distribuzione utilizzata in ambito Big Data. Sulla base di questa distribuzione, ne sono nate altre come Cloudera e Hortonworks che offrono una serie di

(15)

servizi, tools aggiuntivi per la gestione della memorizzazione, elaborazione e visualizzazione dei dati.

Infine, accanto a queste distribuzioni, si sono sviluppate altre tecnologie spesso a partire da progetti open-source e non necessariamente incluse nelle distribuzioni descritte preceden-temente, per poter memorizzare, processare e analizzare i Big Data; ad esempio i database NOSQL per la memorizzazione distribuita, come Cassandra e MongoDB, altri progetti, come Spark, SOLR, ElasticSearch, per l’analisi e l’indicizzazione dei dati, e software come Kibana, Spotfire e Tableu per la visualizzazione.

1.4

Quali sono i contesti principali?

Non è facile definire un contesto principale per quanto riguarda l’utilizzo dei Big Data, poiché questi sono presenti un po’ in tutti i settori: bancario, industriale e perfino quello pubblico. Oggi, la loro applicazione è spesso sinonimo di innovazione, e soprattutto per le aziende, una leva economica molto importante.

In particolare, in questa tesi è stato affrontato un progetto relativo all’ambito delle Re-newable Energy in cui l’obiettivo principale è stato quello di costruire un flusso che potesse elaborare e memorizzare i dati dei sensori dei vari impianti nel mondo, sia in real-time sia in modalità batch per poter caricare lo storico dei dati ed eventuali correzioni dei dati in real-time.

(16)
(17)

DataBase NoSQL

2.1

Introduzione

Il termine NoSQL fa riferimento a un movimento che promuove un insieme di sistemi di memorizzazione e gestione di dati che non utilizzano uno schema relazionale.

Questo termine venne utilizzato per la prima volte nel 1998 da Carlo Strozzi nel descrivere la sua base di dati relazionale che non prevedeva l’interrogazione con il linguaggio SQL. Nel 2009, questo termine è stato ripreso da Eric Evans ad una conferenza incentrata sullo sviluppo delle tecnologie open-source nell’ambito dei database non relazionali, distribuiti. A partire da ciò, questo termine ha preso il significato di “Not Only SQL”, poiché, per alcuni casi d’uso, il linguaggio SQL è più performante ma sopratutto perché, alcuni di questi database, offrono un sistema di interrogazione che è simile a quello SQL; in modo da facilitarne l’utilizzo e non ostacolare coloro e le aziende che, negli ultimi anni, hanno utilizzato principalmente i sistemi SQL.

Questi DB non relazionali sono nati a partire dagli anni 60’ ma inizialmente non hanno avuto una grande popolarità perché quelli relazionali permettevano di analizzare in maniera efficace i dati, ma soprattutto perché garantiscono le proprietà ACID (atomicity, consistency, isolation and durability). Tuttavia, l’avvento del fenomeno dei Big Data, ha comportato un decadimento delle prestazioni dei database relazionali favorendo l’evoluzione di quelli NoSQL. Nel grafico sottostante si vede come a partire dal 2004 l’evoluzione dei db NoSQL sia cresciuta costantemente, ad oggi la quantità di progetti database NoSQL è superiore ed in continuo aumento.

(18)

Fig. 2.1 Storia dell’evoluzione dei database NoSQL [5]

2.2

CAP Theorem

Un punto focale per lo sviluppo di questi database distribuiti, non relazionali è stato la formulazione del CAP theorem: teorizzato nel 2000 dallo scienziato informatico Eric Brewer al simposio “Principles of Distribuited Computing (PODC)” e dimostrato nel 2002 da Seth Gilbert e Nancy Lynch.

Il teorema afferma che per un sistema distribuito è impossibile soddisfare contemporanea-mente le tre proprietà (Consistency, Avaliability, Partition Tolerance), ma al massimo due alla volta. Queste tre proprietà descrivono assieme come i dati vengono gestiti all’interno di un sistema distribuito:

• Consistency: si riferisce al fattore di consistenza che hanno i dati, ovvero che ogni lettura riceve sempre il dato più aggiornato

• Avaliability: relativo al fatto che almeno una copia dei dati sia sempre disponibile ad ogni interrogazione.

• Partition Tolerance: vale a dire che il sistema deve continuare ad operare anche se alcuni nodi, partizioni oppure porzioni di dati, non rispondono correttamente.

(19)

Fig. 2.2 CAP Theorem [6]

Le combinazioni delle proprietà che possono essere soddisfatte sono:

• CA (Consistency & Avaliability): i dati sono sempre consistenti su tutti i nodi e fintanto che il sistema è online, gli utenti potranno sempre leggere e scrivere i dati sui nodi ed essere sicuri che essi siano sempre consistenti su tutti i nodi.

• AP (Avaliability & Partition Tolerance): i dati sono continuamente disponibili anche in caso rottura di uno dei nodi del cluster ma non è garantito che i dati sui nodi siano uguali.

• CP (Consistency & Partition Tolerance): i dati sono consistenti all’interno del cluster e mantiene la partition tolerance a discapito della disponibilità dei dati; se un nodo è rotto oppure semplicemente offline i suoi dati non sono disponibili.

Dalla figura 2.2 si può vedere la distribuzione dei DB, relazionali e non a seconda delle coppie di proprietà che soddisfano. Si può notare come i primi siano associati alla coppia CA (Consistency & Avaliability), in quanto non sono fatti per essere collocati all’interno di un sistema distribuito. Invece, i database NoSQL, sono situati sia sul ramo AP(Avaliability & Partition Tolerance), sia sul ramo CP(Consistency & Partition Tolerance) poiché a seconda

(20)

delle caratteristiche architetturali dei singoli DB, rilassano rispettivamente la proprietà riferita alla consistenza o quella della disponibilità.

2.3

Database relazionali vs NoSQL

Ciò che differenzia sostanzialmente i database relazionali rispetto a quelli NoSQL è il fatto che i primi rispettano le proprietà ACID, mentre i secondi sono sistemi BASE.

Le proprietà ACID, nell’ambito dei database, riguardano le caratteristiche che devono avere le transazioni:

• Atomicity: una transazione viene eseguita in maniera atomica per cui non sono ammesse esecuzioni parziali o incomplete;

• Consistency: dopo ogni transazione, i dati devono rimanere in uno stato di consistenza; • Isolation: ogni transazione deve essere indipendente e isolata rispetto alle altre

transazioni;

• Durability: i risultati di una transazione completata devono essere permanenti all’interno del database.

(21)

Il rispetto di queste proprietà porta, come detto prima, a posizionare questa tipologia di database sul lato CA del CAP Theorem. Questi database sono in grado di effettuare una vasta gamma di transazioni con buone prestazioni sui dataset tradizionali. Invece, parlando di Big Data, le prestazioni decadono in maniera sostanziale. I due limiti principali di questo decadimento delle performance sono:

• la scalabilità verticale

La scalabilità è la proprietà che indica il modo per aumentare le risorse per determinate applicazioni; essa può essere di due tipi: verticale o orizzontale. Si parla di scalabilità verticale quando per aumentare le risorse ad un cluster, si vanno a incrementare le risorse dei singoli nodi, mentre si parla di orizzontale quando si va ad incrementare il numero dei nodi nel cluster. sPer quanto riguarda i database relazionali, si parla di scalabilità verticale. Il limite sta nel fatto che incrementare costantemente le risorse all’aumentare della mole di dati è eccessivamente costoso, poco mantenibile e c’è un limite fisico delle macchine che non può essere superato.

• il modello relazionale

Un ulteriore limite è dato dal modello relazionale in sé, in quanto con l’alta varietà e variabilità dei dati, è difficile mantenere una struttura fissa del modello dati. Un altro fattore importante è la presenza di dati semi e non strutturati che non possono essere gestiti efficacemente da un modello relazionale. Infine, una delle operazioni maggiormente utilizzate nei database relazionali è la JOIN, il cui costo computazionale dipende dalla quantità di dati da analizzare, per cui su grandi volumi di dati, questa operazione è altamente inefficiente.

Invece, i database NoSQL, che si posizionano sugli altri due lati del CAP theroem, AP e CP, sono ottimizzati per poter gestire grandi quantità di dati in maniera efficiente all’interno di un sistema distribuito. Come già detto precedentemente, tutti condividono il fatto di essere Partition Tolerance, ma la maggior parte si posiziona lungo il lato AP rilassando la proprietà della consistenza. Questi ultimi vengono descritti con l’acronimo BASE (Basically Available, Soft-State, Eventually Consistent) dove il concetto fondamentale è quello dell’ Eventually Consistent: il livello di consistenza dei dati è “eventuale”, nel senso che non è immediato ma passa un po’ di tempo prima che le informazioni sui vari nodi vengano aggiornati e resi consistenti.

Tuttavia, i pregi che hanno questi sistemi per poter analizzare una moltitudine di infor-mazioni sono:

(22)

• non essere vincolati al rispetto delle proprietà ACID come i database relazionali; • la scalabilità orizzontale, cioè che a differenza dei database relazionali, per migliorare

le performance non è obbligatorio incrementare le risorse dei singoli nodi del cluster, ma si può scalare anche aggiungendo dei nuovi nodi al cluster. Questo risulta essere più mantenibile e meno costoso;

• costi computazionali distribuiti su più nodi che permettono di eseguire più operazioni più velocemente;

• non essere vincolati ad un modello dati specifico come quello relazionale. I dati semi e non strutturati possono essere, a seconda della tipologia di database utilizzato, gestiti più o meno facilmente. Molti di questi DB non prevedono una struttura definita a priori, per cui anche la gestione di cambiamenti all’interno della struttura informativa dei dati è più agevole rispetto lo schema relazionale;

• un’ultima importante caratteristica è, generalmente, l’assenza dell’operazione di join che necessita una struttura dati relativamente complessa. Questo tipo di operazione non viene più effettuata a livello di database, ma a livello server/client che recupera i dati e ne applica le opportune trasformazioni, tra cui le operazioni di join.

Oltre a queste caratteristiche, che evidenziano come questi database sono più adatte alla realtà dei Big Data, un altro importante fattore è la diversità nella struttura stessa dei DB; questa varietà permette di poter scegliere quale tipologia di database, e quindi anche quale modello dati, meglio si adatti al caso d’uso in esame.

2.4

Classificazione dei database NoSQL

I database noSQL possono essere classificati in 5 categorie[7][8][9]: • Column Oriented

• Document Stored • Graph Based • Key-Value • Multi-Model

(23)

2.4.1

Column Oriented

Fig. 2.4 Struttura dei database Column Oriented

Questi database utilizzano una struttura column oriented, cioè salvano e suddividono i dati per colonne, a differenza dei classici database relazionali che memorizzano le informazioni per righe successive (row - oriented) . Questa soluzione architetturale, permette di effettuare operazioni di lettura e scrittura in modo più veloce, poiché l’accesso puntuale al dato riduce il numero delle operazioni di IO. Il concetto fondamentale per questa famiglia di database è quello di column family store: questo può essere visto come una mappa multidimensionale, 2.4, persistente, ordinata ed indicizzata per row key e column key.

A loro volta le column family si dividono in due macro-categorie: standard e super. Nella prima, la row key identifica l’aggregato che a sua volta mappa una o più famiglie di colonne dove possono essere presenti diversi valori associati ad una diversa column key.

La Super column family è semplicemente un’estensione dello Standard Column Family; questo modello aggiunge un ulteriore livello di indicizzazione fra la row key e l’insieme delle colonne, la cosiddetta super column. Questa chiave viene utilizzata per raggruppare attributi correlati fra di loro, appartenenti allo stesso aggregato. Tale organizzazione ha vari vantaggi fra cui:

• dati più ordinati ed utilizzabili dalle applicazioni; • sharding più efficiente.

Altri vantaggi per questa categoria di database sono:

• i valori in una singola colonna sono memorizzati in maniera contigua e conservati in specifici column datafile;

(24)

• I dati all’interno di ciascun column datafile sono dello stesso tipo, questo li rende ideali per la compressione;

• La memorizzazione per colonna permette di migliorare le performance delle query in quanto permette l’accesso diretto alle colonne;

• Alte performance nelle query di aggregazione (ad esempio COUNT, SUM, AVG, MIN, MAX )

Alcuni esempi di database di questo tipo sono: Cassandra, HBase, Acumulo e Vertiga.

2.4.2

Document Stored

Fig. 2.5 Struttura dei database Document Stored

La differenza sostanziale dai database relazionali e dagli altri NoSQL è che i dati vengono salvati in particolari strutture dati chiamate documenti. Un documento, , come si può vedere nella figura 2.5, contiene una serie di campi, nella forma key-value, in cui vengono salvate le informazioni dei record; i formati più comuni con i quali vengono codificati i dati nei documenti sono i JSON, XML, YAML e BSON.

A differenza delle classiche tabelle del modello relazionale, i documenti sono più flessibili perché non hanno uno schema completamente fisso dei valori che devono salvare, infatti è possibile avere campi più o meno diversi da un documento all’altro. A questa struttura viene associata anche una chiave, un identificativo del documento, che corrisponde ad uno o più campi dei documenti; questa permette di indicizzare e selezionare i documenti molto più velocemente.

Infine, la differenza sostanziale rispetto ai database NoSQL key-value è che questi possono gestire i dati solamente se strutturati o semi-strutturati mentre, i key-value gestisce anche

(25)

quelli non strutturati; infatti i casi d’uso principali per questa famiglia di DB sono applicati alla gestione di dati dati strutturati o semi-strutturati, sparsi, oppure testuali.

Alcuni esempi di questi database sono: MongoDB, AzureDocument DB, Couchbase e CouchDB.

2.4.3

Graph Based

Fig. 2.6 Struttura dei database Graph Based

A differenza dei classici database relazionali e degli altri database NoSQL, i graph based salvano le informazioni sotto forma di un grafo composto da nodi e archi, come si può vedere nella figura 2.6; i nodi corrispondono con i singoli oggetti/record, mentre gli archi le connessioni/relazioni tra i record.

Ogni nodo, potenzialmente, potrebbe contenere informazioni differenti e connessi tra loro grazie a qualche attributo o qualche altro tipo di relazione. Questa struttura permette di mappare facilmente su un grafo i singoli oggetti della programmazione ad oggetti; tuttavia, a differenza degli altri noSQL, questi database vengono utilizzati sopratutto per i casi d’uso in cui l’obiettivo non è vedere le caratteristiche dei singoli oggetti, ma le relazioni che intercorrono tra essi. I Graph based sono più efficienti nell’effettuare operazioni di navigazione all’interno di una rete piuttosto che interrogazioni sulle informazioni contenute nei vari nodi.

(26)

2.4.4

Key-Value

Fig. 2.7 Struttura dei database Key-Value

Questa tipologia di database salva i dati nella forma Key-Value, una struttura dati molto simile a quella dell’array associativo, delle tabelle hash o dei dizionari. In pratica, sono una collezione di record, oggetti ognuno dei quali potenzialmente può contenere dei dati con delle strutture informative differenti, come si può vedere in figura 2.7. Ogni record è composto da una chiave ed un valore; entrambi possono essere composti da uno o più elementi, mentre solamente la chiave permette l’accesso puntuale al dato.

Come appena accennato, i vari record memorizzati possono avere una struttura informativa più o meno eterogenea. A differenza del modello relazionale, dove tutti gli attributi vanno definiti a priori, invece in questi DB vengono salvati esclusivamente solo quelli con valore non nullo; ciò permette di risparmiare spazio, sopratutto nel caso in cui si abbiano dati molto sparsi. Infine questo modello dati, come anche quello dei document base, si concilia molto bene con la programmazione ad oggetti, poiché questi ultimi possono essere facilmente mappati su un singolo record dove i vari campi corrispondono agli attributi dell’oggetto.

Alcuni esempi di database di questo tipo sono: DynamoDB, Redis, Voldemort, Azure table Storage e Oracle NoSQL Database

2.4.5

Multi-Model

L’ultima categoria di database NoSQL è quella dei multi-model. Questa categoria di db si differenzia dalle precedenti perché permette di utilizzare modelli diversi all’interno dello stesso db; come ad esempio i column, key-value, document, relational e graph.

(27)

Tra questa tipologia di DB possiamo trovare: ArangoDB, CortexDB e OrientDB

2.5

Altri Database distribuiti: Hive e Impala

Tuttavia, bisogna specificare che non tutti i database distribuiti sono per forza NoSQL; prendiamo ad esempio Hive ed Impala, due database distribuiti SQL-LIKE. Hive è un data warehouse implementato sopra ad hadoop e che permette di gestire una base di dati in maniera distribuita. In particolare, ad ogni interrogazione corrisponde l’esecuzione di uno o più job map-reduce, il framework di programmazione distribuita descritto nei paragrafi precedenti; la query viene distribuita all’interno dei nodi del cluster ed eseguita in parallelo. Infine, questo database è sql-like poichè utilizza un linguaggio di interrogazione chiamato HiveQL che si basa sullo standard SQL-92.

Un ulteriore database simile ad Hive è Impala. Anche questo non è un database NoSQL, dato che lo standard del suo linguaggio è sempre di impronta SQL, ma a differenza del precedente non utilizza il framework Map-Reduce. Questo database sfrutta un architettura basata sulla Massive Parallel Cumputing (MPP). Ciò si riferisce all’utilizzo in parallelo e coordinato di un insieme di processori o computer o nodi per effettuare una serie di operazioni sincronizzate.

2.6

Apache Cassandra vs MongoDB

Per questo progetto sono stati utilizzati due database NoSQL diversi: Apache Cassandra e MongoDB. Il primo appartiene alla categoria dei Column Oriented, mentre il secondo a quella dei Document Store, ma entrambi vengono utilizzati, in modi differenti, per gestire i dati associati a casi d’uso come le Time Series. Poichè il progetto sviluppato tratta un caso d’uso molto simile a quello delle time series, come verrà poi spigato nei capitoli successivi, si è scelto di valutare quale di questi due fosse il più adatto.

(28)

Fig. 2.8 Logo Apache Cassandra [10]

2.7

Apache Cassandra

The Apache Cassandra database is the right choice when you need scalability and high avail-ability without compromising performance. Linear scalavail-ability and proven fault-tolerance on commodity hardware or cloud infrastructure make it the perfect platform for mission-critical data.Cassandra’s support for replicating across multiple datacenters is best-in-class, pro-viding lower latency for your users and the peace of mind of knowing that you can survive regional outages.[10]

Apache Cassandra è uno dei principali database open-source utilizzati in ambito Big Data. Nasce da un progetto sviluppato da Avinash Lakshman e Prashant Malik presso Facebook. L’obiettivo era quello di trovare una soluzione per migliorare e potenziare la ricerca all’interno del sistema di messaggistica; è stato pubblicato da Facebook come progetto open-source nel 2008, mettendolo su Google Code e nel marzo del 2009 è stato inserito nel progetto Incubator di Apache Software Foundation e distribuito con la Apache License 2.0. Apache Cassandra è stato implementato per poter gestire grandi quantità di di dati non strutturati, semi strutturati e strutturati in un ambiente distribuito su più nodi; questi pos-sono essere dislocati anche in diversi data center o in cloud. Cassandra garantisce una disponibilità continua dei dati, scalabilità lineare e no single point of failure dei nodi che compongono il cluster; inoltre, ha un data model progettato per essere molto flessibile e veloce nell’esecuzione delle query, soprattutto per quelle di scrittura.

Ci sono 4 caratteristiche fondamentali, per cui cassandra riesce a gestire petabytes di informazioni e migliaia di operazioni al secondo:

(29)

• Partitioned row store database: l’architettura di questo DB permette a qualsiasi utente di creare ed interrogare keyspace cioè tabelle che vengono utilizzate attraverso uno specifico linguaggio di interrogazione chiamato CQL. Le tabelle e i KeySpace sono partizionati e distribuiti in tutti i nodi del cluster e ciò permette di velocizzare le operazioni poiché queste vengono distribuite in maniera equa sul cluster.

• Automatic data distribution: Cassandra provvede a distribuire i dati nei nodi che partecipano al ring o nel cluster.

• Built-in and customizable replication: Cassandra, inoltre, provvede un sistema per definire, per ogni keyspace, il numero di repliche dei dati. Queste vengono distribuite su più nodi che partecipano al ring, cosicché, se un nodo ad un certo momento è down, i dati di quel nodo sono salvati in altre repliche su altri nodi. Il fattore di copia può essere definito sia per i keyspace, sia per i data-center in cui è installato il cluster. • Linear Scalability: Cassandra è un database che permette di ottenere delle prestazioni

che scalano in maniera lineare; ciò significa che per migliorare le performance basta semplicemente aggiungere dei nodi, non necessariamenti super performanti.

Nei paragrafi seguenti verrà analizzato il linguaggio di interrogazione (CQL), l’architettura del db, le sue componenti principali e il data model. [11] [12]

2.7.1

CQL

Cassandra Query Language (CQL) è il linguaggio di interrogazione principale per Apache Cassandra. Questo è molto simile al linguaggio SQL utilizzato nei database relazionali, en-trambi condividono l’idea di gestire delle tabelle strutturate in una serie di attributi (colonne) e contenenti una serie di record (righe). La differenza principale è che Cassandra non sup-porta le operazioni di JOIN e le subqueries, mentre ha una serie di features che permettono di gestire efficacemente le collezioni, tipi di attributi definiti dagli utenti (UTD), il partiziona-mento e l’ordinapartiziona-mento dei record attraverso le colonne di clustering; tutte queste features devono essere specificate nello schema della tabella al momento della sua creazione. Questo linguaggio è il più raccomandato per l’interazione con Cassandra date le performance e la semplicità di lettura e scrittura delle query.

La modalità più semplice per interagire con cassandra è la CQL shell; per aprire la shell basta eseguire il comando cqlsh nel terminale di sistema. Attraverso questo comando è possibile connettersi al database di Cassandra in locale oppure su quello di altre macchine specificando l’indirizzo e la porta per la connessione. Una volta aperta la CQL shell, è

(30)

possibile creare keyspace e tabelle, inserire, aggiornare, cancellare e ricercare i dati all’interno di esse e molto altro. Di seguito ci sono alcuni esempi dei principali statement CQL:

INSERT INTO keyspace_name . table_name ( i d e n t i f i e r , column_name . . . ) VALUES ( value , v a l u e . . . ) IF NOT EXISTS USING o p t i o n AND o p t i o n

UPDATE keyspace_name . table_name USING o p t i o n AND o p t i o n SET assignment , assignment , . . . WHERE r o w _ s p e c i f i c a t i o n IF

column_name = l i t e r a l AND column_name = l i t e r a l . . . IF EXISTS DELETE [ column_name [ , column_name ] [ . . . ] | column_name [

term ] ] FROM [ keyspace_name . ] table_name [ USING TIMESTAMP timestamp_value ] WHERE r o w _ s p e c i f i c a t i o n [ IF [ EXISTS | c o n d i t i o n [ AND c o n d i t i o n ] [ . . . ] ] ]

TRUNCATE keyspace_name . table_name

DROP TABLE IF EXISTS keyspace_name . table_name USE keyspace_name

Considerando questi statement, bisogna fare un breve considerazione sull’utilizzo delle condizioni di WHERE. Qui è possibile inserire, come accade nei comuni database relazionali, una o più restrizioni sulle colonne. La differenza sostanziale rispetto ai database relazionali è l’ordine con cui vengono messe:

• le prime devono essere esclusivamente sulle colonne che appartengono alla PARTI-TION KEY e possono essere restrizioni di uguaglianza o di appartenenza ad un insieme ( clausola IN);

• le seconde devono essere quelle relative alle clustering column e possono essere restrizioni del tipo =, < o > . Queste, nel caso di più partition columns, devono essere poste seguendo l’ordine definito nella primary key.

Infine, la distribuzione di Datastax fornisce una serie di driver per poter interagire con Apache Cassandra anche dai principali linguaggi di programmazione, come ad esempio Java, Python e tanti altri.

(31)

2.7.2

Architettura

Cassandra è progettato per poter supportare e gestire una grande quantità di dati e di operazioni senza incorrere in nessun single point of failure; ciò è possibile perché Cassandra si basa su un’architettura peer to peer all’interno di un sistema distribuito. Tutti i nodi del cluster hanno lo stesso ruolo e partecipano in maniera eguale; infatti, non c’è una struttura, come in MongoDB, in cui ci sono i nodi Master che coordinano e distribuiscono il carico di lavoro sui nodi Slave. I dati vengono distribuiti lungo i nodi del cluster e questi comunicano tra di loro scambiandosi le informazioni sullo stato del cluster e sui dati ogni secondo. Per cui le due componenti più significative dell’architettura riguardano come i dati vengono replicati e distribuiti lungo i nodi e come questi si scambiano le informazioni.

Internode Communication

I nodi del cluster comunicano tra di loro attraverso un protocollo chiamato Gossip. Questo è un protocollo di comunicazione peer-to-peer attraverso il quale i nodi inviano le informazioni sul loro stato oppure su quello degli altri nodi di cui sono a conoscenza. Questo processo viene effettuato ogni secondo tra almeno tre dei nodi presenti nel cluster; questi scambiano le informazioni che riguardano loro stessi e quelle relative ai nodi di cui hanno avuto notizia attraverso una precedente messaggio di gossip. In questo modo, tutti i nodi sono a conoscenza dello stato degli altri nodi, non simultaneamente, ma in maniera molto veloce. Inoltre, per evitare incongruenze nei messaggi scambiati, ad ogni messaggio è associata una versione e ogni qual volta un nodo riceve un messaggio con una versione più recente sovrascrive quello vecchio, per evitare di inviare informazioni non aggiornate.

Questo processo, permette di trovare facilmente se un nodo è “down” ovvero che ha avuto un qualche errore per cui non è più attivo; grazie a questo protocollo è possibile sapere in breve tempo quale nodo sia inattivo e per quale ragione, in modo da poter correggere l’errore e riattivare il nodo. Quando il nodo viene riattivato, questo manda un messaggio agli altri nodi, informandoli che è tornato disponibile.

Data distribution and replication

Il modo in cui i dati vengono distribuiti tra i nodi è legato al sistema/alla maniera in cui questi vengono replicati all’interno del cluster. I fattori che vanno ad incidere sulla replicazione sono:

• Virtual node • Partitioner

(32)

• Replication Strategy • Snitch

I dati vengono distribuiti e ripetuti nei nodi appartenenti al cluster; tuttavia distribuire i dati su un numero basso di nodi non porterebbe grandi vantaggi, per questa motivazione vengono utilizzati i virtual nodes. Ad ogni nodo del cluster vengono assegnati n nodi virtuali, di default 256, sui quali i vengono distribuiti i dati alla stessa maniera dei nodi fisici; così facendo, ad esempio, in un cluster a 6 nodi, i dati vengono distribuiti e replicati non solo su 6 nodi ma su 6*256 nodi.

Ad ogni nodo è assegnato un certo range di valori di cui è responsabile, questo viene calco-lato in base ad opportune hash functions che mappano i valori della chiave di partizionamento in un insieme di interi. Quindi, un nodo è responsabile di un certo insieme di partizioni che vengono poi ripetute sugli altri nodi a seconda del fattore di replica impostato; così facendo, quando un nodo è “down”, i suoi dati sono replicati su altri e quindi ancora reperibili.

(33)

L’immagine 2.9 mostra due tipologie di cluster ben distinte: entrambe sono composte da 6 nodi fisici. Nella prima soluzione, non ci sono virtual nodes e il ring del cluster è suddiviso in 6 parti, ognuna delle quali ha associato una lettera (token) che corrisponde al valore assegnato dalla funzione hash per distribuire le partizioni: in questo caso il numero di token coincide con il numero di nodi fisici proprio perchè non sono presenti i virtual nodes. Assumendo che ad un token corrispondono una o più partizioni, si può vedere come ad ogni nodo fisico corrispondono solamente tre token ed ogni token viene replicato su tre nodi differenti: ad esempio il token C viene copiato sui nodi 3,4 e 5.

La seconda soluzione sfrutta la presenza dei virtual nodes e già osservando il ring si può notare come il numero dei token sia superiore rispetto alla soluzione precedente. Questo perché ogni nodo fisico può contenere n virtual nodes ( in questo caso 2), ad ognuno dei quali è assegnato un token e un insieme di partizioni da gestire. Osservando poi la distribuzione dei token nei nodi fisici, si nota come il numero dei primi è associato ad ogni nodo sia superiore rispetto a prima nonostante questi siano sempre riprodotti 3 volte: il token B è replicato sui nodi 1,4 e 6. Questa soluzione permette di distribuire e reiterare i dati più efficacemente perché la dimensione dei vari token è inferiore rispetto la soluzione precedente.

Si è detto che ciò che determina come i dati vengono distribuiti nel cluster sono delle particolari funzioni hash che assegnano un valore ad ogni partizione e ad ogni nodo un range di tali valori, tali funzioni sono chiamate partitioners. La funzione più comunemente utilizzata è la murmur3 Partitioner che sfrutta le murmur Hash functions permettendo di ottenere un range di valori che va da 263 a 263-1.

Invece, ciò che determina la replicazione dei dati è la strategia di ripetizione scelta. Cassandra permette di impostare,per ogni keyspace, sia un fattore di replica ( replication factor) che indica quante copie dei dati sono presenti sul cluster, sia la strategia che indica come questi vengono replicati nel cluster. Ci sono due strategie disponibili:

• SimpleStrategy: questa strategia implica l’utilizzo di un unico data-center e la prima duplicazione viene scritta sul nodo determinato dal partitioner e le altre sui nodi adiacenti;

• NetworkTopologyStrategy: questa strategia comporta l’utilizzo di più data center e permette di specificare il numero di repliche per ognuno di essi.

Infine, l’ultima componente architetturale che incide sul comportamento dei nodi è lo snitch: determina a quale data center e a quali rack appartengono i vari nodi. Cassandra, quindi, permette di distribuire le copie raggruppando i nodi in data center e racks.

(34)

Write Path

Per poter capire come Cassandra gestisce e rende accessibile i dati è bene conoscere come questi vengono memorizzati.

Per quanto riguarda il processo di scrittura del dato ( write path), Cassandra processa i dati utilizzando una serie di step:

• scrittura dei log delle operazioni effettuate in appositi commit log; • scrittura dei dati sulle memtable;

• flushing dei dati dalle memtable;

• storicizzazione dei dati sul disco in apposite SSTables; • compaction.

Fig. 2.10 Write Path

Nella figura ?? è mostrato il “WritePath” di Cassandra. Quando occorre un’operazione di scrittura, Cassandra memorizza i dati in una struttura in memoria (Memtable) e allo stesso tempo aggiunge questa operazione in un commit log sul disco. La Memtable è una sorta di “write-back cache of data” e i dati hanno la stessa struttura delle tabelle che sono presenti sul disco; in entrambi i casi sono suddivisi per la partition key ed ordinati per le clustering columns.

Quando la Memtable raggiunge la sua dimensione massima, opzione presente nel file di configurazione del cluster, viene eseguito il “flush” della tabella, ovvero la scrittura dei dati della Memtable in una SStable; così facendo si libera lo spazio in memoria per poter effettuare altre operazioni di scrittura. Una volta che tutti i dati sono stati inseriti dentro le SSTable, i

(35)

commit log corrispondenti vengono eliminati. Le differenze tra le due tabelle , Memtable e SStable, sono che la prima è una tabella che viene salvata e mantenuta in memoria, essa è mutabile, mentre la seconda è salvata sul disco ed è immutabile; una partizione, di solito, viene scritta su più SStable. Per ogni SSTable, Cassandra crea una serie di strutture che verranno utilizzate nel Read Path:

• Partition Index • Partition Summary • Bloom Filter

Infine, l’ultima fase del write path è la Compaction e questa è essenziale perché Cassandra non effettua operazioni di insert/update/delete direttamente sulle SSTable, perchè queste sono immutabili. Per cui, quando avviene una di queste operazioni, viene scritto un nuovo record associato ad un timestamp e scrive questi record in altre SSTable; lo step di compaction serve per gestire l’accumulo delle SSTable compattando in maniera opportuna i dati. Il comportamento è analogo anche per le operazioni di delete, i dati da cancellare non vengono eliminati immediatamente ma sono marcati come tombstone.

Il processo di compaction è descritto nella figura 2.11 e si può vedere come a partire da un insieme di SSTable, queste vengono unificati in un’unica SSTable. I dati vengono uniti per chiave di partizionamento e vengono selezionati solo quelli più recenti basandosi sul timestamp associato. Inoltre vengono cancellati i dati marcati come tombstones e una volta scritta l’unica SSTable finale vengono eliminate tutte le altre SSTable.

(36)

Tuttavia, bisogna aggiungere qualche considerazione sul trattamento delle operazioni di update. Queste vengono sempre gestite come se fossero delle operazioni di upsert: se il record ha la stessa primary key di uno già presente, quest’ultimo viene sovrascritto con quello nuovo altrimenti viene inserito. Questa operazione viene effettuata grazie allo step di compaction che appunto permette di unire i dati di diverse SSTable aggiungendo quelli nuovi oppure considerando quelli più recenti nel caso di duplicati.

Read Path

Per soddisfare le operazioni di lettura, Cassandra deve combinare sia quelli contenuti nelle molteplici SSTable, sia quelli memorizzati nelle Memtable. Per prima cosa, viene controllato se nelle SSTable sono contenuti alcuni record della partizione richiesta, questa operazione viene effettuata interrogando i BloomFIlter associati ad ogni SSTable:

• se il risultato è positivo, Cassandra controlla la “partition key cache”:

– se si ha un indice associato a quella partizione, Cassandra recupera la posizione del blocco dei dati dalla Compressio offset Map; la posizione indica in che punto della SSTable sono salvati i dati della partizione richiesta. altrimenti:

* Cassandra legge dalla Partition Summary per determinare in maniera ap-prossimata la posizione sul disco della partizione richiesta all’interno della Partition Index

* Dalla partition index recupera il range degli offset in cui sono salvati i dati richiesti ed interroga la “Compression Offset Map” per recuperare la posizione sul disco degli offset ottenuti;

* legge in maniera puntuale i dati sul disco

• se il risultato è negativo non viene effettuata alcuna operazione di I/O su quella tabella, poiché c’è la certezza che quella tabella non contiene i dati richiesti.

Tuttavia, come è stato detto nel capitolo precedente, Cassandra non garantisce la consis-tenza dei dati, per cui in fase di lettura si potrebbe avere una situazione di inconsisconsis-tenza dei dati: ci potrebbero essere più versioni dello stesso dato su nodi diversi. In questi casi, si può impostare il livello di consistenza desiderato, sia per le operazioni di scrittura, sia per quelle di lettura. Le due tabelle 2.13 e 2.15, mostrano nel dettaglio le opzioni di consistenza disponibili:

(37)

Fig. 2.12 Read Path

(38)
(39)

Fig. 2.15 Read Consistency Level

La combinazione di tali opzioni sulle operazioni di lettura e scrittura può portare a garantire efficacemente la consistenza dei dati (STRONG CONSISTENCY); ad esempio, se si impostano entrambi i livelli ad ALL, saremo sicuri di scrivere e leggere gli stessi dati su e da tutte le repliche; analogamente se si impostano entrambi a QUORUM, verranno scritti e letti i dati sulla e dalla maggioranza delle repliche. Invece, un modo ancora più veloce per garantire la STRONG CONSISTENCY è quello di utilizzare ONE per le operazioni in scrittura e ALL per quelle in lettura; così facendo viene scritto il dato più nuovo solo su una replica, ottimizzando quindi le operazioni di scrittura, e vengono letti i dati da tutte in modo da essere certi di avere sempre tutti i dati, compresi quelli più nuovi.

(40)

2.7.3

Data Model

Le componenti per la modellazione dei dati in cassandra sono: • KeySpace • Tabella • Primary Key – Partition Columns – Clustering Columns • Indici KeySpace

Nel modello NOSQL a colonne, i keyspace viene definito come:

keyspace (or key space) in a NoSQL data store is an object that holds together all column families of a design.

In pratica, è l’oggetto più esterno del modello, cioè quello che contiene le tabelle, Column-Family e SuperColumnColumn-Family.

Di solito viene creato un keyspace per ogni applicazione che si vuole implementare. Questa struttura è molto simile a quella dei database del modello relazionale.

La creazione del keyspace avviene attraverso il seguente comando:

CREATE KEYSPACE keyspace_name WITH REPLICATION = map AND DURABLE_WRITES = ( t r u e | f a l s e )

Il parametro map fa riferimento ad una mappa di parametri aggiuntivi in cui vengono specificate una serie di proprietà, le due essenziali sono:

• class: identifica la strategia di replicazione dei dati all’interno del cluster. • replication_factor: indica il numero di repliche dei dati nel cluster

A queste poi si possono aggiungere altre proprietà a seconda delle necessità e soprattutto a seconda della strategia di replicazione del cluster. Ad esempio, se si utilizza ’class’ : ’NetworkTopologyStrategy’, ’dc1’ : 3, ’dc2’ : 2, significa che ci si avvale della strategia

(41)

Fig. 2.16 KeySpace

NetworkTopologyStrategy dove è possibile indicare il numero di repliche che si vogliono per ogni cluster: in questo caso 3 per il dc1 e 2 per il dc2 per un totale di 5. Inoltre, per questa strategia si possono settare delle policy di accesso e distribuzione dei dati. Ad esempio, se un keyspace viene replicato su più nodi sparsi per l’europa, è possibile definire delle policy di accesso che permettono di accedere prima ai nodi più vicini, oppure ai nodi che offrono meno latenza o anche distribuire in maniera equilibrata gli accessi e i dati ai nodi per evitare sovraccarichi.

Tabelle

Le tabelle corrispondono alle column family e vengono definite coma una mappa multidi-mensionale indicizzate da una chiave, la Row Key.

Le tabelle sono costituite da una serie di colonne in cui una è quella per cui vengono in-dicizzati i dati. Tuttavia una tabella non viene salvata in un unico blocco come accadeva nei database relazionali, ma viene distribuita e replicata sui vari nodi. Il modo per cui è possibile fare ciò è dato dal concetto di partizione: una porzione di dati indicizzata su una o più colonne chiamate Partition Columns. Inoltre, i dati delle tabelle vengono anche ordinati

(42)

nel momento che vengono inseriti, questo perchè ci sono altre colonne, chiamate Clustering column, che determinano l’organizzazione dei dati.

Ad ogni tabella è associata una Primary Key che è composta dalle partition column e , se definite, dalle clustering columns; questa è univoca e serve per identificare univocamente ogni record.

Lo statement CQL per la creazione delle tabelle è il seguente

CREATE TABLE IF NOT EXISTS keyspace_name . table_name ( c o l u m n _ d e f i n i t i o n , c o l u m n _ d e f i n i t i o n , . . . , PRIMARY

KEY( ( p a r t i t i o n column_1 , p a r t i t i o n column_2 , . . . ) , c l u s t e r i n g column_1 , c l u s t e r i n g column_2 , . . . ) ) WITH p r o p e r t y AND

p r o p e r t y . . .

Partition Column

Le partition column sono le colonne per cui vengono suddivise in partizioni le tabelle. Queste colonne vengono definite in fase di creazione e fanno parte della primary key della tabella. In, pratica una tabella viene suddivisa in n partizioni a seconda delle n combinazioni dei valori delle colonne selezionate. Di default, nella primary key, viene impostata la prima colonna come colonna di partizione ma è possibile specificare più colonne.

Queste colonne sono essenziali nella gestione del db, poiché permettono di dividere le colonne in più parti e di poter distribuire queste partizioni sui vari nodi e nelle varie repliche. Una tabella, e di conseguenza anche il keyspace, viene distribuita su più nodi, nel senso che le varie partizioni vengono distribuite nei nodi del cluster.

Clustering Column

Le clustering Column invece sono opzionali, nella definizione della tabella, e nel caso ci siano, servono per ordinare i dati all’interno delle partizioni; per cui i dati vengono organizzati in fase di scrittura e le tabelle risultano essere sempre ordinate. I dati possono essere disposti in maniera ascendente o discendente, come nei normali database relazionali e l’ordine delle colonne e il modo con cui ordinare i dati è definito in fase di creazione della tabella.

Index

In Cassandra, è permesso definire degli indici sulle colonne che non fanno parte della partition key, anche dopo la creazione della tabella; ciò permette di velocizzare le operazioni

(43)

che utilizzano tali colonne. Tuttavia, è bene definire gli indici su quelle colonne che hanno un numero non eccessivo di valori, non hanno frequenti operazioni di update/delete e nelle tabelle non hanno valori di tipo counter.

(44)

Fig. 2.17 Logo MongoDB [13]

2.8

MongoDB

MongoDB è un database NoSQL orientato ai documenti. Esso si allontana dalla classica concezione del sistema relazionale sfruttando i documenti in formato JSON e BSON con uno schema più dinamico e veloce nell’integrazione del dato.

Lo sviluppo di questo database è iniziato nel 2007 dall’azienda 10gen con l’intento di creare un platform as a service simile a WIndows Azure o Google App Engine. Nel 2009, l’azienda ha cambiato i suoi piani di Business fornendo tale prodotto con licenza OpenSource e offrendo supporto tecnico, commerciale e altri servizi associati. La prima release considerata “production ready” è la 1.4, distribuita a partire dal Marzo 2010, mentre l’ultima release rilasciata è la 3.2 e la 3.4 è pronta per essere distribuita nel prossimo futuro. Le versioni sono distribuite sotto la GNU Affero General Public License, mentre i driver sono forniti con la Apache License; in aggiunta MongoDB offre servizi di supporto, sia tecnico che commerciale e licenze commerciali con tool per la gestione aggiuntivi.

MongoDB si contraddistingue per una serie di caratteristiche:

• query ad hoc: MongoDB offre un linguaggio di interrogazione che permette di effettuare ricerche specifiche per campi, intervalli e anche regular expression. Le query inoltre possono restituire sia interi documenti, sia campi specifici del documento e si

(45)

possono definire anche delle funzioni custom, scritte principalmente in javascript, da integrare nelle query;

• indicizzazione: l’indicizzazione è molto simile a quella utilizzata nei tradizionali RDBMS; qualsiasi tipologia di campo può essere indicizzata, si possono definire sia indici su campi singoli sia su campi multipli, inoltre nelle ultime versioni, sono stati aggiunti degli indici specifici per i campi testuali e geospaziali;

• alta affidabilità: in generale, l’architettura di un cluster MongoDB è costituita da un nodo Master e n nodi Slave e la distribuzione del carico di operazioni viene gestita attraverso i replica set. Ad ogni nodo è associata una replica che si può comportare come primaria o secondaria a seconda del ruolo del nodo; quella primaria può effettuare tutte le operazioni di scrittura e lettura, mentre quelle secondarie solo quelle di lettura. Così facendo il carico delle operazioni viene distribuito dal nodo master, e quando questo fallisce ne viene eletto un altro tra quelli disponibili;

• sharding e bilanciamento dei dati: MongoDB scala orizzontalmente utilizzando la tecnica dello scharding. In pratica, le collezioni vengono divise in intervalli basandosi sulla chiave di shard impostata e distribuiti su molteplici shard. Uno shard è un replica set, quindi con una replica primaria e due o più repliche secondarie. I dati poi vengono nuovamente bilanciati in modo automatico così da mantenere una equa distribuzione dei dati all’interno del cluster;

• aggregazione: MongoDB ha al suo interno un Aggregation Framework che permette di effettuare delle operazioni di aggregazione all’interno delle query.

Nei prossimi paragrafi verranno descritte più nel dettaglio l’architettura, il data model e alcuni esempi di interrogazioni disponibili [13].

2.8.1

Architettura

L’architettura di MongoDB è stata scelta in modo da garantire, principalmente, due proprietà: l’alta affidabilità e la scalabilità orizzontale. La prima viene garantita attraverso il concetto di “replica set”, ovvero un insieme di server che mantengono lo stesso dataset; ciò significa replicare i dati su più nodi, garantendo quindi una alta disponibilità del dato anche in caso di fallimento di uno o più server. Invece, la seconda viene garantita attraverso il concetto dello sharding, ovvero una particolare metodologia per distribuire i dati lungo i nodi del cluster. Nei prossimi due paragrafi verranno analizzati nel dettaglio questi due concetti.

(46)

Replica Set

Un Replica Set in mongodb è un insieme di istanze mongod, che conservano gli stessi dati; un’istanza mongod è una macchina in cui è attivo il servizio di MongoDB.

Un sistema in cui si utilizzano i replica set, permette di garantire l’alta disponibilità dei dati a discapito di un fattore di replicazione; questa è l’architettura basilare per un cluster di produzione.

La replicazione dei dati incrementa il loro grado di disponibilità, poiché questi vengono copiati su più server. In alcuni casi, la replicazione può incrementare anche la capacità delle operazioni di lettura che un client può effettuare; questo perchè si possono copiare i dati in più data center, anche più vicini ai clienti, e dedicare alcune di queste copie a necessità ben precise, come ad esempio disaster recovery, reporting o backup. Si è detto che una replica è un insieme di istanze, nodi in cui è in esecuzione un processo mongod e in cui sono condivisi gli stessi dati. A differenza di Apache Cassandra, in cui ogni nodo ha la stessa importanza e l’architettura è di tipo peer to peer, in MongoDB esiste un nodo primario (Master) e n nodi secondari (Slave); la figura 2.18 mostra tale architettura.

(47)

Un replica set può avere al massimo un nodo primario e n nodi secondari; quando il nodo primario non è disponibile, i nodi secondari procedono con “un’elezione” per scegliere il nuovo nodo primario, come mostrato nella figura successiva.

Fig. 2.19 Election

La replicazione dei dati sui nodi secondari avviene in maniera asincrona, e le operazioni di scrittura incidono esclusivamente sul nodo primario. Invece, per le operazioni di lettura di default, sono indirizzate esclusivamente sul nodo primario; è possibile specificare sui client delle opzioni di lettura in cui specificare se leggere o meno anche dai nodi secondari e, nel caso, anche da quale. Il fatto che i nodi secondari aggiornano i loro dati in maniera asincrona, potrebbe portare ad una lettura di dati non ancora aggiornati.

Sharding

Lo sharding è un metodo per distribuire i dati su più macchine appartenenti allo stesso cluster.

A database architecture that partitions data by key ranges and distributes the data among two or more database instances. Sharding enables horizontal scaling.

Nella figura 2.20 si può osservare la struttura di un cluster MongoDB sharded; questo è composto da:

• shard • mongos

(48)

• config server

Fig. 2.20 Sharded Cluster

Ogni shard contiene un sottoinsieme dei dati appartenenti al cluster; tutti assieme con-tengono l’intero dataset del cluster e possono essere istanziati come replica set per garantire l’alta affidabilità. Le query possono essere eseguite sia sull’intero cluster sia sui singoli shard, in quest’ultimo caso però, si potrà ottenere solo il subset di dati assegnato allo shard interrogato. Inoltre, ogni database ha uno shard primario che contiene tutte le non-sharded collection di quel database, questo perchè lo sharding avviene a livello di collezioni e non di database, quindi in un db ci possono essere delle collezioni divise in più shard e altre no.

Per distribuire i dati di una collezione su più shard va definita la chiave di sharding (Shard Key). Questa viene scelta impostando uno o più campi dei documenti della collezione; gli unici vincoli sono che questa chiave deve essere immutabile, non può essere cambiata e i campi devono essere presenti in tutti i documenti. la scelta di tale chiave va ad incidere sulle performance, l’efficienza e la scalabilità del cluster. I vantaggi principali nell’utilizzare un cluster sharded sono:

• mongodb distribuisce sia le operazioni di scrittura sia quelle di lettura sui singoli shard del cluster;

• distribuire la quantità di dati da salvare sui nodi, evitando di replicare la totalità di dati su tutti;

(49)

• alta affidabilità, se configurato anche come replica set.

Infine, le altre due componenti del sharded cluster sono il configServer e le istanze mongos. Il primo semplicemente memorizza i metadati e le configurazioni del cluster, mentre il secondo funge da router per distribuire le operazioni di scrittura e lettura sui singoli shard, come mostrato nella figura 2.21.

Fig. 2.21 Operations in a Sharded Cluster

2.8.2

Data Model

MongoDB è un database NoSQL documentale per cui i dati non vengono memorizzati come record all’interno di una tabella ma come documenti in un formato binario chiamato BSON (Binary JSON). Questa codifica estende il più comune formato JSON per poter includere nuovi tipi, come ad esempio integer,long, date e floating point. Infine, un documento BSON può contenere uno o più campi, ognuno dei quali può includere un valore specifico di un certo tipo, un array, un valore binario oppure altri documenti.

I documenti che condividono una struttura simile vengono organizzati in “collections” e queste a loro volta sono organizzate in database. La differenza sostanziale rispetto al modello relazionale è che in questo DB non è possibile effettuare operazioni di JOIN per concatenare il contenuto informativo di più collezioni ma, per ovviare a questa operazione, nel modello documentale è preferibile annidare i documenti (Embedded Document, figura 2.22) e le informazioni in modo da avere sempre tutti i dati nello stesso documento. Questa tipologia di modellazione si avvicina molto alla struttura delle classi nella programmazione ad oggetti e ne facilita la gestione con questa tipologia di linguaggi; idealmente un documento può rappresentare una classe e i suoi campi gli attributi di tali oggetti.

(50)

Fig. 2.22 Document

In generale, è bene utilizzare la struttura annidata quando ci sono delle relazioni tra le entità del modello del tipo one-to-one e one-to-many, viceversa non è consigliato utilizzarli se ci sono relazioni del tipo many-to-many oppure non si vogliono duplicare i dati all’interno delle collezioni.

I documenti non hanno una struttura statica e ben definita, ma possono variare anche all’interno della stessa collezione, ciò nasce dalla necessità di gestire dati semi strutturati e strutturati allo stesso tempo. Infatti, anche all’interno della medesima collezione, i documenti possono avere dei campi diversi l’uno dall’altro poiché non è necessario definire a priori la struttura. Inoltre, si possono aggiungere e rimuovere campi a seconda delle necessità, per uno, pochi, molti o tutti i documenti nella collezione senza andare ad influire sugli altri o sulle performance del sistema. Tuttavia, i documenti hanno una dimensione massima consigliata di 16 Mb oltre la quale si verifica un decadimento sostanziale delle performance delle operazioni di ricerca,scrittura e lettura. Questo potrebbe limitare in maniera sostanziale la quantità di documenti che è possibile annidare, dal momento che quello più esterno non può superare tale dimensione; per ovviare a ciò si può dividere i documenti in più collezioni ed effettuare le operazioni di JOIN lato client.

Infine, un’altra componente molto rilevante nella modellazione dei dati è costituita dagli indici. Come è stato accennato nel precedente paragrafo, MongoDB offre una vasta gamma di indici che servono a rendere più performanti la maggior parte delle operazioni sulle collezioni.

(51)

La funzionalità di base è analoga a quella dei classici RDBMS ma la gamma delle tipologie di indicizzazione è più ampia:

• Unique Index: definendo un indice come “unique”, MongoDB non permette oper-azioni di insert o update di un documento che ha come indice uno già presente. Di default, gli indici non sono impostati come unique e se un indice è composto da più di un campo e questo viene impostato ad unique, deve essere unica la combinazione di tali valori.

• Compound Index: è possibile creare indici composti da più campi. Questi sono utili soprattutto quando vengono effettuare delle query di update/ricerca che hanno più condizioni di filtering (molteplici predicati nella condizione di where); di norma, si va a definire un indice contenente tutti i campi che sono messi nelle condizioni di filtering e nel caso di query diverse si implementano più indici.

• Array Index: per i campi che contengono un array, ogni valore di tale array è mappato su una voce dell’indice.

• TTL Index: Time To Live index, permettono all’utente di specificare il periodo di tempo dopo il quale i dati devono essere automaticamente cancellati.

• Geospatial Index: MongoDB supporta degli indici geospaziali per ottimizzare le query legate ad operazioni spaziali. In particolare, ottimizzano quelle query che vanno a ricercare documenti che contengono punti o poligoni che sono vicini o intersecano altri punti, linee, poligoni, rettangoli o cerchi.

• Partial Index: in questa tipologia di indici si può specificare una “filtering expression” durante l’inizializzazione dell’indice e l’utente può istruire mongoDB nell’includere nella ricerca solo i documenti che soddisfano tale indice.

• Sparse Index: poiché non tutti i documenti devono avere gli stessi campi, questi servono per indicizzare i campi che non sono presenti in tutti i documenti; in pratica, contengono solo le voci relative ai documenti che contengono i campi specificati. • Text Search Index: questo é un indice specializzato nella ricerca testuale il quale

utilizza operazioni avanzate di semantica per ricercare quali documenti e/o campi contengono determinate parole. L’ordine con cui vengono restituiti i documenti, a differenza degli altri casi, è dato dal grado di rilevanza della ricerca.

Riferimenti

Documenti correlati

Questo elaborato si concentrerà sulla parte di elaborazione dei dati tramite il framework Apache Spark, ponendo in secondo piano la parte di archiviazione sul file system distribuito

Le pale del mozzo modificano l’energia cinetica del vento in energia

Va tenuto conto inoltre che la potenza termica resa dalla pompa di calore dipende dalla temperatura a cui la stessa assorbe calore..

La carta semilogaritmica o grafico semilogaritmico indica un grafico con un asse con scala lineare e un asse con scala. logaritmica (tipicamente in base 10). Usi dei

n  DBMS (Database Management System = Sistema di gestione della Base di Dati): componente software che interagisce con la Base di Dati e con i programmi applicativi degli utenti..

Le tabelle sono usate in quanto permettono di ordinare i dati e di poterli leggere e confrontare molto facilmente.. Ad esempio, nella tabella che segue, abbiamo riportato le

• • Se il risultato del test di ipotesi SUPERA Se il risultato del test di ipotesi SUPERA il il valore critico, allora la valore critico , allora la differenza fra i gruppi

è necessario che ciascuna unità della popolazione abbia la stessa probabilità di entrare a far parte del campione Idealmente estrarre un campione casuale è come pescare una