Caso BTRFS: instantáneas (snapshots) para branchs de testing

Uso de la tecnología BTRFS

Nota: Este documento solo tiene la función pedagógica de enseñar como utilizar esta tecnología, no haciéndose responsables los autores por ningún problema o información o perdida de datos que el intento de aplicar lo aquí mencionado produzca. Hasta no conocer bien la tecnología se sugiere probar lo aquí mencionado en un ambiente de laboratorio.

Btrfs es una tecnología que cambia el paradigma de los FS de linux. Recupera todos los avances prácticos de los últimos 20 años y concibe un sistema completo de storage, incluyendo y superando gran parte de las cosas que se podían hacer con mdadm (RAIDs de Linux), lvm (Logic volume manager de Linux), enriqueciéndolo con logros y aciertos de zfs (Zettabyte File System original de open solaris y retomado como fs de facto de soluciones BSD como Free/True NAS). Es una tecnología muy flexible que facilita cosas que de otra manera serían muy costosas.

En este caso específico de estudio se indaga la utilidad de los snapshots de btrfs para facilitar la creación de un ambiente de testing en un servidor con recursos limitados.

Otros usos de snapshots no abarcados por este texto son por ejemplo el resguardo de información ante una migración o upgrade. Ante un problema en la migración o upgrade, puede volverse al estado anterior restaurando el snaphot previo. Sin embargo este uso no será descripto aquí.

Es imprescindible destacar que lo aquí mencionado solo puede ser utilizado en la medida en que las políticas de seguridad de la organización admitan la posibilidad de compartir datos entre ambientes. Ya que desde el ambiente de testing creado en el snapshot se accede, en modo lectura, a toda la información del volumen original + los cambios realizados en testing. La información original sí queda resguardada de los cambios que se realicen sobre el snaphotde testing. El volumen original y los snapshot comparten información del momento de snapshot pero no modificaciones ulteriores. Cada uno funciona como si fuese un volumen independiente, siendo transparente para las aplicaciones si la información está en bloques del volumen original o del snapshot.

Se describe a continuación las necesidades a que respondió su utilización en este caso de trabajo y su contexto:

  • Necesidad de tener la posibilidad de levantar completamente un ambiente de testing.

  • Restricción de espacio en los servidores que hacían imposible esta necesidad sin el recurso a snapshots (Instantáneas).

Instantáneas BTRFS.

Una de las facilidades más flexibles de BTRFS es la posibilidad de sacar instantáneas de un momento dado del FS. Esta instantánea puede servir como backup antes de un cambio riesgoso o explotar otra funcionalidad compartiendo gran parte de los bloques originales de FS en dos líneas de tiempo/modificaciones distintas.

El uso más frecuente del Snapshot es congelar el FS antes de los cambios para que, en el caso que algo salga mal, volver al punto de partida de manera rápida y segura.

Sin embargo, una de las funcionalidades más interesantes del snapshot es que BTRFS admite la creación de Snapshots RW, esto es con posibilidad de continuar escribiendo cambios sobre el snapshot, sin alterar el FS original, pero, al mismo tiempo, compartiendo la información que no cambia. Un snapshot RW funciona como una copia viva del FS original, pero sin duplicar la información y solo incrementa el espacio requerido para los cambios y la duplicación de la metadata. Es la tecnología ideal para generar un branch de testing, sobre todo si no hay storage suficiente para duplicar todo y la información que pueda modificarse en testing es un porcentaje pequeño del total de la información.

Descripción general del funcionamiento de los snapshots en BTRFS

No es necesario extenderse demasiado en como funciona, pero se detallan a continuación algunos aspectos técnicos a los fines de para entender como es el uso de espacio y como se mantiene actualizado el mirror del fs de producción.

BTRFS utiliza por defecto una tecnología llamada CoW (Copy on Write), es decir, si uno no se lo define explícitamente, nunca reescribe modificaciones sobre los bloques de datos originales. Esto es, por ejemplo, si yo tengo guardado un archivo y lo modifico parcialmente, cuando se graba, el FS automáticamente genera el archivo modificado a partir de los bloques originales intocados + los bloques modificados grabados en un extent distinto del original. Luego de que la escritura se realiza correctamente se libera el espacio utilizado por los bloques modificados. Esto es transparente para las aplicaciones.

Este principio de CoW se utiliza para los snapshot RW. En el contexto de un branch de testing funciona más o menos de esta manera:

  • En el momento del snapshot ocurre lo siguiente

    • Se crea un sistema de referencias (metadata) completamente nuevo que conforma la metadata del nuevo volumen snapshot .

    • Todas las nuevas referencias de los archivos apuntan a exactamente los mismos bloques de datos.

    • En el volumen ahora existen en /dataoriginal/miarchivo y /snapshot20260108/miarchivo como dos archivos separados

    • Las referencias de ambos archivos apuntan a exactamente los mismos bloques de datos en el mismo extent.

    • En el volumen se encuentra duplicada la metadata de miarchivo pero no la información o los datos que constituye el contenido del documento.

    • Para las aplicaciones se trata de dos archivos distintos situados en diferentes volumenes, sin embargo los datos ocupados por ambos son exactamente los mismos

  • Cuando abro el archivo /snapshot2026018/miarchivo, lo modifico y guardo:

    • CoW Realiza como siempre una copia de boques originales + bloques modificados y graba el nuevo archivo colocando los nuevos bloques en otro extent.

    • Cuando termina de grabar, detecta que los bloques originales estaban referenciados por la metadata desde otro lugar: /dataoriginal/miarchivo entonces no los libera

    • En este caso el archivo original queda sin tocar, el archivo nuevo puede tener bloques compartidos con el original y bloques nuevos en otro extent. Ahora /dataoriginal/miarchivo quedó intacto y /snapshot2026018/miarchivo es el archivo modificado.

    • Advertencia técnica: Lo que define si ambos archivos comparten o no los bloques originales el modo de escritura de la aplicación. Por ejemplo un procesador de texto en general reescribe todo el archivo y no una parte. Esto hace que el archivo modificado duplica completamente todos los bloques. Es decir si el archivo original tenía 10K y ahora el nuevo 15k, la cantidad de espacio real utilizado por ambos archivos, habiendo un snapshot que lo referencia, es muy probable que sea 25. Sin embargo esta operatoria sigue siendo válida para un FS  donde es muchísima la información congelada y poca la que se va cambiando día a día.

