Lo hice y lo entendí

El blog de Vicente Navarro
08 feb

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!

Entradas relacionadas

5 Comentarios a “rdiffdir: Sincronizando directorios entre sistemas distintos sin usar la red”

  • Miguel dice:

    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++

  • jors dice:

    ¡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.

    • 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.

      ¡Exacto! Ahí está el problema que podemos solucionar con rdiffdir.

      De todos modos, con este post me ha dado por comprobar que rsync transfiera solamente los deltas

      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!

Trackbacks y pingbacks:

Tema LHYLE09, creado por Vicente Navarro