rdiffdir: Sincronizando directorios entre sistemas distintos sin usar la red
Imaginemos que tenemos dos directorios muy grandes (de decenas o cientos de GB) que queremos mantener idénticos en dos sistemas diferentes. Por ejemplo, podríamos pensar en un directorio con documentos profesionales que queremos sincronizar entre el PC de casa y el del trabajo o en un directorio con fotos familiares que queremos sincronizar entre el PC de tu casa y el de tu madre.
La idea sería que tras modificar los ficheros en uno de los PCs, pudiéramos copiar sólo los cambios al otro PC (que en principio sería poco volumen de datos) sin tener que copiar todos los ficheros cada vez (recordemos que hablamos de muchos GB de datos).
Si ambos sistemas están conectados por red (local, Internet), aunque puede haber otras soluciones diferentes, mi solución preferida sería usar rsync (Backups con rsync), disponible en Linux, Mac OS X y Windows/Cygwin.
También podríamos optar por almacenar los datos en “La Nube“, con Dropbox, Google Drive, Skydrive, iCloud, etc. Así, si modificamos algunos ficheros en un sistema, los ficheros modificados se actualizan en la nube y, posteriormente, en los otros sistemas. Pero ojo, imaginemos que manejamos 100GB de datos. Además de que necesitamos tener al menos dicho espacio contratado en nuestro proveedor de almacenamiento en la nube, resulta que para subir inicialmente 100GB a la nube con una conexión a Internet de 1Mbps de subida necesitaríamos varios días:
100.000.000.000 bytes / ( 1.000.000 bit/s / 8 bytes/bit ) = 800.000 s = 9,26 días
Si no tenemos rsync
, ni almacenamiento en la nube, y tal vez ni acceso por red, habría quien copiaría todos los ficheros a un disco duro externo (cientos de GB) o tal vez quien llevara cuenta de qué ficheros han cambiado para copiar sólo esos a una memoria USB. Y posteriormente aún habría que volver a copiar los ficheros en el sistema destino…
Bueno, pues resulta que rdiffdir
es una solución excelente a este problema. rdiffdir
está escrito en Python, es parte de la aplicación duplicity (para hacer backups de directorios), se basa en rdiff
y usa la librería librsync
. Con rdiffdir
podemos crearnos muy fácilmente un fichero que contenga sólo los cambios con el algoritmo de rsync y aplicar dichos cambios en el sistema que esté desfasado.
Usemos por ejemplo el caso del directorio con documentos profesionales que queremos sincronizar entre el PC de casa y el del trabajo para entender cómo lo haríamos con rdiffdir
:
Partimos de un escenario en el que los directorios están perfectamente sincronizados en ambos sistemas. Acabamos de llegar al trabajo, y el directorio que queremos sincronizar contiene lo siguiente:
trabajo ~ $ find directorio/ directorio/ directorio/subdirectorio1 directorio/subdirectorio1/ficheroA.txt directorio/subdirectorio2 directorio/subdirectorio2/ficheroB.txt trabajo ~ $ cat directorio/subdirectorio1/ficheroA.txt Prueba A trabajo ~ $ cat directorio/subdirectorio2/ficheroB.txt Prueba B
Antes de comenzar a trabajar, generamos un fichero con los checksums de los bloques de los ficheros y con la información de los directorios con rdiffdir
:
trabajo ~ $ rdiffdir signature directorio signature_$(date +%y%m%d).rdiffdir
Y comenzamos a trabajar: editamos ficheros, añadimos ficheros y directorios, borramos ficheros…
trabajo ~ $ echo "Nueva linea" >> directorio/subdirectorio1/ficheroA.txt trabajo ~ $ rm -rf directorio/subdirectorio2/ trabajo ~ $ mkdir directorio/subdirectorio3 trabajo ~ $ echo "Prueba C" > directorio/subdirectorio3/ficheroC.txt
y al final de la jornada, copiamos el fichero de firmas y generamos un fichero con los cambios:
trabajo ~ $ rdiffdir delta signature_130208.rdiff directorio cambios_$(date +%y%m%d).rdiffdir
Nos vamos a casa, copiamos el fichero de cambios, y lo aplicamos sobre el directorio:
casa ~ $ rdiffdir patch directorio cambios_130208.rdiffdir
y verificamos que, efectivamente, tenemos los cambios del día:
casa ~ $ find directorio directorio directorio/subdirectorio1 directorio/subdirectorio1/ficheroA.txt directorio/subdirectorio3 directorio/subdirectorio3/ficheroC.txt casa ~ $ cat directorio/subdirectorio1/ficheroA.txt Prueba A Nueva linea casa ~ $ cat directorio/subdirectorio3/ficheroC.txt Prueba C
Si pensamos hacer cambios en casa, habría que repetir el proceso: generar un fichero de firmas antes de empezar, y uno de cambios al finalizar.
Pero, ¡a ver si va a costar más el collar que el perro! ¿Qué ocupa un fichero de firmas de un directorio enorme? ¿Qué tarda en generarlo? Pues acabo de probar con un directorio con 22000 ficheros, 1400 directorios y 10GB y ha tardado sobre 6 minutos y ocupa unos 130MB: Un tamaño adecuado para poder transportarlo en una memoria USB.
duplicity está disponible en algunas distribuciones Linux (Fedora, Ubuntu, Debian). En otras, podemos compilarlo. También podemos usarlo en Windows bajo Cygwin. Hay que instalar previamente los paquetes python
, librsync1
y librsync-devel
y luego, sólo hay que bajar el fichero con las fuentes, descomprimirlo, entrar en él desde la shell de Cygwin y ejecutar:
python setup.py install
:wq!
Acabo de conocer tu página y ya llevo un rato leyendo artículos. TODOS muy buenos, pero es que hay 2 detalles que me han acabado de convertir en fan de este blog, ver a “coco” atravesando firewall y ese final de artículos, ¡espectacular! con :wq
Un saludo a ti y a todos tus seguidores que yan son uno más. seguidores++
¡Me alegro mucho de que te guste!
¡Muy interesante! Se podría haber hecho también con rsync a pesar de no tener red, pero esto obligaría a tener un pinganillo USB tan grande con la copia entera, y con tamaños grandes hoy en día no es viable.
De todos modos, con este post me ha dado por comprobar que rsync transfiera solamente los deltas (bueno, en realidad ligeramente más porque actúa a nivel de los chunks que usa internamente) al momento de transferir datos binarios. En mi caso lo comprobé con rsync + un .tar.gz + iptraf:
Transferencia inicial de el .tar.bz (1403 paquetes y 18237896 bytes transferidos):
$ rsync -a e.tar.gz user@host.com:.
│┌192.168.2.20:60946 = 1403 18237896 CLOSED eth0 │
│└192.168.2.22:22 = 1621 94028 CLOSED eth0 │
Ahora añadimos un archivo pequeño de texto plano al .tar.bz y lo retransferimos (52 paquetes y 42736 bytes transferidos):
$ rsync -a e.tar.gz user@host.com:.
│┌192.168.2.20:60980 = 52 42736 CLOSED eth0 │
│└192.168.2.22:22 = 73 33772 CLOSED eth0 │
Efectivamente transfiere el sólo diferencial más el overhead que añade el protocolo.
¡Exacto! Ahí está el problema que podemos solucionar con
rdiffdir
.Sí, sólo transfiere los bloques cambiados. En rsync’s locales (origen y destino en el mismo sistema) siempre se transfiere el fichero completo, a menos que se use la opción
--no-whole-file
. Yo una vez tenía unos ficheros gigantescos y el rsync tardaba mucho en copiarlos cada vez que tenían un pequeño cambio, porque copiaba todo el fichero. Probé con--no-whole-file
y tardaba incluso más, porque tenía que leer el fichero origen, el destino, y obtener sus checksums para compararlos y luego ver qué bloques copiar. Total, que tardaba mucho más y valía la pena copiar el fichero completo. Valdría la pena para backups en una memoria USB cuya velocidad de lectura fuera buena pero cuya velocidad de escritura fuera lamentable (algo que es bastante frecuente).Por cierto, muy interesante lo del “IPTraf”. Yo hablé del “IPerf” en “Midiendo el ancho de banda de red con IPerf (y con scp, netcat, wget)“.
¡Gracias por el comentario!