Este funcionamiento nos permite tener un snapshot sobre el que corra la plataforma de testing que comparta todos los bloques de datos del filesystem original en un momento de tiempo dado, salvo las nuevas modificaciones que se vayan haciendo en testing. Se utiliza BTRFS con subvolúmenes y reflinks para generar un entorno de testing que comparte bloques con el mirror local de producción.

El subvolumen de testing no se utiliza como snapshot histórico para restaurar un estado anterior, sino como espacio de trabajo aislado mediante Copy-on-Write, permitiendo modificaciones mínimas de bloques sin duplicar el almacenamiento completo.

La sincronización rsync desde producción opera únicamente sobre el subvolumen principal (/data) y el mecanismo interno de CoW es transparente.

Operación: creación de snapshots y su disponibilización

La creación de snapshots se puede hacer en cualquier momento en que se decida congelar el estado de la plataforma. Si se trata de una aplicación con soporte sobre base de datos, conviene hacer más o menos al mismo tiempo un backup de la base de datos de producción para que coincida lo más posible con el snapshot de los datos replicados. Como se explicó más arriba, a partir de ese momento, en el filesystem btrfs se crean dos líneas de tiempo diferentes con pasado compartido, en donde una de ellas puede ser montado en el HFS estándar del OS como volumen separado.

Si se trata de una aplicación con FS compartido por ejemplo por NFS, luego de crear el snapshot se debe montar y exportar por nfs de manera de hacerlo accesible a los nodos de aplicación que lo necesite.

Paso a paso para crear Snapshot

  1. De ser necesaria una definición estricta del momento de corte, se debería detener la aplicación durante unos segundos para que el snapshot tenga lo que realmente necesita tener.

  1. Ingresar con root al servidor que contiene el volumen BTRFS montado Ej: /var/ sería el punto en donde el volumen original está montado.

  2. Crear snapshot:

btrfs subvolume snapshot /var/app/data /var/app/data_test_$(date +'%Y%m%d%H%M%S')

Paso a paso para montar el snapshot como subvolumen

  1. Montar el subvolumen snapshot de manera permanante desde fstab.
    1. Verificar que no haya nada en el punto de montaje, ej. /appTest/data

    2. Realizar un backup de /etc/fstab por las dudas

    3. Especificar la siguiente sintaxis en fstab, tomando como base el UUID del volumen principal nombrado desde la raíz del punto de montaje. El subvolumen se le especifica en las opciones de FS (4ta columna de fstab o bien -o de mount):

UUID=xxxxxx-xxxx-xxxx-xxx-xxxxxxxxxxxx /var/appTest btrfs defaults,auto,noatime,compress=zstd,space_cache=v2,subvol=app/data_test_$(date +'%Y%m%d%H%M%S') 0 0

  1. Montar el recurso luego de la modificación de fstab:

systemctl daemon reload && mount -a

De esta manera, los cambios que se realicen sobre el volumen montado en /var/appTest se verán reflejados en el snapshot creado, y los bloques de datos que no son modificados por la plataforma de test se comparten con el volumen original.

Es importante destacar que si se borran archivos en el volumen original, los bloques de datos continuarán existiendo en la medida que tengan alguna referencia desde uno o más snapshot. Solo se liberará el espacio cuando los bloques no tengan ninguna referencia desde ningún snapshot/subvolumen.

 Un snapshot es siempre un subvolumen. La recíproca no es correcta, no todos los subvolumenes son snaphots.

¿Qué es un subvolumen en btrfs? Un subvolumen btrfs es un punto o subdirectorio a partir del cual se genera una raíz de filesystem nueva e independiente. Esto incluye el sistema de referencias a bloques y metadata aislado. Esto permite incluso enviar subvolumenes completos por la red con los comandos send y receive de btrfs. La creación de subvolúmenes es prácticamente instantánea. Para el caso de un snapshot puede requerir unos segundos más según el tamaño de la metadata a duplicar. Es importante reiterar que no se copian los bloques de datos, sino unicamente la metadata de los archivos. Los bloques de datos, en tanto no se modifiquen archivos son los mismos, sólo que ahora referenciados desde dos lugares diferentes.  

La creación de un subvolumen se ve como si fuese un subdirectorio, sin embargo no comparte estructura de metadata con el resto de los «directorios». Un subvolumen puede montarse independientemente como se hizo en este ejemplo con el subvolumen del snapshot.

Una vez montado de manera independiente, en el volumen de nivel superior, se oculta. Es decir tenemos dos maneras excluyentes de acceder a un subvolumen, si no está montado como si fuese parte de la estructura de directorios del volumen principal; si está montado únicamente desde ese punto de montaje.

Nota: Toda vez que se utilicen subvolúmenes se debe considerar que los subvolumenes constituyen una barrera para el snapshot del nivel superior. La instantánea se crea para todos los archivos de un volumen/subvolumen sin atravesar subvolumenes. Si se nos pasa en un snapshot algún subdirectorio que es un subvolumen, ese subdirectorio no tendrá ningún dato en el snapshot creado.

Comentarios cerrados.