37 – Sincronizando archivos: lsyncd

Te doy la bienvenida al episodio 37 de deployandome, el podcast de tecnología para sysadmins y devops. Soy Rodolfo Pilas y estoy grabando el 2 de mayo de 2019.

Hace un rato que no deployo una edición del podcast, confío que a partir de ahora poder hacerlo en forma en forma periódica. Por supuesto, que siempre puedes seguir cuando sale una edición nueva a través de twitter o instagram @deployandome, o escuchar con tu aplicación de podcast preferida, porque tendrá mucho espacio entre ediciones, pero seguro está en todos lados que he conseguido publicarlo.


Me ha sucedido muchas veces que me piden replicar, copiar, espejar los archivos de una carpeta en otro servidor. Generalmente cuando se desea tener una contingencia pasiva del servicio que presta un servidor, es decir, que el servidor principal recibe archivos y se copian a un segundo equipo como contingencia si el primero falla.

No creo que esta sea una situación muy excepcional ya que personalmente me ha pasado unas cuantas veces y estamos hablando aquí de algo adicional a un método de respaldos. Mientras que un respaldo habilita puntos de recuperación históricos, sincronizar archivos entre servidores, de mantener un espejo de un servidor en otro.

Si has estado en la situación de armar una solución que cumpla estos requerimientos, me inclino a pensar que optaste por lo que siempre suelo optar en primer lugar: por rsync.

rsync es una herramienta espectacular para hacer esta sincronización. Cada vez que se corre rsync compara los archivos del origen con el destino y trasmite solamente los diferenciales binarios. Rsync copiará obviamente los archivos nuevos, puede borrar los que no existen más en el origen, pero no copiará los archivos que han cambiado; lo que hace rsync obtener hashes de trozos de los archivos y comparar con el hash correspondiente en destino, si e hash coincide procesa el pedazo siguiente y si no coincide, transfiere el pedazo hasta igualarlo en el destino. Al final los archivos quedan idénticos.

Por esta funcionalidad rsync es muy apreciado a la hora de copiar archivos grandes sobre redes que pueden introducir errores o cortes de comunicación, pues cuando la tarea finalice puedes estar seguro que los archivos son iguales.

Pero rsync tiene un problema bastante grave: no escala.

Si tengo una carpeta con 100 archivos rsync revisará cada uno buscando diferencias y si están iguales finaliza su tarea, para esto demora algunos segundos. Ahora supongamos que estmos frente a una una carpeta con 4 millones de archivos, como ya me ha pasado, y supongamos también que solo un archivo ha cambiado o es nuevo, entonces rsync revisara los 3.999.999 archivos iguales y sincronizará solo el archivo que ha cambiado, para lo cual seguramente demorará... si, muchas horas. Por lo tanto hay un problema de escala donde rsync deja de ser óptimo por el tiempo que demora, necesitamos algo más inteligente ... y de eso, te voy a contar en esta edición de deployandome


Si has seguido la explicación anterior, te habrás dado cuenta que el problema de escala que tiene rsync se soluciona dándole inteligencia como para evitar procesar archivos que ya han sido copiados a destino.

Y como todo en ingeniería, la solución para este problema puede ser abordada desde distintas enfoques.

Un enfoque simple, es decirle a rsync que si el archivo existe en destino lo considere como idéntico y no lo revise por pedazos para saber si hay cambios. Esto se logra con la opción --ignore-existing de rsync, que es ideal, por ejemplo, cuando tenemos la carpeta donde los usuarios de un sitio web suben su foto de perfil; estos archivos no se modifican, lo que sucederá que puede ser reemplazado con otro en un determinado perfil, pero nunca modificado.

Con la opción --archive rsync solo analizará el archivo remoto si la fecha del archivo local es más nueva que la del remoto..

Pero en todos los casos rsync necesita analizar, cada vez que se corre, todos los archivos del orígen y compararlos contra todos los archivos de destino.

Una opción que me sirvió durante un tiempo fue pasarle a rsync la lista de archivos de origen procesadas con el comando find con la opción -mtime que devuelve solo los archivos modificados entre la vez anterior que se corrió rsync.

Pero todas estas soluciones son remedios provisorios a los problemas de escala te comenté, pues llega un momento que esos mismos remedios son insuficientes para encarar el problema de la cantidad de archivos, pues en definitiva todos suponen revisar el 100% de los archivos de origen y con 4 millones de archivos, hasta un simple ls demora minutos en empezar a desplegar resultados.

