(articolo redatto da Vito Carrozza)
Il concetto di data storage rappresenta uno dei pilastri più critici per le architetture software enterprise. Con la crescita esponenziale del volume di dati prodotti e gestiti dalle aziende, la capacità di immagazzinare, processare e accedere a questi dati in modo efficiente e affidabile è diventata una sfida cruciale.
In questo contesto, le architetture di data storage devono garantire non solo la capacità di gestire grandi volumi di dati, ma anche di mantenere standard di qualità adeguati al panorama tecnologico odierno.
Questo articolo si propone di esplorare in profondità i diversi approcci al data storage su larga scala, focalizzandosi sulle tecniche e sulle tecnologie di maggiore rilevanza per questo scopo.
Database Relazionali
I database relazionali sono stati il fulcro delle architetture di data storage per decenni. Questi sistemi, basati sul modello relazionale introdotto da Edgar F. Codd negli anni ’70, organizzano i dati in entità interconnesse tra loro mediante relazioni.
In un database relazionale, le entità vengono implementate mediante delle tabelle aventi un certo aspetto intenzionale (detto anche “struttura” o “schema”) che è ciò che le righe di questa tabella (dette anche “istanze”) vogliono rappresentare.
Le istanze di una tabella si collegano ad istanze di altre tabelle attraverso delle relazioni (“chiavi esterne”) e sono identificate univocamente a livello di entità da una “chiave primaria” (che è un set di campi della tabella stessa su cui è stato definito un vincolo di unicità).

Pro e Contro
Uno dei principali vantaggi dei database relazionali è la garanzia delle proprietà ACID (Atomicità, Consistenza, Isolamento, Durabilità), che assicurano che le transazioni vengano eseguite in modo affidabile, anche in presenza di interruzioni di malfunzionamenti. Questo rende i database relazionali ideali per applicazioni critiche dove l’integrità dei dati è essenziale, come i sistemi finanziari, ERP (Enterprise Resource Planning), CRM (Customer Relationship Management), e-commerce, e altro ancora. Tuttavia, i database relazionali presentano anche dei limiti, in particolare quando si tratta di scalabilità orizzontale (scale-out). La necessità di mantenere la consistenza e le proprietà ACID in ambienti distribuiti può comportare un degrado delle performance e una complessità crescente nella gestione del sistema. Inoltre, la rigidità del modello relazionale può essere un ostacolo quando si gestiscono dati non strutturati o semi-strutturati, che non si adattano facilmente alla struttura tabellare.
Transazioni ACID
Una transazione una sequenza di operazioni che, quando eseguita correttamente, produce una variazione dello stato della base dati. In un database relazionale, si richiede che le transazioni rispettino particolari proprietà che vengono raccolte sotto l’acronimo ACID. Queste proprietà sono:
- Atomicità: ogni transazione viene eseguita completamente o per nulla. Se una parte della transazione fallisce, l’intera transazione viene annullata, garantendo che il database rimanga in uno stato consistente (rollback).
- Consistenza: una transazione porta il database da uno stato consistente a un altro, dove per stato consistente si intende che:
- le interrogazioni successive vedranno lo stato delle transazioni precedenti
- viene garantito che tutte le regole definite (vincoli, trigger, ecc.) vengono rispettate.
- Isolamento: le transazioni eseguite in parallelo non interferiscono tra loro. Esistono diversi livelli di isolamento (read uncommitted, read committed, repeatable read, serializable) che definiscono quanto una transazione è isolata dalle altre. Per maggiori informazioni sui livelli di isolamento delle transazioni è possibile riferirsi a questo sito.
- Durabilità: una volta che una transazione è stata confermata, i suoi effetti persistono nel tempo, anche in caso di guasti di sistema.
Queste proprietà sono fondamentali per garantire l’integrità dei dati, ma possono limitare la scalabilità e la flessibilità del sistema.
Database non relazionali
Con l’emergere di applicazioni che richiedono una maggiore scalabilità, flessibilità e capacità di gestione di dati non strutturati, i database non relazionali (o NoSQL) hanno guadagnato una notevole popolarità. A differenza dei database relazionali, i database NoSQL non si basano su tabelle relazionate e non richiedono una struttura rigida per i dati. Invece, offrono una varietà di modelli di dati più variegata e adattabile alle esigenze.
Differenze con i database relazionali
La principale differenza tra database relazionali e non relazionali risiede nella flessibilità del modello di dati. I database NoSQL sono progettati per gestire grandi volumi di dati non strutturati o semi-strutturati, come documenti JSON, dati multimediali, log di eventi, e altro ancora. Questo li rende particolarmente adatti per applicazioni web, social media, analisi di big data e IoT (Internet of Things).
La caratteristica più significativa dei database NoSQL è l’introduzione del grouping logico: uno degli svantaggi principali dei database relazionali è che l’inserimento di righe in una tabella richiede che tutti i campi dello schema vengano compilati con un valore. I database NoSQL raggruppano tra loro tutti i record con la stessa struttura, consentendo così l’inserimento di nuove righe con strutture diverse. Un’altra differenza significativa riguarda la gestione delle transazioni. Mentre i database relazionali aderiscono strettamente alle proprietà ACID, molti database NoSQL adottano il modello BASE (Basically Available, Soft state, Eventual consistency), che privilegia la disponibilità e la scalabilità rispetto alla consistenza immediata. Questo significa che, in un sistema distribuito, i dati possono essere temporaneamente inconsistenti, ma alla fine convergeranno verso uno stato consistente. Infine, i database NoSQL salvano i dati in strutture dati note ai comuni linguaggi di programmazione, semplificando così le operazioni tramite ORM.
Tipi di Database NoSQL
I principali tipi di database NoSQL includono:
- Document Store: memorizzano i dati in formato documento (es. JSON, BSON, XML). MongoDB è uno dei rappresentanti più noti di questa categoria. I document store sono particolarmente utili per applicazioni che gestiscono contenuti dinamici e complessi, come blog, e-commerce e CMS.
- Key-Value Store: memorizzano i dati come coppie chiave-valore. Questo modello è estremamente semplice e veloce, ideale per applicazioni con accesso rapido a dati non strutturati. Esempi includono Redis e DynamoDB.
- Column Store: memorizzano i dati in colonne piuttosto che in righe. Questo approccio è ottimizzato per query analitiche su grandi volumi di dati. Apache Cassandra e HBase sono esempi di database a colonne.
Graph Database: memorizzano dati che sono fortemente interconnessi, come reti sociali o mappature di percorsi. Su di essi sono naturalmente applicabili i comuni algoritmi dei grafi. I database a grafo, come Neo4j, sono progettati per gestire query che richiedono l’esplorazione di nodi e relazioni.
Miglioramento dei Parametri di Affidabilità
Garantire alti livelli di scalabilità, performance e high availability (le definizioni qui) è fondamentale nelle architetture di data storage su larga scala. Questi obiettivi possono essere raggiunti attraverso diverse tecniche, tra cui indexing, database replication e sharding/partitioning.
Indexing
L’indexing è una tecnica utilizzata per migliorare la velocità delle query sui database.
Nello specifico essa cerca di individuare i record desiderati in un tempo sublineare, ossia in un tempo che cresce con complessità minore rispetto alla dimensione dell’input.
![]()
Un indice è una struttura dati che permette di accedere rapidamente a una riga specifica in una tabella, senza doverla scansionare interamente (impiegando così un tempo lineare). Quando l’indice è creato a partire da una sola colonna, esso è, per ogni riga, il riferimento al valore assunto da quella colonna per quella riga. Quando invece l’indice è generato su più colonne, allora si parla di “indice composito” ed è il riferimento al set di valori assunti dalle colonne per la riga referenziata.

Gli indici vengono implementati utilizzando delle strutture dati ad accesso veloce. Nello specifico, vengono usate le HashMap (con complessità di accesso costante) per query rapide e i B-TREE (con complessità di accesso logaritmica) quando è necessario garantire anche la proprietà di ordinamento dell’indice. Gli indici offrono un significativo miglioramento delle performance, soprattutto in presenza di grandi quantità di dati. Tuttavia, è importante utilizzare gli indici con attenzione, poiché la loro creazione e manutenzione può comportare un overhead significativo in termini di spazio su disco e tempo di aggiornamento.
Database Replication
La database replication è un’altra tecnica chiave per migliorare l’affidabilità e l’high availability di un sistema. La tecnica consiste nel copiare e mantenere i dati su più server (repliche), in modo che se uno dei server fallisce, gli altri possano continuare a fornire accesso ai dati. Esistono diversi modelli di replicazione, tra cui:
- Master-Slave Replication: il server master gestisce tutte le operazioni di scrittura e le replica sui server slave, che gestiscono le operazioni di lettura.
- Multi-Master Replication: tutti i server possono gestire operazioni di lettura e scrittura, e sincronizzano i dati tra loro. Questo modello è più complesso, ma offre una maggiore tolleranza ai guasti.
- Asynchronous vs. Synchronous Replication: nella replica asincrona, i dati vengono copiati sui server replica con un certo ritardo, mentre nella replica sincrona, i dati vengono copiati immediatamente, garantendo una maggiore consistenza a scapito della latenza.
Sharding/Partitioning
Sharding e partitioning sono due tecniche che molto spesso vengono utilizzate insieme. Esse permettono di migliorare la scalabilità orizzontale suddividendo i dati di una tabella su più server detti “shard”. Ogni shard contiene una porzione dei dati (detta “partizione” o “data fragment”) e può essere gestito in modo del tutto indipendente dalle altre.
Molto spesso, in mancanza di più shard paralleli, si preferisce optare esclusivamente per il partitioning, lavorando in maniera indipendente e parallela su partizioni di dati che risiedono sullo stesso server.
Il partizionamento può basarsi su diversi criteri, come i valori assunti dai dati, l’hashing di una chiave, o la geolocalizzazione e ogni partizione condivide lo schema originario.

Lo sharding permette di distribuire il carico di lavoro su più server, migliorando le performance e la capacità di gestire grandi volumi di dati. La scalabilità è favorita, in quanto è possibile aggiungere/rimuovere gli shard in trasparenza e le query operanti su dati appartenenti a shard diversi possono essere condotte in parallelo. Tuttavia, la gestione dello sharding può essere complessa, specialmente in termini di bilanciamento del carico e gestione delle transazioni distribuite in quanto, soprattutto in questo ultimo caso, è necessaria un’azione di sincronizzazione fra gli shard stessi.
Teorema CAP
Il teorema CAP (Consistency, Availability, Partition tolerance), formulato da Eric Brewer, è un principio fondamentale che descrive le limitazioni dei sistemi distribuiti.
Come concetto preparatorio, è necessario fornire la definizione di network partitioning: il “network partitioning” è un malfunzionamento che provoca la suddivisione degli utenti in gruppi isolati. Gli utenti appartenenti a un certo gruppo risultano impossibilitati a comunicare con gli utenti degli altri gruppi.
Secondo il teorema, un sistema distribuito non può garantire simultaneamente tutte e tre le seguenti proprietà:
- Consistency: ogni lettura riceve l’ultimo dato scritto o un errore.
- Availability: ogni richiesta riceve una risposta che non è un errore, senza garanzia che essa contenga il dato più aggiornato.
- Partition tolerance: il sistema continua a funzionare nonostante la perdita di comunicazione tra nodi in caso di network partitioning.
Nello specifico, secondo il teorema:
- se si decide di dare priorità alla consistency e all’availability, allora non è possibile garantire la partition tolerance (CA): in tal caso, l’unica possibilità per eliminare la partition tolerance è eliminare i collegamenti di rete. Ma questo significherebbe ritornare ad un database centralizzato;
- se si decide di dare priorità all’availability e alla partition tolerance, allora non è possibile garantire la consistency (AP): in questo caso le repliche continuano a fornire i valori più recenti in esse memorizzati, comunicando al client che questi potrebbero essere non aggiornati;
- se si decide di dare priorità alla consistency e alla network partitioning, allora non è possibile garantire l’avaliability (CP): le repliche restituiscono degli errori chiedendo al client di rieffettuare la richiesta in futuro.

