Scalabilita' e Cloud Computing con MySQL

MySQL e' un potente e diffuso database relazionale Open Source. La semplicita', la velocita' e la flessibilita' lo hanno reso il piu' diffuso DB per applicazioni web spesso in architettura LAMP. Ma le sue funzionalita' ne consentono un uso anche in modo massivamente parallelo ed in Cloud Computing.

Nel seguito sono riportate alcune informazioni di interesse organizzate in paragrafi specifici: Replicazione, Scalabilita' orizzontale, Esempio di configurazione, Sviluppo di applicazioni (Sharding e Partitioning, memcache), Cloud Computing.

Replication

La funzionalita' di replica dati di MySQL e' semplice da configurare, e' molto flessibile ed e' adatta per aumentare la scalabilita' del database e per un uso in Cloud. In questo documento viene presentato un esempio per scalare una base dati MySQL su decine o centinaia di server. Vengono inoltre presentati i principali aspetti tecnici per implementare una base dati MySQL in Cloud.

In una tipica configurazione di MySQL replication sono presenti un solo Master, su cui avvengono tutte le modifiche dei dati, ed uno o piu' Slave, su cui vengono replicati i dati e che viene utilizzato in sola lettura.
Poiche' una tipica applicazione su DB esegue un numero molto elevato di letture rispetto alle modifiche, il numero dei DB Slave puo' essere elevato garantendo cosi' tempi di risposta ottimali per tutte le SELECT. Le attivita' di modifica vengono invece dirette al Master su cui e' garantita la consistenza dei dati.

La replicazione su MySQL e' statement based ed asincrona.
Il Master si occupa di registrare su file (bin-log file) tutti gli statement che vengono eseguiti sulla base dati e che operano una qualche modifica ai dati (DML e DDL).
Lo Slave si collega con un thread al Master, raccoglie il contenuto dei bin-log, lo trasferisce in locale e quindi si occupa di applicarlo alla base dati.
La parte svolta dal Master e' molto semplice, poco onerosa e "stupida". In pratica ospita una sessione client per ogni Slave configurato. La maggioranza delle opzioni di configurazione e la gestione ricadono sullo Slave. E' questo che si occupa della ricezione dei log, del loro allienamento e della corretta applicazione degli statement SQL sulla base dati.

MySQL Replication Architecture

La replicazione in MySQL e' molto flessibile e sono possibili molte alternative.
Gli Storage Engine utilizzati sullo Slave possono essere diversi da quelli utilizzati sul Master. Questo consente di scegliere l'Engine piu' adatto allo scopo (eg InnoDB sul Master in cui avvengono le transazioni, MyISAM sullo slave su cui vengono effettuate un selezioni o i backup).

Scalabilita' orizzontale della replicazione

Nel caso piu' semplice di replicazione un Master viene replicato su uno Slave. Se gli accessi in lettura al database sono molto elevati (eg. siti web molto acceduti) e' possibile configurare in modo semplice decine di Slave. In questo caso si parla di scalabilita' orizzontale: e' infatti possibile aumentare il throughtput del sistema in modo lineare semplicemente aggiungendo piu' macchine dello stesso tipo. La scalabilita' verticale e' invece tipicamente piu' costosta poiche' richiede di incrementare la potenza di una macchina aggiungendo componenti o sostituendola con una piu' performante.

Con la particolare configurazione descritta nel seguito e' possibile aumentare il numero di Slave DB senza appesantire il Master raggiungendo cosi' le centinaia di server Slave.
Uno Slave puo' comportarsi a sua volta da Master e questo puo' essere utilizzato in cascata piu' volte. In particolare, se il numero di Slave che si vuole mantenere allineati e' molto elevato, si utilizza la catena A -> B => Cn dove n e' puo' essere grande quasi a piacere. A e' configurato come Master. B e' configurato come Slave di A e Master di tutti i Cn. In questa configurazione tutte le modifiche vengono applicate sulla base dati A e trasferite su tutti i sistemi C acceduti in sola lettura. E' una configurazione di replica MySQL in daisy chain tra i primi livelli di master e petalosa sugli slave.
Per sfruttare al meglio tale architettura e' opportuno che le applicazioni utilizzino due connessioni differenti: una per gli update e l'altra per le SELECT. In caso contrario e' necessario separare gli accessi... ed e' possibile farlo con MySQL Proxy.