Pero para solucionar este problema y aportar muchas más funcionalidades a la hora de sincronizar o procesar archivos nuevos o cambiados existe lsyncd del cual te voy a contar ahora.


lsyncd cómo ya supondrás por la terminación en letra d es un daemon se corre tu Linux y que está continuamente viendo una carpeta del filesystem local para interceptar los eventos de inotify y de fsevents. Inotify es un api del kernel Linux que notifica eventos de filesystem tanto de un archivo como de una carpeta. FSEvents, por su parte, es el equivalente de inotify pero para sistemas MacOSX.

Una vez que lsyncd detecta un cambio a nivel de filesystem en la carpeta que está monitoreando, puede lanzar eventos en forma asincróna que actúen exclusivamente sobre ese cambio que se acaba de producir. Es decir que si tengo una carpeta con 4 millones de archivos y agrego o modifico solo un archivo, lsyncd actuará solamente sobre ese archivo y sabe cuál es el archivo porque justamente lo anuncia inotify y no necesita revisar la totalidad de los archivos.

¿y cuáles son los eventos que puede lanzar lsyncd?

Lo más simple que puede hacer lsyncd es lanzar un rsync de ese archivo para duplicarlo a otra carpeta. Y es lo más simple pues en el archivo de configuración del daemon le indicas carpeta origin y carpeta destino y no necesitas nada más. Estas opciones de configuración lsyncd las identifica como capa 4, la más alta y más simple de configurar, donde lsyncd tiene directivas y él maneja por debajo el rsync.

En la misma capa 4, lsyncd puede lanzar un rsync+ssh para copiarlo a uno o más servidores remotos. Y aquí la configuración es carpeta de orígen, lista de servidores, opciones de conexión ssh y ya!

Por defecto lsyncd deja un log de todo lo que va haciendo que te permite conocer cómo han ido evolucionando los datos dentro de la carpeta o carpetas que monitorea.

Extendiendo la funcionalidad de lsyncd, ya en lo que denomina capa 3, podemos invocar a comandos del sistema o de bash, como cp, sed if o lo que necesitemos, pudiendo decidir si actuamos sobre la creación de nuevos archivos o sobre la modificación.

En lo que se describe como la capa 2 de configuración, lsyncd nos va a permitir hacer spawn lanzar aplicaciones, como por ejemplo pdftotext, y aquí le vamos a poder decir a lsyncd qué el evento responde a una determinada extensión. Entonces nuestro evento quedaría configurado en condiciones de: cuándo se crea un archivo, cuya extensión es .pdf, ejecute la siguiente línea del comando de pdftotext para convertir su contenido a texto plano.

Lsyncd va un paso más, en la capa de configuración más baja de lsyncd, la capa 1, tendremos a nuestra disposición todo el poder del lenguaje lua, que es un lenguaje de programación imperativo muy liviano, utilizado como lenguaje de extensión en cientos de aplicaciones para darte el poder de crear la funcionalidad extra que quieras. Los ejemplos que trae el manual de lsyncd llevan desde registros de cambios en bases de datos, notificaciones en Slack, conexiones con servicios de ftp, esperas por eventos locales o remotos, etc.


Y esto es lo interesante de lsyncd, que no solo es un replicador inteligente de archivos, con lo cual soluciona el problema de escalabilidad de rsync que te comentaba en un principio; lsyncd es un procesador de eventos a partir de los cambios en el filesystem.

Lsyncd es un Software Libre que está escrito en C y en Lua y se obtiene con licencia GPL versión 2. Se instala mediante paquete en la mayoría de las distribuciones y es un proyecto iniciado en el año 2010 por Axel Kittenberger.

Una de las cosas que hice con lsyncd fue crear simple sistema de distribución de archivos para una CDN (Content Delivery Network) que recibía las peticiones de archivos gestionadas por regiones mediante el servicio de DNS que según donde estabas ubicado en el mundo te ofrece el servidor más cercano geográficamente.


Soy Rodolfo Pilas, en twitter me puedes seguir por @pilasguru y te dejo un saludo. Confío que este podcast te haya aportado para mejorar y, como siempre, espero tus inquietudes y sugerencias comentando en deployando.me

Hasta la próxima edición.

Referencias: