MySQLfs “AB” public repo

So, actually it was easier than I thought. Here’s a public repo for my updated MySQLfs:

It’s a work in progress and I wrote my first C statement 10 days ago, so please be kind ūüėČ

Contributors are welcome. As you see I cloned an already existing repository in order to have all the history imported but didn’t start from the latest commit as I found the new added function a bit confused as of now (well, maybe it’s just me who can’t really understand them…), but I plan to merge them back later as I fix the things that need more attention in my environment right now.

Have fun.

MySQLfs updates

I already spent some talk on this previously but I wrote in Italian, so let’s do a little recap for English readers.

Just recently I became involved in a project where a cluster of machine had to replicate their datas constantly in an active-active fashion and with geographical distribution.

We checked different kinds of solutions based either on drbd or zfs or hast or coda or… Well there’s a lengthy post on this issue just a few posts before this one, so I suggest you checking that.

At the end of our comparison we found the solution that suited us best to be mysqlfs. So I started investigating on that and quickly found some issues that could be improved.

Main points were:

  • performances, as mysqlfs turned out to be pretty slow under certain circumstances
  • transaction awareness
  • better integration with mysql replication

As I digged in the code, I found a pretty good general infrastructure but quite frankly I don’t think mysqlfs was really ever used in a production environment.
Apart from that, the project was quite young (latest official version was 0.4.0) and also pretty “static”, with it’s latest release dating back in 2009.

So, without any knowledge of C or Fuse whatsoever I took the sources of the latest “stable” release and began experimentating with it.

A few weeks has passed and I think I reached a very interesting point. Those are the goal that I reached as of now:

  • mysqlfs is now using InnoDB instead of MyIsam
  • all the writing operations are now enclosed into a transaction that gets rolled back if something bad happens halfway
  • using transactions also means better replication interoperability, since innodb and the binary log don’t fight for the drives. Innodb first, bin log after.
  • mysqlfs now uses fuse API version 2.6 instead of the old… Mmh… 2.5 I think.
  • using fuse’s API version allowed switching on fuse “big writes”, the switch that allow the kernel and the file system to exchange data blocks bigger than standard 4k
  • mysqlfs internal data block was changed from 4k to 128k either to reduce the blocks fragmentation, to reduce the rows in the “data block” table, to reduce the inserts, and finally to match the big write setting. Receiving 128kb of datas and then pushing 4k at time in the db wouldn’t really make any sense
  • moving to the 2.6 API allowed mysqlfs to be FreeBSD compliant. I don’t know (yet) about Mac OS or anything else, but having the devil in the party is a good plus for me.
  • today I started working on the new file system function that got introduced in e latest versions of fuse, that should to even better to speed and such

Next steps are…

  • implement file and inode locking
  • implement some kind of mechanism to do somewhat write-thru cache. Many basic system commands (cp, tar, gzip) use very small writing buffers (8/16k) so the impact of the big write switch get lost and the performances degrade a lot. I’m a bit afraid this task is above my (null) C knowledge but I have some interesting ideas in mind…
  • implement the missing functions from fuse
  • introduce some kind of referential integrity in the db, although I have to understand the performance downsize
  • introduce some kind of internal data checksum, although everything comes at a price in terms of CPU time
  • introduce some kind of external, let’s say php for example, API, to allow direct php applications to access directly the file system, while it’s mounted, maybe in different machines at the same time, without having to use the file system-functions… Wouldn’t be cool to have a web app, a Linux server and a FreeBSD server all working on the same file system at the same time? Yes I know, I’m insane ūüôā
  • improve replication interoperability introducing server signatures in stored datas
  • introduce some kind of command line tools to interact with the db and check total size usage and such
  • in a long future introduce some kind of versioning algorithm for the stored datas

Right now the modification I made to mysqlfs aren’t public yet, as I couldn’t really understand the status of the project on sourceforge. Furthermore it’s code base on sourceforge is not aligned to the version that was on the installer (the one I started working on), and it’s stored in svn that I don’t absolutely know how to use.