Come abbiamo visto utilizzando la replicazione e' possibile costruire complesse architetture di database MySQL che soddisfano ai piu' stringenti requisiti di affidabilita' e scalabilita'.

MySQL Massive ReplicationMySQL Massive Replication and Proxy
MySQL Replication MySQL Proxy and Replication

Esempio di configurazione

Troppe parole! Vediamo un esempio: un database Master con 16 Slave per un'applicazione che utilizza connessioni distinte RO/RW.

Gia' fatto!?
Naturalmente va provato tutto (eg. comportamento delle applicazioni sulle primary key in auto increment)... ma la configurazione di decine o centinaia di Slave e' tutta qui!

Sviluppo di applicazioni scalabili

La replicazione di MySQL e' generalmente trasparente alle applicazioni. Accedere ai dati sul Master o sugli Slave non comporta infatti alcuna differenza. L'unica avvertenza e' quella di dirigere tutte le attivita' di modifica verso il Master.
Per fare in modo che tutte le attivita' di modifica siano rivolte al Master e' possibile agire in due modi:

La scrittura di applicazioni utilizzate in modo efficiente da migliaia o milioni di utenti in contemporanea richiede un'attenta progettazione. Con un'utilizzo attento di MySQL e' possibile scalare in modo orizzontale sul database cosi' come e' possibile farlo sugli application server.
La prima distinzione e' quella tra gli accessi in scrittura e quelli in lettura, nel prossimi capitoli le connessioni saranno ancora piu' differenziate o saranno precedute da accessi non relazionali.
Un ultimo commento... Le basi dati debbono essere ben disegnate e cosi' deve essere anche per le applicazioni! Indici non selettivi, tabelle non normalizzate, accessi inutili o ripetuti sono errori comuni... Su applicazioni usate in modo appena significativo gli errori di disegno rendono praticamente insufficiente qualsiasi infrastruttura sia predisposta. Prima di pretentere la scalabilita' di un'applicazione, prova a farla funzionare bene!

Sharding e Partitioning

Al crescere delle dimensioni della base dati l'accesso in scrittura diventa sempre piu' pesante. E questo sia sul Master che sugli Slave che debbono comunque replicare le modifiche occorse. A questo punto l'unica soluzione e' diminuire la dimensione della base dati!

Una prima possibilita' e' quella di isolare componenti applicative ed utilizzare database differenti per ciascun gruppo. In questo modo e' possibile utilizzare gruppi di database differenti ciascuno di minori dimensioni.
E' inoltre possibile dividere le tabelle applicativamente in modo orizzontale. Questo richiede generalmente una modifica relativamente semplice nelle applicazioni per determinare a quale database accedere. Naturalmente si perde la possibilita' di effettuare join... ma se il problema e' quello di gestire milioni di accessi in contemporanea nessun join globale potrebbe essere efficiente. La scelta su come suddividere le basi dati e' molto importante. Questa tecnica di partizionamento orizzontale delle tabelle e' detta sharding.
Con MySQL, cosi' come su tutti i DB relazionali, e' semplice implementare lo Sharding a livello applicativo.

Dalla versione 5.1 di MySQL e' disponibile il partitioning. Con il partitioning non e' richiesta alcuna modifica applicativa poiche' si tratta di un meccanismo di memorizzazione interno alla base dati. Con il pruning il partizionamento puo' fornire miglioramenti prestazionali elevati. Tuttavia tutte le partizioni sono ospitate sullo stesso server. Quindi se, oltre a migliorare l'accesso ad una tabella, e' necessario separare il carico scalandolo su piu' server, il partizionamento non e' sufficiente e debbono essere applicate le tecniche descritte nei paragrafi precedenti.
Con MySQL il partitioning e' completamente trasparente a livello applicativo anche se vanno utilizzati alcuni accorgimenti nelle query per sfruttarlo appieno.

