Da alcuni mesi sto lavorando su un progetto in cui una certa mole di dati deve essere memorizzata su un filesystem condiviso tra più nodi attivi di un cluster, anche con replicazione distribuita su base geografica.
Abbiamo vagliato una serie di soluzioni differenti basate su tecnologie differenti e con approcci differenti al problema, ma abbiamo avuto parecchie difficoltà a trovare qualcosa che soddisfare tutti i nostri prerequisiti. Nell’ordine abbiamo valutato…
- NBD: approccio alla replica block based. Ha una logica di funzionamento tale da far si che tutte le operazioni effettuate da un nodo su un dato disco vengano replicate su un altro nodo connesso via rete locale. La sincronizzazione è effettuata a livello di blocchi utilizzando delle tabelle bitmap per individuare, una volta effettuata la prima sincronizzazione iniziale, quali siano i blocchi modificati. Di fondo l’approccio di funzionamento è agnostico al filesystem ed è analogo a quello di md, il mirror software, di Linux. Questo approccio nativo pone due grandi limiti:
- il primo è che una replica block level, proprio in quanto agnostica rispetto al filesystem, sarà sempre molto dispendiosa in termini di quantità di dati da far viaggiare tra un nodo e l’altro (i blocchi sono piccoli, le scritture non ottimizzabili o sequenziabili…) e soprattutto, per quanto ottimizzata dalle mappe bitmap nel momento in cui il nodo slave fosse momentaneamente sconnesso dal primario, dovrebbe forzatamente rifare un check sull’allineamento con l’intero volume intero – fattori molto importanti in quanto rendono praticamente impossibile utilizzare NDB in uno scenario in cui i due server non siano in rete locale
- il secondo è che il nodo slave è un hot standby ed il nodo secondario non ha accesso ai dati che sono disponibili sul suo disco fintanto che questo non diventi il master. Per onestà intellettuale va detto che da un paio di anni NDB include anche una finta modalità multi master in cui entrambi i volumi possono essere montati contemporaneamente su entrambi i server e la sincronizzazione è bidirezionale, ma di fondo si tratta nuovamente di una mezza fregatura: NDB non è un filesystem (ed è agnostico al filesystem) quindi con lui da solo non potrete farci niente. Un eventuale filesystem ext3 creato nel volume NDB condiviso non potrà essere acceduto dal secondo server perché ext3 non è multi sessione. NDB non implementa partizioni di quorum, non implementa meccanismi di locking multinodo… Nulla. La soluzione che quindi viene suggerita è quella di usare un filesystem clustered tipo GFS di RedHat o OCFS2 di Oracle sul volume NDB che a questo punto farebbe solo finta di essere un improbabile storage condiviso via rete… A mio avviso una bella schifezza, considerato il forte impatto in termini di implicazioni tecniche e tecnologiche nell’implementare un filesystem cluster (il multi cast per GFS, l’uso di clvm, un filesystem non rimontabile facilmente in caso di Disaster Recovery nel caso di OCFS2)
Qualora tutto ciò non vi fosse sembrato abbastanza, NDB non ha alcuna logica interna per la gestione stessa del cluster che secondo le menti dietro di esso dovrebbero essere demandate a qualcosa di esterno tipo HA. Insomma, in soldoni NDB dice di fare tutto ma fa piuttosto poco.
- HAST di FreeBSD giusto per renderci conto che ha gli stessi esatti limiti di NDB. Che peccato per un progetto nato praticamente praticamente ora e che per di più sarà ancora più castrato dalla mancanza di filesystem come GFS ed OCFS2 su FreeBSD. In pratica quindi il fratello stupido di qualcosa che già non è completo. Epic Fail.
- la DataReplication delle EVA-qualcosa di HP. Fichissima, incrementale e WAN aware (con tanto di compressione dei dati in transito), peccato che il nodo secondario sia nuovamente un hots-tandby inoperativo.
- sincronizzazioni timerizzate a base di rsync: paradossalmente la soluzione che a conti fatti rispondeva alla maggior parte dei prerequisiti – è incrementale, funziona tramite internet, è compressa… Insomma mica male… Il problema è che dovendo schedulare la risincronizzazione ad intervalli temporali, proprio in quanto timerizzata ha dei buchi di disallineamento. Certo uno può pianificare le sincronizzazioni molto frequenti, ma il problema è che l’operazione di risincronizzazione, per quanto non trasferisca dati allineati, è piuttosto lenta a partire, soprattutto al crescere dei file memorizzati. Con poche decine di migliaia di file tramite internet la frequenza minima realistica di allineamento è di 10/15 minuti di intervallo.
- ZFS su FreeBSD: ancora una volta una soluzione superganza, questa volta anche facilmente backuppabile, ma anche questa volta non compatibile con uno scenario dual master.
- HDFS: multi master, geograficamente distribuito, incrementale… Ma… cluster di 64MB? Il dispatcher dei nodi non è clusterizzabile e non ha per design uno slave? Ma stiamo scherzando? diciamo che ho letto male la documentazione, dai.
a questo punto della mia ricerca devo dire che iniziavo ad essere piuttosto sconfortato, quando mi sono ricordato di aver letto un po’ di tempo fa di un progetto per creare un filesystem virtuale operante su database MySQL: MySQLfs.
Ho cercato e su sourceforge ho trovato la pagina del progetto, purtroppo apparentemente non otto attivo, visto che l’ultima versione, la 0.4.0 è del 2009… In un impeto di ottimismo ho deciso di provare comunque a scaricarlo e compilarlo.
MySQLfs è, in verità, un modulo per FUSE, il progetto che permette di scrivere dei filesystem custom operanti in userland invece che a livello kernel. I vantaggi sono molti, tra cui la possibilità di scrivere facilmente un modulo che si interfacci con le librerie standard mysql. Nel caso specifico, mysqlfs si limita a “tradurre” in SQL le write e le effettuate verso il filesystem che astrae. La cosa interessante è che il database dentro cui vengono memorizzati i dati può essere replicato su altri nodi mysql. La replicazione di mysql è ovviamente incrementale, trasformando indirettamente il filesystem risultante in un vero e proprio filesystem journaled di tipo copy on write, ed il database è ovviamente intrinsecamente multi sessione e quindi può essere tranquillamente montato in modalità multi master su più nodi. Il protocollo mysql su cui è basata la replicazione è compresso e si comporta molto bene anche su tratte geografiche.
Il database è facilmente backuppabile sia in maniera integrale (dump) sia in maniera incrementale (ad esempio backuppando i binary log stessi della replication), è atomico e transazionale…
Insomma sulla carta sembrerebbe essere la soluzione di tutti i mali.
Ma ovviamente c’è sempre un “ma”…
Allo stato attuale mysqlfs 0.4.0 è piuttosto lento.
Fortunatamente ci ho lavorato un po’ per portarlo al passo con i tempi e per ottimizzare alcune cose tra cui:
- passaggio alla versione 26 delle api di fuse, più perforanti e che supportano la modalità “big writes” che, in soldoni, leggono e scrivono blocchi di dati più grossi riducendo drasticamente il numero di QUERY eseguite
- implementazione del supporto alle transazioni, che ottimizza drasticamente l’uso del binary log da parte di mysql, evitando le racing conditions tra le scritture al disco da parte del db engine e quelle da parte del thread del binary log
I risultati preliminari sono ottimi e spero di rilasciare una versione pubblica di questa nuova release di mysqlfs al più presto.
Cercherò di contattare gli autori originali per far includere le mie modifiche nella distribuzione ufficiale.