I know the latter ones aren’t big issue, but my spare time is very thin, and I definitely can’t waste time in learning svn or manually merging the “new” code that’s in the svn and that is different from the tgz I started from. If any of you is willing to do it I’ll be glad to help.

My internal git repository isn’t public yet because of laziness and because I’d like to publish something that’s at least usable and I have to fix a couple of problems before it could be defined “idiot proof”.

In the meantime if any of you is willing to try I’d be very glad to share the modified code, or if any of you is willing to contribute then I’d be twice as glad as long as we try to keep development a bit aligned.


P7M Viewer for Mac OS X

Recently I convinced my boss in switching from Windows-based clients to Mac OS X ones. Unfortunately one of the activity we dealt with required the ability of reading P7M files, that’s files that have been digitally signed and encoded in PCKS#7 SMIME Mail.

I searched a lot but wasn’t able to find a P7M viewer for Mac OS X… With Windows Acrobat Reader itself reads the P7M, while Acrobat for Mac doesn’t…, so I started investigating.

The command line to decode a P7M file is pretty easy:

openssl smime -decrypt -in file_in.pdf.p7m -inform DER -verify -noverify -out file_out.pdf

So the deal was to allow any user to view the files without having to deal with the Terminal.

Luckily enough with a great help from my friend Marco Balestra, we quickly hacked an AppleScript Application that can be used to decrypt the P7M, launch the viewer, and then delete the temporary file.

Here you find it attached. Just Unzip it, right click on the P7M and select “Open with…”

Obviously it comes with no warranties of any kind ūüôā

Ermh… I forgot the attachment, here it is: OpenP7M

SCP tra due host remoti

Chiunque abbia lavorato per pi√Ļ di 10 minuti usando SSH conoscer√† sicuramente SCP, il comando che permette di copiare un file tra due macchine appoggiandosi ad una sessione ssh. Il principio √® semplice: si pu√≤ copiare un file da un server ssh alla nostra machina locale oppure un file dalla nostra macchina locale al server. Semplice. Un esempio?

Da qui a li:

scp file.txt utente@server:/directory/

Da li a qui:

scp utente@server:/directory/file.txt .

Ciò che in pochi realizzano è che lo stesso comando può essere usato per copiare un file tra due server entrambi remoti. Il principio è semplice;

scp utente1@serverorigine:/directory/file.txt utente2@serverdestinazione:/directory/

Ciò che però la documentazione si scorda di dirvi e che, a differenza di quanto potreste aver pensato, la vostra macchina non farà da ponte (è un feature, non un bug!) bensì farà in modo che il primo server instauri una connessione diretta verso il secondo per copiare il file.

Questo ha delle implicazioni non da poco, nell’ordine:

  • i due server devono essere in grado di parlarsi, topologicamente intendo. Scordatevi la possibilit√† di fare voi da gateway tra due reti differenti
  • per poter fare la copia il primo server deve essere in grado di autenticarsi in maniera automatizzata sul secondo (authorized_keys… Avete presente?) in quanto la sessione √® “cieca” ed il primo server non sarebbe in grado di venirvi a chiedere la password. Questo vincolo ovviamente non riguarda la connessione tra voi ed il primo server, quella pu√≤ tranquillamente essere password based

Buone copie.

MySQLfs, un nuovo approccio al concetto di filesystem condiviso

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.

PHP: CURL – Upload di un file in POST, dietro proxy.

PHPRecentemente mi sono trovato a dovere simulare il comportamendo di un browser interagendo con un web server in PHP. L’obiettivo dello script PHP che si stava facendo era quello di simulare il caricamento in POST di un documento. L’obiettivo √® facilmente raggiungibile in PHP tramite le librerie CURL. Cercando su internet si trovano numerosi esempi da cui se ne deduce che l’uso-tipo √® il seguente:

/* L'url a cui inviare il POST */
$request_url = "";

/* Indico a CURL quale sia il file da inviare:
 * nel form c'è un <input type="file" name="FileUP" /> */
$post_params['FileUP'] = "@/home/io/TestPdf2.pdf";

/* Nel Form ho un qualsivoglia altro parametro da passare
 * in post */
$post_params['AltroParametro'] = "Ezekiel";

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_params);
curl_setopt($ch, CURLOPT_VERBOSE, TRUE);
$result = curl_exec($ch);

Il trucco sta nello specificare con la @ davanti il nome del file da inviare: in questo modo CURL capisce che parliamo di un file e si regola di conseguenza. Tutto ha funzionato bene fino a che non ho provato ad eseguire lo stesso codice da dietro SQUID in modalit√† trasparente, che ha iniziato a rispondermi “Invalid request”. Dopo ore ed ore di tentativi (inutili), ho scoperto che il punto √® molto semplice: CURL utilizza un’intestazione HTTP non supportata da Squid, la “Expect: 100-continue”. Per impedire questo comportamento √® sufficiente aggiungere un’opzione:

curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));

E tutto magicamente funzionerà.

FreeBSD Ports: installazioni tramite proxy http

Al fine di superare eventuali blocchi topologici, o semplicemente per ottimizzare l’utilizzo della connessione ad internet √® possibile specificare le impostazioni relative ad un server Proxy HTTP ed FTP da usarsi durante le operazioni di compilazione dei Ports.

La cosa √® piuttosto semplice: i ports scaricano ogni pacchetto utilizzando l’utility di sistema fetch la quale referenzia due variabili di ambiente per leggere le impostazioni relative ai proxy:


Per far si, quindi, che i ports utilizzino il proxy in fase di installazione del software baster√† modificare il file RC del proprio profilo (ad esempio .cshrc per l’utente root) aggiungendo le seguenti righe:

setenv FTP_PROXY

Al fine di risolvere alcuni problemi di compatibilità con alcuni software di scuola linux (ad esempio wget) può essere utile specificare le stesse variabili anche in lower-case:

setenv http_proxy
setenv ftp_proxy

Da notare, inoltre, che √® molto importante specificare le impostazioni del proxy con la sintassi http://utente:password@host:porta/ al fine di specificare che il proxy che si sta utilizzando √® di tipo HTTP (ad esempio nel caso di SQUID). Discorso diverso invece qualora si stia utilizzando un ftp-gateway, in tal caso l’impostazione del FTP_PROXY dovr√† seguire l’apposita sintassi.

FreeBSD Ports: condivisione distfiles

Al fine di ottimizzare al massimo i tempi di installazione dei pacchetti scaricati tramite ports e minimizzare i trasferimenti da web, è possibile realizzare una struttura condivisa di gestione della directory distfiles dei ports di FreeBSD.

La directory, normalmente situata in /usr/ports/distfiles, contiene infatti tutti i pacchetti scaricati da internet per effettuare l’installazione dei ports.

La logica alla base dell’ottimizzazione √® quella di creare una singola macchina repository che condivida a tutte le altre macchine la directory distfiles. La tecnologia “nativa” per la condivisione delle directory via rete sotto FreeBSD/Unix √® l’NFS. La sua configurazione √® piuttosto semplice, ed essendo parte del base-system, non richiede alcuna installazione di software aggiuntivo.

Condivisione lato Repository

Per condividere la cartella sulla macchina di Repository sarà sufficiente attivare il servizio nfsserver ed esportare la directory.

Il primo step da effettuare √® quello di configurare il file export indicando quali directory si voglia esportare ed a quali server. Il file √® situato in /etc/export e la sua sintassi √® piuttosto basilare: ogni riga contiene il path da esportare e l’indirizzo IP (o gli indirizzi IP) che potranno accederci. Sar√† possibile inoltre specificare alcuni parametri aggiuntivi quali -ro per indicare che l’export debba essere effettuato “read-only”. Nel nostro caso, per√≤, non √® cos√¨:


A questo punto per attivare il servizio nfsserver bisogna modificare il file /etc/rc.conf aggiungendo le seguenti righe:


A questo punto per avviare manualmente il server (che comunque si avvierà al reboot della macchina) è sufficiente eseguire:

/etc/rc.d/rpcbind start
/etc/rc.d/nfsserver start
/etc/rc.d/nfsd start

