Rsync: el algoritmo que solo transmite lo que cambió en un archivo
Copiar de nuevo un archivo de 10 GB para actualizar tres líneas es un desperdicio que la mayoría de las herramientas de copia todavía cometen. El algoritmo rsync resuelve ese problema desde 1996: compara el archivo orige
Copiar de nuevo un archivo de 10 GB para actualizar tres líneas es un desperdicio que la mayoría de las herramientas de copia todavía cometen. El algoritmo rsync resuelve ese problema desde 1996: compara el archivo origen y el destino por bloques, detecta qué cambió y transmite solo esa diferencia.
Detrás del comando que casi todo desarrollador usó alguna vez para sincronizar una carpeta hay una idea elegante de ingeniería. Un checksum se desliza byte a byte sobre el archivo sin recalcularse desde cero, y esa idea, publicada por Andrew Tridgell en su tesis doctoral, terminó siendo la base de herramientas de backup modernas como Borg y Restic.
TL;DR
- El algoritmo rsync divide el archivo destino en bloques fijos y calcula dos checksums por bloque: uno débil (estilo Adler-32) y uno fuerte (MD5).- Un checksum rodante permite deslizar la ventana de comparación byte a byte sin recalcular todo desde cero.-
rsync -avz --progress origen/ destino/transfiere solo los bloques que cambiaron entre dos árboles de archivos.- La firma del archivo destino viaja primero por la red; el emisor la compara contra su propia copia y arma un delta de instrucciones.- Borg y Restic aplican la misma idea de deduplicación por bloques para backups incrementales con historial completo.- Un archivo de 1 GB con apenas un byte modificado puede sincronizarse transmitiendo solo unos pocos kilobytes de delta.- La bandera--checksumfuerza comparar por hash en vez de por tamaño y fecha de modificación: más lento, pero exacto.
Qué es el algoritmo rsync y por qué importa
rsync es tanto un programa de línea de comandos como el nombre del algoritmo de sincronización que lo hace posible. Existe desde 1996 y viene preinstalado en casi cualquier distribución Linux, en macOS y, vía WSL o Cygwin, en Windows. Su trabajo se puede enunciar en una frase: dejar dos copias de un mismo árbol de archivos idénticas moviendo la menor cantidad de datos posible por la red.
El algoritmo rsync importa porque resuelve algo que cp, scp o un cliente FTP no resuelven. Todos esos comandos retransmiten el archivo completo aunque haya cambiado un solo byte. Para un archivo de configuración de 2 KB eso no se nota, pero para una base de datos de 40 GB, un directorio de logs o la imagen de una máquina virtual, retransmitir todo en cada sincronización es directamente inviable en la mayoría de las conexiones.
La solución de Tridgell separa el problema en dos roles. Quien tiene el archivo destino, que ya tiene una versión aunque desactualizada, calcula una firma de ese archivo por bloques. Quien tiene el archivo origen recibe esa firma, la compara contra su propia copia byte a byte, y arma una lista de instrucciones: copiar el bloque 4 tal cual, o transmitir estos 37 bytes porque son literales y no existen en destino. Esa lista de instrucciones, mucho más liviana que el archivo completo, es lo único que viaja por la red.
Cómo funciona el algoritmo de sincronización delta
El proceso completo tiene cuatro pasos y ocurre cada vez que corrés rsync entre dos árboles que ya comparten una versión previa.
Primero, el receptor (el lado que tiene el archivo destino) divide ese archivo en bloques de tamaño fijo, típicamente entre 700 bytes y unos pocos kilobytes según el tamaño total del archivo. Para cada bloque calcula dos valores: un checksum débil, rápido de calcular y de actualizar, y un checksum fuerte tipo MD5, lento pero prácticamente libre de colisiones. Esa lista de pares es la firma del archivo, y es lo primero que viaja por la red, del receptor hacia el emisor.
Segundo, el emisor recibe la firma y la carga en una tabla hash indexada por el checksum débil. Después abre su propia copia del archivo y empieza a deslizar una ventana del mismo tamaño de bloque, byte a byte, calculando el checksum débil de esa ventana en cada posición.
Tercero, en cada posición de la ventana el emisor busca el checksum débil en la tabla hash. Si no hay coincidencia, ese byte se marca como literal y la ventana avanza una posición. Si hay coincidencia en el checksum débil, el emisor calcula el checksum fuerte de esa misma ventana y lo compara contra el guardado en la firma: el débil puede coincidir por azar entre datos distintos, pero el fuerte prácticamente nunca. Si ambos coinciden, todo ese bloque se reemplaza por una instrucción de copia y la ventana salta el tamaño completo del bloque en lugar de avanzar de a un byte.
Cuarto, el emisor arma una secuencia final de instrucciones y se la envía al receptor, que la aplica sobre su copia local para reconstruir un archivo idéntico al del origen. En ningún momento el receptor envía el archivo completo, y el emisor tampoco reenvía los bloques que el receptor ya tenía.
sequenceDiagram
participant D as Destino (receptor)
participant O as Origen (emisor)
D->>D: divide el archivo en bloques
D->>O: envia firma (checksum debil + fuerte por bloque)
O->>O: desliza ventana byte a byte y calcula checksum debil
O->>O: si hay match debil, verifica con checksum fuerte
O-->>D: instrucciones (copiar bloque N o bytes literales)
Note over D,O: solo viajan la firma y las instrucciones, nunca el archivo completo
flowchart TD
A["Nueva posición de la ventana deslizante"] --> B{"¿Coincide el checksum débil?"}
B -->|"No"| C["Marcar byte como literal y avanzar 1 posición"]
B -->|"Sí"| D{"¿Coincide el checksum fuerte MD5?"}
D -->|"No"| C
D -->|"Sí"| E["Emitir instrucción COPY bloque N y saltar el bloque completo"]
C --> A
E --> A
El checksum débil de rsync se actualiza en tiempo O(1) al deslizar la ventana un byte.
Ejemplos prácticos de sincronización con rsync
El comando más simple posible copia una carpeta local a otra manteniendo permisos, symlinks y timestamps:
rsync -av carpeta_local/ carpeta_backup/
La bandera -a (modo archivo) agrupa recursividad, preservación de permisos, propietarios, timestamps y symlinks en una sola opción. La -v agrega salida verbose para ver qué archivos se transfirieron. Fijate que ambas rutas terminan en barra: eso le dice a rsync que sincronice el contenido de carpeta_local dentro de carpeta_backup, no la carpeta como subdirectorio nuevo.
Un caso más realista es desplegar el build de una aplicación a un servidor remoto por SSH, excluyendo carpetas pesadas y borrando en destino lo que ya no existe en origen:
rsync -avz --delete --exclude='.git' --exclude='node_modules' -e ssh ./dist/ [email protected]:/var/www/app/current/
La -z comprime los datos en tránsito, algo útil en conexiones lentas. La -e ssh fuerza el transporte sobre un túnel SSH cifrado, y --delete hace que el destino termine siendo un espejo exacto del origen: si borraste un archivo local, también desaparece en el servidor.
Cómo empezar a usar rsync
En Debian, Ubuntu o cualquier derivado se instala con:
sudo apt install rsync
En macOS, con Homebrew (la versión que trae el sistema suele ser vieja):
brew install rsync
Confirmá que quedó instalado y qué versión de protocolo negocia con:
rsync --version
La primera línea de esa salida muestra el número de versión y, más abajo, el protocolo que usa para hablar con otra instancia de rsync; ambos lados de una sincronización necesitan protocolos compatibles.
Para exponer una carpeta como servicio, sin necesitar una cuenta SSH completa, rsync puede correr como daemon con un archivo de configuración propio. Estas son las claves exactas que necesita un módulo mínimo en /etc/rsyncd.conf:
[backups]
path = /srv/backups
comment = Modulo de backups
read only = false
uid = rsyncuser
gid = rsyncuser
hosts allow = 10.0.0.0/24
Con eso guardado, arrancás el daemon y te conectás desde otra máquina usando la sintaxis rsync://:
sudo rsync --daemon
rsync -av archivo_local.tar.gz rsync://10.0.0.5/backups/
💡 Tip: corré siempre una sincronización nueva con
--dry-run --statsprimero. La sección "Literal data" contra "Matched data" del reporte final te dice, en bytes, cuánto de la transferencia fue delta real y cuánto tuvo que enviarse completo.
Casos de uso reales del algoritmo rsync
El uso más común sigue siendo el backup incremental: correr rsync -a --link-dest=../backup-anterior origen/ backup-nuevo/ en un cron nocturno crea una copia que ocupa en disco solo lo que cambió, mientras cada snapshot completo sigue siendo navegable como una carpeta normal gracias a los hardlinks compartidos con la copia previa.
Los mirrors de paquetes de Linux sincronizan sus repositorios entre servidores usando rsync desde los años 90.
Los mirrors de paquetes de Linux (Debian, Arch, CPAN, CTAN) usan rsync desde hace décadas para replicar sus repositorios entre cientos de servidores espejo alrededor del mundo: solo los paquetes nuevos o actualizados generan tráfico real entre el mirror maestro y sus réplicas.
En el mundo del backup moderno, herramientas como Borg y Restic llevan la misma idea un paso más allá: en vez de comparar solo contra la última copia, dividen cada archivo en chunks de tamaño variable y los indexan en un repositorio con deduplicación global. El resultado no es una herramienta de sincronización de dos puntas, sino un sistema de backups con historial completo donde cada bloque único se guarda una sola vez sin importar en cuántos snapshots aparezca.
Un cuarto caso frecuente es desplegar sitios estáticos o assets de frontend a un servidor de archivos: en vez de subir el build entero por SFTP cada vez, un pipeline de CI corre rsync contra el servidor de producción y solo transfiere los archivos que el bundler realmente regeneró.
Errores comunes y buenas prácticas con rsync
La barra final en las rutas es el error más repetido. rsync -a origen destino (sin barra en origen) copia la carpeta origen completa dentro de destino, creando destino/origen/. rsync -a origen/ destino (con barra) copia el contenido de origen directamente dentro de destino. Confundir ambos casos es la causa número uno de "por qué se duplicó mi carpeta" en foros de soporte.
⚠️ Ojo:
--deleteborra en destino cualquier archivo que ya no exista en origen. Si invertiste las rutas por error, podés vaciar una carpeta que llevaba años acumulando datos en segundos. Corré siempre primero con--dry-runy revisá la lista de "deleting" antes de sacar esa bandera.
Los permisos y la propiedad de archivos solo se preservan completos si el usuario que corre rsync tiene privilegios para asignarlos, típicamente root en ambos lados. Sin eso, -a preserva lo que puede y calla el resto salvo que agregues -v para ver los avisos.
Los archivos sparse (con huecos reales en disco, comunes en imágenes de disco y bases de datos) se expanden a su tamaño lógico completo por defecto durante la transferencia. La bandera --sparse le pide a rsync que detecte esos huecos y no escriba ceros de más, algo crítico si estás sincronizando imágenes de VM de cientos de gigabytes lógicos que en realidad ocupan una fracción en disco.
Por último, los symlinks rotos o que apuntan fuera del árbol sincronizado se copian tal cual con -a y no se siguen. Si necesitás copiar el contenido real al que apuntan, la bandera es -L, y hay que usarla con cuidado porque puede generar bucles infinitos con symlinks circulares.
Comparativa: rsync frente a otras herramientas de sincronización
HerramientaCuándo usarlaVentajaLimitaciónrsyncSincronizar dos árboles de archivos que ya comparten una versión previaTransferencia delta real, sin servidor dedicadoNo guarda historial de versiones anterioresscpCopiar un archivo puntual una sola vezSimplicidad, siempre disponible junto a SSHRetransmite el archivo completo siemprercloneSincronizar contra almacenamiento en la nube (S3, GCS, Backblaze)Decenas de backends de nube soportadosEl delta real solo aplica entre rutas locales, no todos los backends lo soportan igualBorg BackupBackups con historial completo y deduplicación entre snapshotsCada bloque único se guarda una sola vez para siempreRequiere inicializar y mantener un repositorio propioUnisonSincronización bidireccional entre dos máquinas activasResuelve conflictos en ambas direccionesConfiguración más compleja que un rsync unidireccional
Profundizando: la matemática del checksum rodante
El checksum débil clásico de rsync es una variante de Adler-32 pensada para actualizarse en tiempo constante. Para una ventana de bytes b1...bn se calculan dos sumas: a = (b1 + b2 + ... + bn) mod M y b = (n*b1 + (n-1)*b2 + ... + bn) mod M, y el checksum final combina ambas como a + b*65536.
La parte clave es que, al mover la ventana un byte hacia adelante, tanto a como b se recalculan con una resta y una suma, sin volver a sumar los n bytes desde cero:
a_nueva = a_vieja - b1 + b_n_mas_1
b_nueva = b_vieja - n * b1 + a_nueva
Esa actualización en O(1) por posición es lo que hace viable deslizar la ventana byte a byte sobre archivos de gigabytes: sin ella, calcular el checksum en cada una de las millones de posiciones posibles sería tan costoso como no tener el algoritmo.
graph LR
A["Ventana en bytes 0 a 511"] -. "desliza 1 byte" .-> B["Ventana en bytes 1 a 512"]
B -. "resta byte saliente, suma byte entrante en O(1)" .-> C["Checksum actualizado sin recalcular todo"]
El checksum débil por sí solo no alcanza porque un Adler-32 de 32 bits eventualmente colisiona entre ventanas de datos distintos, sobre todo en archivos con patrones repetitivos como binarios o dumps de bases de datos. Por eso cada coincidencia débil se confirma con un hash fuerte, MD5 en el protocolo clásico o opciones más modernas como xxhash y BLAKE3 vía --checksum-choice en versiones recientes, antes de aceptar el bloque como copia válida.
El tamaño de bloque tampoco es arbitrario: rsync lo calcula por defecto como una función aproximada a la raíz cuadrada del tamaño del archivo, con un piso y un techo fijos. Bloques más chicos detectan cambios más finos pero generan firmas más pesadas; bloques más grandes bajan el overhead de la firma pero cualquier cambio dentro de un bloque obliga a retransmitirlo completo.
Vale la pena diferenciar esto de herramientas de diff binario como xdelta o bsdiff: esas necesitan tener ambos archivos, viejo y nuevo, disponibles en la misma máquina para generar el parche. El algoritmo rsync está diseñado justamente para el caso donde eso no es posible, cuando origen y destino están en dos máquinas distintas y solo uno de los dos lados necesita conocer el contenido completo del otro a través de su firma, no del archivo en sí.
Tu próximo paso: creá dos carpetas de prueba, copiá un archivo grande entre ambas, modificá unos pocos bytes en el medio con dd o un editor hexadecimal, y corré rsync -av --stats origen/ destino/ para ver en el reporte cuántos bytes realmente viajaron por la red.
📖 Resumen en Telegram: Ver resumen
Preguntas frecuentes
¿rsync necesita que el archivo completo exista en ambos lados antes de sincronizar?
La primera vez sí. Sin una firma previa para comparar, rsync transmite el archivo completo como cualquier otra herramienta de copia. El ahorro del algoritmo delta aparece a partir de la segunda sincronización contra un destino que ya tiene una versión previa del archivo.
¿Qué significa la barra al final de una ruta en rsync?
Cambia qué se sincroniza. origen/ (con barra) sincroniza el contenido de esa carpeta dentro del destino. origen (sin barra) sincroniza la carpeta completa como un subdirectorio nuevo dentro del destino.
¿rsync cifra los datos que transmite?
Depende del transporte. Con -e ssh, todo el tráfico viaja dentro de un túnel SSH cifrado. Contra un daemon rsync puro (protocolo rsync:// sin SSH), el tráfico va en texto plano salvo que agregues un túnel propio con stunnel o una VPN.
¿Cómo sé cuántos datos viajaron realmente por la red en una sincronización?
Agregá la bandera --stats al comando. El reporte final separa "Literal data" (bytes enviados completos porque no coincidieron con nada en destino) de "Matched data" (bytes que se reconstruyeron a partir de bloques que ya existían).
¿rsync sirve para sincronizar una base de datos que está recibiendo escrituras en ese momento?
No es la herramienta ideal para eso. Si el archivo cambia mientras se calcula la firma o se transmite el delta, el resultado puede quedar inconsistente. Lo habitual es detener el servicio, usar un mecanismo de snapshot del sistema de archivos, o volcar la base con una herramienta de dump antes de correr rsync sobre el archivo resultante.
¿En qué se diferencia rsync de Restic o Borg si ambos evitan retransmitir datos repetidos?
rsync compara un origen y un destino puntuales en el momento de correr el comando. Restic y Borg mantienen un repositorio con deduplicación entre todos los snapshots históricos, así que un bloque que ya se guardó hace seis meses no se vuelve a escribir aunque hoy aparezca en un archivo completamente distinto.
Referencias
- Reporte técnico de rsync: el paper original de Andrew Tridgell y Paul Mackerras donde se describe el algoritmo de checksum rodante.- Sitio oficial de rsync: documentación, manual y changelog del proyecto.- Rsync en Wikipedia: historia del proyecto y comparación con protocolos relacionados.- Borg Backup: documentación de una herramienta de backup que aplica deduplicación por bloques de contenido variable.- Restic: backup con deduplicación y cifrado que retoma la misma idea de bloques únicos.
📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.