Mis copias de seguridad
Por referencia mía y de otros, voy a dejar acá escrito y explicado cómo gestiono mis copias de seguridad. Porque los discos duros se rompen y los ordenadores desaparecen. Etc.
Primero, mi instalación: tengo un ordenador de bajomesa (tiramisu
) y un netbook (kropotkin
). Ambos corren la misma versión de Xubuntu, la última estable.
Mi primera línea de defensa contra las pérdidas de información es la sincronización de ambas máquinas. Aquellos directorios que contienen cosas que no quiero perder (documentos, fotos, código, ¡copias de seguridad de otras máquinas, incluido esto que lees ahora!, cosas que no son documentos en desarrollo, etc.) se guardan en el directorio .bck
de ambos ordenadores. Los directorios que veo son enlaces blandos (vía ln
) a subdirectorios de .bck
.
tiramisu
es máster; kropotkin
esclavo. Para sincronizar ambos, desde el segundo, periódicamente, ejecuto
rsync -av -e "ssh -l carlos" --delete \
carlos@192.168.0.192:/home/carlos/.bck/ .bck
Más interesante es cómo consigo mantener varias copias completas de los ~60GB de ficheros de /home/carlos
en un disco duro extraíble de 160GB. De hecho, tengo dos copias anuales (junio y diciembre) desde el 2007 y algo así como mensuales durante el último año. Diríase que no caben, salvo que uno haga uso de los enlaces duros (vía, de nuevo, ln
): guardo una única copia física de cada fichero, pero cada copia temporal contiene todos los ficheros.
Es decir, aquella foto mía de 2007 parece estar más de 15 veces en 15 directorios distintos, pero existe una única copia de sus contenidos en el disco. Y solo se desaparecerá cuando se borren todas ellas. Tal es la magia de los enlaces duros.
En términos prácticos, lo consigo de la siguiente manera. El disco duro externo tiene dos directorios:
folders
, que contiene directorios con marcas temporales (p.e., carlos_20130815). Cada uno de ellos contiene una copia exacta de mihome
en la fecha en cuestión.files
, un directorio que contiene únicamente ficheros y cuyo nombre es su hash (vía md5sum).
Los ficheros de los directorios contenidos en folders
son enlaces duros al fichero correspondiente en files
. El código que utilizo para generar una nueva copia de seguridad hace lo previsible:
- Crear una nueva estructura de directorios debajo de
folders
. - Calcular el _hash _de cada fichero de mi
home
. - Buscarlo en
files
y, dependiendo de si lo encuentra o no, copiarlo y enlazarlo o únicamente enlazarlo.
Es decir:
#!/bin/bash
# Variable definitions
origen=/home/carlos
destino=/media/disk-2/bck/folders/carlos_`date +%Y%m%d`
prevbck=/media/disk-2/bck/folders/`ls -t | head -1`
files_dir=/media/disk-2/bck/files2
test -d ${files_dir} || ( echo "Destination file does not exist" ; exit 2 )
cd $origen
# Creating dir structure
find . -type d -exec mkdir -p ${destino}/{} \; 2> /tmp/bck.log
function process_file {
file=$1
file_dest="$destino/${file}"
file_prev="$prevbck/${file}"
if [ -e "$file_prev" ]
then
if [ "$file" -ot "$file_prev" ]
then
ln "$file_prev" "${file_dest}"
return 1
fi
fi
# calculo el hash de cada fichero
# creo un nombre de fichero "igual" al hash
# pero reservo el 1er caracter del hash como nombre de directorio
# motivo: directorios con +100k ficheros tienen mal rendimiento
file_hash=`md5sum "$file" | cut -f1 -d" " | sed -e "s;\(.\)\(.*\);\1/\2;"`
file_hash="${files_dir}/${file_hash}"
if [ -e "${file_hash}" ]
then
ln "${file_hash}" "${file_dest}" &
else
cp "$file" "${file_dest}"
ln "${file_dest}" "${file_hash}" &
fi
}
find . -type f -name '*' -not -user root 2> /tmp/bck.log \
| while read file
do
echo $file >> /tmp/borrar
process_file "$file"
done
exit 0
El proceso tiene dos caveats. El primero es que estoy expuesto a colisiones de hash, algo que tengo sin solucionar y que me hace vivir peligrosamente. De hecho, me llena de orgullo eso de ser una persona tan sumamente sofisticada que uno de mis problemas potenciales sea explícitamente una colisión de hash.
La segunda y más seria es que mantener +100k ficheros en un disco formateado con ext3
hace que se degrade el rendimiento de los ls
y comandos similares. La solución que he ideado recientemente —aunque reconozco que igual debería probar con otro sistema de ficheros más avanzado que ext3
— consiste en utilizar el primer dígito del hash como nombre de directorio (de manera que en files
no tengo 100k ficheros sino 16 directorios (con nombres 0
-f
) con menos de 10k ficheros en promedio. Por eso la línea
file_hash=`md5sum "$file" | cut -f1 -d" " |
sed -e "s;\(.\)\(.*\);\1/\2;"`
en mi código es marginalmente más complicada que la original.
Limpio, cómodo y sencillo, creo.