Nelle architetture di data storage su larga scala, è spesso necessario fare delle scelte in base al teorema CAP. Ad esempio, i database relazionali tendono a privilegiare la consistenza rispetto alla disponibilità, mentre molti database NoSQL optano per la disponibilità e la tolleranza alle partizioni, accettando una consistenza eventuale (eventual consistency).
Memorizzazione scalabile di dati non strutturati
Oltre ai dati strutturati, le aziende moderne devono gestire una quantità crescente di dati non strutturati, come documenti, immagini, video, e log. Questi dati, che prendono solitamente il nome di BLOB (binary large objects) non seguono uno schema predefinito e non possono essere facilmente memorizzati in un database relazionale. Inoltre, non possono essere recuperati in maniera semplice in modo scalabile, per cui sono state ideate delle tecniche e delle tecnologie utile a tale scopo.
Distributed File Systems (DFS)
I Distributed File Systems (DFS) offrono le stesse astrazioni di un filesystem su hard drive locale, ma in questo caso il supporto di memorizzazione è un insieme di server connessi in rete. Questi sistemi, oltre a fornire proprietà di replicazione e scalabilità per loro intrinseca natura, permettono di memorizzare i blob in una struttura gerarchica e di recuperarli secondo degli algoritmi di recupero che vengono eseguiti in maniera ricorsiva e con una complessità logaritmica.
Oltre a non aver bisogno di API per l’interrogazione, essi offrono di default buone performance di I/O.
Object/Blob Store
Gli Object Store (o Blob Store) sono un’altra soluzione per la gestione di dati non strutturati. Invece di utilizzare un filesystem tradizionale, gli object store memorizzano i dati come oggetti binari, ciascuno identificato da un ID univoco e corredato da una serie di informazioni di contenuto. Nello schema in figura è rappresentato il tipo di dato astratto che rappresenta un oggetto:

Gli object store non sono organizzati in strutture gerarchiche, ma in container detti bucket, i quali possono essere implementati utilizzando strutture dati ad accesso veloce che sfruttano l’ID univoco come entry point.
Gli object store sono ideali per la gestione di dati multimediali, backup, archiviazione e applicazioni di cloud storage. Per questo motivo, i principali cloud providers offrono una serie di soluzioni di object storage organizzati in classi. La classe più costosa è quella che offre performance e high availability maggiori. In tabella, con colori che vanno dal rosso al verde, sono riportate rispettivamente le classi per Amazon S3, GCP Storage, Azure Blob e Alibaba OSS.
| Amazon S3 | GCP Storage | Azure Blob | Alibaba OSS |
| S3 Standard | Standard | Hot tier | Standard |
| Standard – Infrequent access | Nearline | IA | |
| Glacier Instant Retriever | Coldline | Cool tier | Archive |
| Glacier Deep Archieve | Archieve | Archieve tier | Cold archieve |
Tabella 1 – classi di object storage per i maggiori cloud providers. Dal rosso al verde, le classi più costose, ma che offrono prestazioni migliori
Solitamente, l’uso esclusivo di una classe non è un’opzione selezionabile per diversi motivi come vincoli di budget, architetturali e strutturali. Per tale motivo si predilige l’utilizzo di una soluzione ibrida fra classi.
Gli object store hanno due svantaggi:
- gli oggetti sono immutabili, quindi modifiche e cancellazioni comportano delle riscritture, con conseguenti problemi di performance.
- la scelta di una struttura dati non adeguata al bucket può provocare un degrado delle prestazioni.
Conclusioni
Il data storage su larga scala nelle architetture software enterprise è un campo vasto e complesso, che richiede una profonda comprensione delle diverse tecnologie e delle loro implicazioni in termini di scalabilità, high availability e performance. I database relazionali offrono solidità e consistenza, ma possono incontrare limiti in contesti altamente scalabili. I database non relazionali forniscono flessibilità e capacità di gestire dati non strutturati, ma richiedono compromessi in termini di consistenza. Tecniche come l’indexing, la database replication e lo sharding/partitioning sono fondamentali per migliorare le performance e garantire i principali parametri di affidabilità. Infine, il teorema CAP e le soluzioni per dati non strutturati, completano il quadro di un panorama in continua evoluzione dettando la scelta delle giuste tecnologie che può fare la differenza tra il successo e il fallimento di un’architettura di data storage su larga scala.
Se anche tu vuoi far parte del team di sviluppo Nexsoft,
dai un’occhiata alle nostre opportunità di lavoro e conosciamoci subito!