memcache

La tecnica di raccogliere in una cache i dati che vengono richiesti piu' volte puo' essere applicata a piu' livelli migliorando notevolmente le prestazioni e consentendo un numero maggiore di accessi alla applicazione ed al database. Lo stesso avviene quando e' possibile effettuare eleborazioni pesanti prima che vengano richieste. Anche la dernomalizzazione e l'overnormalizzazione dei dati possono dare buoni risultati. Ma tutte queste tecniche dipendono dall'applicazione e richiedono generalmente una codifica accorta ed impegnativa.

memcache e' una cache distribuita che consente di reperire in modo rapido i valori associati ad una chiave. L'uso di memcache permette di evitare accessi ad una base dati nelle ricerche piu' utilizzate e semplici.
L'implementazione e' semplice. Uno o piu' server mantengono in memoria una cache costituita da una enorme tabella ad hash. La chiave puo' essere lunga fino a 250 caratteri, il dato fino ad un MB. L'utilizzo e' in client server (tipicamente sulla porta 11211) con API disponibili praticamente con ogni linguaggio. In pratica anziche' ricercare il risultato con l'SQL come in questo esempio (PHP):

$risultato = array();
$sql = "SELECT * FROM emp WHERE ename like ". $cond;
$res = mysql_query($sql, $mysql_connection);
while($rec = mysql_fetch_assoc($res)){
    $risultato[] = $rec;
}
Si effettua prima una ricerca su memcache, nella maggior parte dei casi si ottiene la risposta (in tempi brevissimi). Se non si trova il risultato su memcache si ricavano i dati richiesti accedendo al DB e poi si inserisce il record nella cache per rendere piu' veloci i successivi accessi. Modificare il codice e' molto semplice, bastano una if() e due comandi in piu':
if( ! $risultato = $memcache->get("emp like:" . $cond) ){
    $risultato = array();
    $sql = "SELECT * FROM emp WHERE ename like ". $cond;
    $res = mysql_query($sql, $mysql_connection);
    while($rec = mysql_fetch_assoc($res)){
        $risultato[] = $rec;
    }
    $memcache->set("emp like:" . $cond, $risultato, 3600);
}

Non e' tutto cosi' facile perche' ci sono da gestire gli update, le cancellazioni, la sincronizzazione tra server, ... memcache non e' sempre applicabile perche' non c'e' autenticazione, gestione delle transazioni, possibilita' di query complesse, ...
Ma e' terribilmente semplice e veloce! In particolare se usato per evitare accessi alla base dati per query eseguite moltissime volte.

memcache e' un software Open Source e puo' essere scaricato da questo sito.

Cloud Computing

MySQL e' facilmente utilizzabile in ambienti virtualizzati. Generalmente non e' necessaria alcuna variazione nella configurazione. In qualche caso si presentano limiti prestazionali legati all'accesso verso lo storage, in questo caso e' opportuno un tuning specifico.

MySQL fornisce direttamente il supporto per alcune soluzioni Cloud come IaaS (eg. MySQL su Amazon EC2). Direttamente sul sito MySQL si possono trovare i riferimenti per la virtualizzazione ed il Cloud Computing. Oltre alle AMIs (Amazon Machine Images) e' inoltre possibile utilizzare anche il servizio Amazon RDS.

Ma in questo capitolo, piu' che il supporto ufficiale e gli accordi commerciali, vogliamo riportare alcuni importanti aspetti tecnici nella configurazione di MySQL in un Cloud.

Riassumendo MySQL e' un ottimo DB per un utilizzo in Cloud. Semplice, flessibile e facilmente gestibile. Con l'utilizzo di tecniche di replicazione, Sharding e cache (eg. memcache) puo' scalare in modo molto elevato.
Per l'utilizzo di tecniche NoSQL... ne parleremo un'altra volta!


Titolo: Testo: Scalabilita' e Cloud Computing con MySQL Replication
Livello: Avanzato (3/5)
Data: 1 Aprile 2010
Versione: 1.0.7 - 14 Febbraio 2016
Autore: mail [AT] meo.bogliolo.name