Backup con rsync e hard links

Ecco un argomento per amministratori di reti. Un sistema rapido e soprattutto efficiente per effettuare backup incrementali con un’occupazione minima di spazio su dico.

Gli ingredienti principali sono due: rsync e gli hard links. Il tutto è stato testato solo su linux (Debian e Ubuntu) ma non vedo controindicazioni ad applicarlo su altri sistemi unix.

rsync

rsync è un utilissimo  programma per sincronizzare due alberi di directory, sia sullo stesso filesystem che attraverso diversi filesystem, sia sulla stessa macchina che (via rete) attraverso più macchine. E’ in grado di trasferire solo le porzioni di file che sono state modificate dall’ultima esecuzione rendendo il processo di sincronizzazione molto rapido.

hard links

Gli hard links sono simili ai link simbolici ma, a differenza dei link simbolici in cui abbiamo un file vero e proprio e uno o più link a quel file, con gli hard link abbiamo due files che in realtà puntano allo stesso inode, i due files occuperanno su disco lo stesso spazio di un file perché puntano agli stessi blocchi. Se modifichi uno dei due files in realtà li modifichi entrambi, la rimozione di uno dei files non comporta la cancellazione dei dati dal disco finché ci sono altri hard link che puntano allo stesso inode. Quando l’ultimo hard link viene cancellato allora vengono cancellati anche i dati dal disco.

Un hard link si può creare con

ln

oppure con

cp -l

Ecco un esempio:
Abbiamo un file di nome testfile

rsa@rsa-desktop:~$ ls -li testfile
823205 -rw-r--r-- 1 rsa rsa 104857600 2009-09-14 16:20 testfile

823205 è l’inode a cui punta questo file.
Ora creiamo un hard link di nome testfile2:

rsa@rsa-desktop:~$ ln testfile testfile2
rsa@rsa-desktop:~$ ls -li testfile2
823205 -rw-r--r-- 2 rsa rsa 104857600 2009-09-14 16:20 testfile2

Il nuovo file punta allo stesso inode del precedente. Creando questo file non abbiamo occupato altro spazio sul disco, abbiamo semplicemente aggiunto un’altro riferimento allo stesso file.
Possiamo creare un ulterore hard link usando “cp -l ” invece di “ln”:

rsa@rsa-desktop:~$ cp -l testfile2 testfile3
rsa@rsa-desktop:~$ ls -ali testfile3
823205 -rw-r--r-- 3 rsa rsa 104857600 2009-09-14 16:20 testfile3

Adesso sovrascrivo testfile (che come puoi vedere sopra è un file da circa 100M) facendolo diventare un file da 6 caratteri. Vedremo che tutti gli hard link diventano di 6 caratteri:

rsa@rsa-desktop:~$ echo "ciao " > testfile
rsa@rsa-desktop:~$ ls -li testfile*
823205 -rw-r--r-- 3 rsa rsa 6 2009-09-14 16:29 testfile
823205 -rw-r--r-- 3 rsa rsa 6 2009-09-14 16:29 testfile2
823205 -rw-r--r-- 3 rsa rsa 6 2009-09-14 16:29 testfile3


A che serve tutto ciò?

Serve a mettere in piedi un sistema di backup molto furbo ed efficiente, sia dal punto di vista della velocità che, soprattutto, dello spazio occupato su disco.

Supponiamo, per semplificare, di voler mantenere le ultime 3 versioni del nostro backup: bakcup.0 è la più recente, backup.1 la precedente e backup.2 quella ancora precedente. Ora vogliamo fare una nuova copia di backup.

Innanzitutto la più vecchia possiamo eliminarla, invece di cancellarla però ce la teniamo da parte, ci servirà più avanti per risparmiare un po’ di tempo.

mv backup.2 backup.tmp

Poi rinominiamo backup.1 in backup.2 e backup.0 in backup.1

mv backup.1 backup.2
mv backup.0 backup.1

A questo punto possiamo fare il nostro nuovo backup in backup.0. Invece di partire da zero però “ricicliamo” il più vecchio backup che avremmo dovuto cancellare. Questo passo ci aiuta a risparmiare tempo nel caso di backup voluminosi, poi vediamo perché.

mv backup.tmp backup.0

Ora abbiamo in backup.0 il backup più vecchio, lo “rinfreschiamo” con il backup più recente usando gli hard links:

cp -al backup.1/. backup.0

A cosa ci è servito riciclare il backup più vecchio? Cancellarlo ha un costo: la cancellazione ricorsiva di un gran numero di files può impiegare un po’ di tempo che in questo modo abbiamo risparmiato.
Ora che abbiamo in backup.0 gli stessi dati del backup più recente, facciamo il nuovo backup usando rsync:

rsync -a --delete source_directory/  backup.0/

Ecco fatto, rsync si limiterà ad aggiornare i files che sono stati modificati dall’ultimo backup, cancellerà quelli che sono stati eliminati e aggiungerà i nuovi. Tutto il resto non verrà toccato quindi il processo sarà molto rapido.
Anche lo spazio occupato sul disco da tutti questi backup sarà minimo perché avendo usato gli hard links, ogni file che non è stato modificato non occupa spazio aggiuntivo.