Per verificare di aver effettuato tutto correttamente a questo punto si pu√≤ eseguire il comando showmount -e che elencher√† tutti i filesystem condivisi sull’attuale macchina (nonch√© chi possa accedere alle condivisioni).

Accesso al Repository

L’accesso al Repository lato client √® ancora pi√Ļ semplice: sar√† infatti sufficiente attivare il client NFS e provvedere al mount del volume remoto. Per attivare il client NFS bisogna modificare il file /etc/rc.conf aggiungendo le seguenti righe:


A questo punto per avviare manualmente il client (che comunque si avvierà al reboot della macchina) è sufficiente eseguire:

/etc/rc.d/nfsclient start

Bene, a questo punto √® possibile effettuare il mount del volume remoto. Per far ci√≤ la cosa migliore √® rinominare l’eventuale vecchia distfiles gi√† presente sul client ed effettuare il mount.

mv /usr/ports/distfiles /usr/ports/distfiles.old
mount <server>:/usr/ports/distfiles /usr/ports/distfiles

Per essere sicuri che il volume remoto venga automaticamente rimontato al boot sarà sufficiente modificare il file /etc/fstab aggiungendo una riga relativa al mount remoto:

<server>:/usr/ports/distfiles /usr/ports/distfiles nfs rw 0 0

Server WEB con Load Balancing e integrità delle sessioni (Apache 2.2 + mod_proxy_balance)

Buongiorno e grazie per l’acquisto.

Oggi configureremo un cluster di server WEB affinchè sinao in grado di bilanciare le richieste tra i componenti del cluster e garantire un certo livello di alta affidabilità.

Partiamo con gli ingredienti. Servono 3 dicasi tre server: due (presumibilmente potenti) in cluster per erogare il sito web vero e proprio ed un server (presumibilmente pi√Ļ piccolo) per effettuare il balancing delle richieste. Per dirla tutta sui due web server pu√≤ girarci un qualsiasi server web a partire da Apache 2.0 in poi mentre sul server di balancing avremo bisogno di Apache 2.2 compilato con il supporto per il mod_proxy e mod_proxy_balancer.

Per chi non lo sapesse l’unico sistema operativo degno di essere usato √® Freebsd, per cui questo how-to si appogger√† ad esso.

Per il nostro esempio definiamo i due web server come www1 ( e www2 ( mentre la macchina balancer è identificata come www (

Innanzitutto andiamo su www, dentro /usr/ports/www/apache22 e spariamoci un bellissimo make options, all’interno del quale attiveremo tutti i mod_proxy, seguito da un make install che fruller√† per parecchi minuti.

cd /usr/ports/www/apache22
make options
make install

A questo punto modifichiamo l’httpd.conf dentro /usr/local/etc/apache22 aggiungendo le seguenti righe:

<Proxy *>
Order deny,allow
Allow from all
ProxyPass /balancer-manager !
ProxyPass / balancer://mycluster/ stickysession=BALANCEID nofailover=On
ProxyPassReverse /
ProxyPassReverse /
<Proxy balancer://mycluster>
BalancerMember route=www1
BalancerMember route=www2
ProxySet lbmethod=byrequests
<Location /balancer-manager>
SetHandler balancer-manager
Order deny,allow
Allow from all

A questo punto dentro /etc/rc.conf io suggerisco di attivare lo startup di apache22 al boot e di htcacheclean che fa la pulizia della directory di cache del proxy:


Ok, il balancer √® pronto, ora dobbiamo semplicemente istruire i web server affinch√© in fase di erogazione dei contenuti venga specificato il COOKIE che permette al balancer di riassociare un client al suo server. Dentro l’httpd.conf di ognuno dei due server web incolliamo (nel virtual host che ci interessa o nella location) il seguente codice:

RewriteEngine On
RewriteRule .* – []

Attenzione ad impostare correttamente il domain del cookie, il lifetime ed il path. E soprattutto attenti ad aver attivato il mod_rewrite prima di attivare la rewriteengine. E soprattutto sul secondo server cambiate www1 in www2

Ok, restartate tutti e tre gli apache… dovrebbe funzionare.

Buon divertimento.

poi amplio il concetto…