Sto usando questo sistema da un po’ di tempo per avere backup storici e funziona a meraviglia, se i dati di cui vuoi fare il backup non cambiano molto frequentemente questo sistema è veramente molto efficiente perché ti consente di mantenere un gran numero di backup storici con una occupazione del disco di poco superiore a quella che avresti con una sola copia di backup.

Quello che segue è lo script che uso al momento per mantenere le ultime 30 versioni del mio Dropbox:

#!/bin/sh

TO_BE_BACKED_UP=~/Dropbox
BACKUP_PATH=/home/backup/rsa/dropbox
BACKUP_FOLDER=backup_dropbox

echo "**********************"
date
echo "**********************"

N_BACKUPS=30
if [ -e $BACKUP_PATH/$BACKUP_FOLDER.$N_BACKUPS ];
then
 echo "$BACKUP_PATH/$BACKUP_FOLDER.$N_BACKUPS -> $BACKUP_PATH/$BACKUP_FOLDER.tmp"
 mv $BACKUP_PATH/$BACKUP_FOLDER.$N_BACKUPS $BACKUP_PATH/$BACKUP_FOLDER.tmp
fi

for i in `seq $N_BACKUPS -1 1`;
do
 j=$(($i-1))
 if [ -e $BACKUP_PATH/$BACKUP_FOLDER.$j ]
 then
 echo "$BACKUP_PATH/$BACKUP_FOLDER.$j -> $BACKUP_PATH/$BACKUP_FOLDER.$i"
 mv $BACKUP_PATH/$BACKUP_FOLDER.$j $BACKUP_PATH/$BACKUP_FOLDER.$i 
 fi
done

if [ -e $BACKUP_PATH/$BACKUP_FOLDER.tmp ];
then
 echo "$BACKUP_PATH/$BACKUP_FOLDER.tmp -> $BACKUP_PATH/$BACKUP_FOLDER.0"
 mv $BACKUP_PATH/$BACKUP_FOLDER.tmp $BACKUP_PATH/$BACKUP_FOLDER.0;
else
 mkdir $BACKUP_PATH/$BACKUP_FOLDER.0;
fi

echo "Backup of $TO_BE_BACKED_UP to $BACKUP_PATH/$BACKUP_FOLDER.0 ..."

if [ -e $BACKUP_PATH/$BACKUP_FOLDER.1/. ]
then
 echo "Copying..."
 cp -al $BACKUP_PATH/$BACKUP_FOLDER.1/. $BACKUP_PATH/$BACKUP_FOLDER.0 
fi
echo "Rsyncing..."
rsync -a --delete $TO_BE_BACKED_UP/ $BACKUP_PATH/$BACKUP_FOLDER.0/

echo "Done."

4 commenti su “Backup con rsync e hard links

  • Ciao Rudy,
    interessante…ma mi sono perso al comando:
    cp -al backup.1/. backup.0
    ti faccio alcune domande:
    1)se ora i due file backup.1 e .0 puntano allo stesso inode,
    cosa ne rimane dei blocchi di memoria che erano assegnati al file backup.0?
    2)con il comando rsync aggiorni il file backup.0 che punta agli stessi blocchi di memoria del file backup.1, quindi modifichi anche il file backup.1 perdendo questa versione. Xche?

    ciao, grazie
    S.

  • Ciao Sandro,
    ecco le risposte.

    “1)se ora i due file backup.1 e .0 puntano allo stesso inode,cosa ne rimane dei blocchi di memoria che erano assegnati al file backup.0?”

    Dopo questo cp i files contenuti nella cartella backup.0 puntano agli stessi inode dei corrispondenti files nella cartella backup.1. Se in backup.0 c’era qualche altro file che non è in backup.1 resta li dov’è e verrà cancellato successivamente da rsync. Se in backup.0 c’e un file di nome “pippo” e anche in backup.1 c’è un file con quel nome ma è diverso, allora il file “pippo” di backup.0 viene eliminato e al suo posto viene inserito un hard link al file “pippo” di backup.1. L’eliminazione del file “pippo” di backup.0 comporta la liberazione dei relativi blocchi su disco solo se non ci sono altri hard links che puntano allo stesso inode. Il filesystem si preoccupa di liberare i blocchi quando non ci sono più referenze, se c’è ancora almeno una referenza (cioè un hard link) i blocchi restano allocati.

    “2)con il comando rsync aggiorni il file backup.0 che punta agli stessi blocchi di memoria del file backup.1, quindi modifichi anche il file backup.1 perdendo questa versione. Xche?”

    Facciamo sempre riferimento al nostro file “pippo” che esiste in backup.1 e, dopo il cp -l, esiste anche in backup.0. Entrambi i files “pippo” puntano a questo punto allo stesso inode.
    Supponiamo che questo file sia stato nel frattempo modificato, l’esecuzione di rsync non va a modificare il contenuto del file (sarebbe un casino perché anche il file contenuto in backup.1 verrebbe modificato) ma va ad eliminare il file “pippo” in backup.0 e crea un nuovo file (che punta quindi ad un diverso inode) contenente la nuova versione.

    Quindi solo i files che vengono modificati tra un backup e il successivo occupano nuovo spazio su disco, tutti quelli che non vengono modificati puntano agli stessi inode dei rispettivi files dei backup precedenti non occupando spazio aggiuntivo.

    Spero di essermi spiegato.
    Ciao

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *