ZFS, The Z File System, es un sistema de archivos avanzado diseñado para superar las limitaciones de los sistemas de archivos más comunes. Originalmente fue diseñado por Sun, y actualmente es un proyecto open source desarrollado por OpenZFS Project.

ZFS es significativamente diferente del resto de los sistemas de archivos, debido a que es más que sólo un sistema de archivos. Combina los roles tradicionalmente separados de gestor de volúmenes lógicos y sistema de archivos para obtener ventajas únicas. De esta forma, el sistema de archivos es consciente de la estructura de discos subyacente. Los sistemas de archivos tradicionales pueden ser creados sólo en un único disco (si se poseen dos discos, se necesitarán dos sistemas de archivos separados e independientes).

En las configuraciones de RAID por hardware tradicionales, este problema se resuelve presentando al sistema operativo un disco local simple construido con el espacio provisto por un número de discos físicos, sobre el cual el sistema operativo inicializa un filesystem. Incluso utilizando soluciones de RAID por software, como GEOM, el sistema de archivos cree que está trabajando sobre un dispositivo simple.

La combinación de gestor de volúmenes y sistema de archivos que posee ZFS permite crear múltiples sistemas de archivos compartiendo un mismo pool de almacenamiento disponible. Una de las grandes ventajas de conocer y gestionar la estructura de discos, es que los sistemas de archivos existentes pueden expandirse automáticamente cuando nuevos dispositivos de disco se agregan al pool. Utilizando otras tecnologías esto no es posible. Por ejemplo si gestionamos el espacio de almacenamiento con LVM en Linux y aumentamos el tamaño de un volúmen, luego será necesario redimensionar el filesystem (o incluso tabla de particiones) que usa tal volumen. Esto en ZFS no es necesario ya que es transparente: si se agrega espacio de almacenamiento al pool, los filesystems lo ven automátcamente. Además ZFS posee otras características adicionales interesantes que pueden ser aplicadas a cada sistema de archivos de forma individual, como compresión, deduplicación y snapshots.

ZFS tiene tres principales metas de diseño:

Integridad de datos: todos los datos poseen un checksum. Cuando se escribe un dato, se calcula un checksum que se guarda junto con el mismo. Cuando el dato posteriormente se lee, el checksum se computa nuevamente para detectar (y corregir si se dispone de redundancia) errores.

Almacenamiento por pooles: los dispositivos físicos de almacenamiento se agregan a un pool, y el espacio de almacenamiento se gestiona dinámicamente desde el mismo. El espacio está disponible para todos los filesystems dentro del pool, y puede incrementarse agregando más dispositivos al pool. Trabaja de forma similar a LVM en GNU/Linux.

Rendimiento: a través de múltiples mecanismos de caching.

Jerarquía de un sistema de archivos ZFS

Un pool de almacenamiento ZFS es una colección lógica de dispositivos que proveen espacio para los datasets. Un pool de almacenamiento ZFS es además la raíz (root) de la jerarquía de sistema de archivos. Esta raíz puede ser accedida como un filesystem cualquiera, pero las características físicas de almacenamiento son gestionadas por la herramienta zpool.

Dataset es el término genérico para un sistema de archivos, volumen, snapshot o clon ZFS. Cada dataset tiene un nombre único con el formato pool/path@snapshot. La raíz del pool es técnicamente un dataset más. Los datasets se nombran de forma jerárquica al igual que los directorios. Es posible crear datasets anidados, los cuales por defecto heredan las propiedades de su padre que luego pueden ser modificadas.

Los snapshots son copias de sólo lectura de un filesystem o volumen. Se crean de forma extremadamente rápida e inicialmente no consumen espacio, ya que utilizan la tecnología CoW (copy on write) al igual que LVM. De esta forma los snapshots empiezan a consumir espacio a medida que que los datos en el dataset activo cambian.

Los clones son volúmenes o sistemas de archivos de lectura/escritura cuyo contenido inicial es el mismo que el del dataset original. Al igual que los snapshots, crear un clon es instantáneo, e inicialmente no consume espacio. Los clones sólo pueden crearse desde un snapshot, y este snapshot no puede ser eliminado mientras el clon exista, aunque es posible promover (con el comando promote) el clon para no dependa más del sistema de archivos original (transformándolo así en un dataset independiente).

Mi primer servidor FreeBSD

Habiendo enumerado ya todas las ventajas y características avanzadas de ZFS, se deduce claramente que es el sistema de archivos indicado cuando se requiere almacenar grandes volúmenes de datos de forma eficiente y con alto rendimiento.

Al ser liberado bajo la licencia CDDL (incompatible con la GPL), no es posible distribuir ZFS junto con el kernel Linux. Por esta razón, desde 2008 se está desarrollando una implementación nativa para Linux, en forma de módulo del kernel (proyecto ZOL). Actualmente la implementación de ZFS para Linux se considera estable y lista para producción. Aunque aún faltan implementar algunas características de ZFS y resolver ciertas limitaciones y problemas de estabilidad.

Por lo tanto, la mejor opción para aprovechar todos los beneficios y estabilidad de un sistema de archivos ZFS es instalar un servidor FreeBSD. Mi intención entonces es montar un servidor FreeBSD 10 que funcione como repositorio de datos (datastore) dentro de mi organización, al que luego se podrá acceder mediante NFS (NAS), o tal vez iSCSI (DAS).

Instalar un servidor FreeBSD es extremadamente fácil. El artículo Cómo instalar FreeBSD 10 explica paso a paso cómo instalar FreeBSD. Por supuesto ignorar la instalación de X.org y KDE (ya que ese artículo apunta a un sistema Desktop), y seleccionar ZFS para el sistema de archivos raíz durante la instalación.

Siendo que se van a utilizar sistemas de archivos ZFS, el sistema deberá contar con suficiente memoria RAM. Y con suficiente me refiero a MUCHA. Algunas de las características que provee ZFS pueden requerir grandes cantidades de memoria para lograr una máxima eficiencia. Como mínimo, la memoria total del sistema debe ser de al menos 1 GB de RAM por cada 1 TB de almacenamiento. Pero si se usa deduplicación (mi intención es hacerlo), la regla general es es 5 GB de memoria RAM por cada 1 TB deduplicado. Para no tener problemas de performance, recomiendo un sistema con una base de 8 GB de memoria RAM, sobre todo si su uso va a ser intensivo.

Resumiendo, mi sistema posee 8 GB de RAM con una instalación fresca de FreeBSD y dos discos SCSI llamados da0 y da1:

root@fbsd10:~ # cat /var/run/dmesg.boot | grep 'disk'
Waiting (max 60 seconds) for system process `syncer' to stop...Syncing disks, vnodes remaining...0 0 0 0 0 done
da0: <VMware Virtual disk 1.0> Fixed Direct Access SCSI-2 device 
da1: <VMware Virtual disk 1.0> Fixed Direct Access SCSI-2 device

El dispositivo da0 ha sido inicializado y particionado durante la instalación de FreeBSD 10, y es donde se aloja el sistema de archivos raíz:

root@fbsd10:~ # ll /dev/da*
crw-r-----  1 root  operator  0x55 Oct 29 10:42 /dev/da0
crw-r-----  1 root  operator  0x58 Oct 29 10:42 /dev/da0p1
crw-r-----  1 root  operator  0x59 Oct 29 10:42 /dev/da0p2
crw-r-----  1 root  operator  0x5a Oct 29 10:42 /dev/da0p3
crw-r-----  1 root  operator  0x56 Oct 29 10:42 /dev/da1

Entonces resta crear e inicializar un nuevo pool ZFS sobre el dispositivo da1 para utilizar como almacenamiento de datos.

Al haber seleccionado el uso de ZFS para el sistema de archivos raíz, el nombre utilizado para el pool del sistema de archivos raíz es "zroot" (el nombre que sugiere por defecto el instalador):

root@fbsd10:~ # zpool list
NAME    SIZE  ALLOC   FREE    CAP  DEDUP  HEALTH  ALTROOT
zroot  6.94G  1.37G  5.57G    19%  1.00x  ONLINE  -

El instalador inicializó una tabla GPT en el disco con las siguientes particiones:

root@fbsd10:~ # gpart show
=>      34  16777149  da0  GPT  (8.0G)
        34      1024    1  freebsd-boot  (512K)
      1058   2097152    2  freebsd-swap  (1.0G)
   2098210  14678973    3  freebsd-zfs  (7.0G)

La partición da0p3, etiquetada como "freebsd-zfs", posee el nombre "gptid/08fc84c4-5f6f-11e4-a8ae-005056a37ba6", según lo reporta la herramienta glabel:

root@fbsd10:~ # glabel list da0p3
Geom name: da0p3
Providers:
1. Name: gptid/08fc84c4-5f6f-11e4-a8ae-005056a37ba6
   Mediasize: 7515634176 (7.0G)
   Sectorsize: 512
   Stripesize: 0
   Stripeoffset: 1074283520
   Mode: r1w1e1
   secoffset: 0
   offset: 0
   seclength: 14678973
   length: 7515634176
   index: 0
Consumers:
1. Name: da0p3
   Mediasize: 7515634176 (7.0G)
   Sectorsize: 512
   Stripesize: 0
   Stripeoffset: 1074283520
   Mode: r1w1e2

Luego se observa que el pool "zroot" está conformado únicamente por la partición "gptid/08fc84c4-5f6f-11e4-a8ae-005056a37ba6":

root@fbsd10:~ # zpool status zroot | grep -A 5 "config:"
config:

        NAME                                          STATE     READ WRITE CKSUM
        zroot                                         ONLINE       0     0     0
          gptid/08fc84c4-5f6f-11e4-a8ae-005056a37ba6  ONLINE       0     0     0

El instalador creó automáticamente los siguientes sistemas de archivos (datasets) para el sistema operativo:

root@fbsd10:~ # zfs list
NAME                 USED  AVAIL  REFER  MOUNTPOINT
zroot               1.37G  5.46G   144K  none
zroot/ROOT           854M  5.46G   144K  none
zroot/ROOT/default   854M  5.46G   854M  /
zroot/tmp            176K  5.46G   176K  /tmp
zroot/usr            545M  5.46G   144K  /usr
zroot/usr/home       144K  5.46G   144K  /usr/home
zroot/usr/ports      144K  5.46G   144K  /usr/ports
zroot/usr/src        545M  5.46G   545M  /usr/src
zroot/var           1.33M  5.46G   672K  /var
zroot/var/crash      148K  5.46G   148K  /var/crash
zroot/var/log        244K  5.46G   244K  /var/log
zroot/var/mail       148K  5.46G   148K  /var/mail
zroot/var/tmp        152K  5.46G   152K  /var/tmp

Crear un sistema de archivos ZFS es una operación muy simple, por lo que el número de sistemas de archivos tiende a ser numeroso. Para lidiar con esto, ZFS monta automáticamente los sistemas de archivos sin necesidad de editar el archivo /etc/fstab. Por defecto los filesystems se montan bajo la ruta equivalente al nombre del filesystem en el espacio de nombres de ZFS.

La salida del comando df (disk free) es:

root@fbsd10:~ # df
Filesystem         1K-blocks   Used   Avail Capacity  Mounted on
zroot/ROOT/default   6599444 874464 5724980    13%    /
devfs                      1      1       0   100%    /dev
zroot/tmp            5725156    176 5724980     0%    /tmp
zroot/usr/home       5725124    144 5724980     0%    /usr/home
zroot/usr/ports      5725124    144 5724980     0%    /usr/ports
zroot/usr/src        6282596 557616 5724980     9%    /usr/src
zroot/var            5725652    672 5724980     0%    /var
zroot/var/crash      5725128    148 5724980     0%    /var/crash
zroot/var/log        5725224    244 5724980     0%    /var/log
zroot/var/mail       5725128    148 5724980     0%    /var/mail
zroot/var/tmp        5725132    152 5724980     0%    /var/tmp

Manos a la obra

Luego de comprender cómo se relacionan a bajo nivel los discos, particiones, pooles y datasets, vamos a crear un nuevo pool utilizando el disco /dev/da1 completo (crudo, sin crear ninguna tabla de particiones).

ZFS no se preocupa por los dispositivos subyacentes, sino que acepta cualquier dispositivo por bloques (discos, particiones, etc.)

Si vamos a utilizar ZFS por primera vez, primero es necesario verificar que el mecanismo que permite a FreeBSD montar pooles ZFS durante el inicio del sistema esté habilitado:

root@fbsd10:~ # cat /etc/rc.conf | grep zfs
zfs_enable="YES"

Si está configurado en "NO", cambiar a "YES" e iniciar el servicio zfs ejecutando service zfs start.

Para crear un nuevo pool ZFS llamado "ztarahui" sobre el dispositivo /dev/da1, ejecutar:

root@fbsd10:~ # zpool create ztarahui /dev/da1

zpool es la herramienta que posee FreeBSD para gestionar pooles de almacenamiento ZFS (man zpool).

Para ver el nuevo pool creado, consultar su estado con la herramienta zpool:

root@fbsd10:~ # zpool status ztarahui | grep -A 5 "config:"
config:

        NAME        STATE     READ WRITE CKSUM
        ztarahui    ONLINE       0     0     0
          da1       ONLINE       0     0     0

También es posible revisar nuevamente la salida de df -h:

root@fbsd10:~ # df -h
Filesystem            Size    Used   Avail Capacity  Mounted on
zroot/ROOT/default    6.3G    854M    5.5G    13%    /
devfs                 1.0K    1.0K      0B   100%    /dev
zroot/tmp             5.5G    176K    5.5G     0%    /tmp
zroot/usr/home        5.5G    144K    5.5G     0%    /usr/home
zroot/usr/ports       5.5G    144K    5.5G     0%    /usr/ports
zroot/usr/src         6.0G    545M    5.5G     9%    /usr/src
zroot/var             5.5G    680K    5.5G     0%    /var
zroot/var/crash       5.5G    148K    5.5G     0%    /var/crash
zroot/var/log         5.5G    244K    5.5G     0%    /var/log
zroot/var/mail        5.5G    148K    5.5G     0%    /var/mail
zroot/var/tmp         5.5G    152K    5.5G     0%    /var/tmp
ztarahui               49G     31K     49G     0%    /ztarahui

Se observa que el pool "ztarahui" ha sido creado y montado. A partir de este momento es accesible como cualquier filesystem. Por ejemplo, es posible crear y acceder a un archivo:

root@fbsd10:~ # cd /ztarahui/
root@fbsd10:/ztarahui # ls
root@fbsd10:/ztarahui # date > prueba.txt
root@fbsd10:/ztarahui # ll
total 1
-rw-r--r--  1 root  wheel  29 Oct 30 11:12 prueba.txt
root@fbsd10:/ztarahui # cat prueba.txt
Thu Oct 30 11:12:50 ART 2014

Crear datasets dentro del nuevo pool

Hemos creado el pool exitosamente, sin embargo no está aprovechando ninguna de las ventajas de las características avanzadas que provee ZFS. Para ello es necesario definir datasets, o filesystems. Por ejemplo, para crear en el nuevo pool un dataset con compresión habilitada, utilizar la herramienta zfs de la siguiente forma:

root@fbsd10:/ztarahui # zfs create ztarahui/comprimido
root@fbsd10:/ztarahui # zfs set compression=gzip ztarahui/comprimido

He creado el dataset de nombre "comprimido", que posee compresión gzip para ahorrar espacio de almacenamiento en el pool.

El nuevo dataset es un sistema de archivos montado en la ruta /ztarahui/comprimido, al cual se puede acceder inmediatamente:

root@fbsd10:/ztarahui # df -h
Filesystem             Size    Used   Avail Capacity  Mounted on
zroot/ROOT/default     6.3G    854M    5.5G    13%    /
devfs                  1.0K    1.0K      0B   100%    /dev
zroot/tmp              5.5G    176K    5.5G     0%    /tmp
zroot/usr/home         5.5G    144K    5.5G     0%    /usr/home
zroot/usr/ports        5.5G    144K    5.5G     0%    /usr/ports
zroot/usr/src          6.0G    545M    5.5G     9%    /usr/src
zroot/var              5.5G    680K    5.5G     0%    /var
zroot/var/crash        5.5G    148K    5.5G     0%    /var/crash
zroot/var/log          5.5G    244K    5.5G     0%    /var/log
zroot/var/mail         5.5G    148K    5.5G     0%    /var/mail
zroot/var/tmp          5.5G    152K    5.5G     0%    /var/tmp
ztarahui                49G     33K     49G     0%    /ztarahui
ztarahui/comprimido     49G     31K     49G     0%    /ztarahui/comprimido
root@fbsd10:/ztarahui # ll
total 3
drwxr-xr-x  2 root  wheel   2 Oct 30 11:17 comprimido/
-rw-r--r--  1 root  wheel  29 Oct 30 11:12 prueba.txt

La herramienta zfs se utiliza para configurar datasets dentro de un pool de almacenamiento ZFS. Como mencioné anteriormente, los datasets pueden ser sistemas de archivos, volúmenes o snapshots.

Para comparar la eficiencia del dataset "comprimido", el cual utiliza la característica de compresión gzip provista por ZFS, creo un nuevo dataset llamado "sin_comprimir", esta vez sin compresión habilitada:

root@fbsd10:/ztarahui # zfs create ztarahui/sin_comprimir
root@fbsd10:/ztarahui # df -h
Filesystem                Size    Used   Avail Capacity  Mounted on
zroot/ROOT/default        6.3G    854M    5.5G    13%    /
devfs                     1.0K    1.0K      0B   100%    /dev
zroot/tmp                 5.5G    176K    5.5G     0%    /tmp
zroot/usr/home            5.5G    144K    5.5G     0%    /usr/home
zroot/usr/ports           5.5G    144K    5.5G     0%    /usr/ports
zroot/usr/src             6.0G    545M    5.5G     9%    /usr/src
zroot/var                 5.5G    680K    5.5G     0%    /var
zroot/var/crash           5.5G    148K    5.5G     0%    /var/crash
zroot/var/log             5.5G    244K    5.5G     0%    /var/log
zroot/var/mail            5.5G    148K    5.5G     0%    /var/mail
zroot/var/tmp             5.5G    152K    5.5G     0%    /var/tmp
ztarahui                   49G     35K     49G     0%    /ztarahui
ztarahui/comprimido        49G     31K     49G     0%    /ztarahui/comprimido
ztarahui/sin_comprimir     49G     31K     49G     0%    /ztarahui/sin_comprimir

Notar que todos los datasets disponen de los 49 GB que posee el pool "ztarahui".

root@fbsd10:/ztarahui # ll
total 4
drwxr-xr-x  2 root  wheel   2 Oct 30 11:20 comprimido/
-rw-r--r--  1 root  wheel  29 Oct 30 11:12 prueba.txt
drwxr-xr-x  2 root  wheel   2 Oct 30 11:21 sin_comprimir/

Para comparar la eficiencia de almacenamiento de ambos datasets, voy a copiar a cada uno de ellos el archivo de texto /var/log/bsdinstall_log, de aproximadamente 86 KB:

root@fbsd10:/ztarahui # ll /var/log/bsdinstall_log
-rw-r--r--  1 root  wheel  88144 Oct 29 10:36 /var/log/bsdinstall_log

Copio el mismo archivo dentro de ambos datasets:

root@fbsd10:/ztarahui # cp /var/log/bsdinstall_log /ztarahui/sin_comprimir/copia-bsdinstall_log
root@fbsd10:/ztarahui # cp /var/log/bsdinstall_log /ztarahui/comprimido/copia-bsdinstall_log

Si luego de copiar listamos el contenido de cada dataset, se observa que ambos filesystems reportan exactamente el mismo tamaño de archivo:

root@fbsd10:/ztarahui # ll comprimido/
total 9
-rw-r--r--  1 root  wheel  88144 Oct 30 11:22 copia-bsdinstall_log
root@fbsd10:/ztarahui # ll sin_comprimir/
total 87
-rw-r--r--  1 root  wheel  88144 Oct 30 11:22 copia-bsdinstall_log

Esto es correcto porque la compresión es transparente para el sistema de archivos, sólo es visible a nivel pool. Si en cambio examinamos cuánto espacio ocupa cada dataset dentro del pool, se nota claramente que el dataset comprimido es más eficiente en lo que respecta a espacio de almacenamiento utilizado:

root@fbsd10:/ztarahui # df -h | grep ztarahui
ztarahui                   49G     35K     49G     0%    /ztarahui
ztarahui/comprimido        49G     40K     49G     0%    /ztarahui/comprimido
ztarahui/sin_comprimir     49G    118K     49G     0%    /ztarahui/sin_comprimir

El dataset "comprimido", que utiliza compresión gzip, ocupa sólo 40 KB de almacenamiento, mientras que el dataset "sin_comprimir" utiliza 118 KB.

Notar que el espacio utilizado por el pool refleja el tamaño de los archivos que contiene exceptuando sus datasets.

Eliminar datasets

Si intentamos borrar directorios donde hay datasets montados, rm lógicamente falla:

root@fbsd10:/ztarahui # rm -r *
rm: comprimido: Device busy
rm: sin_comprimir: Device busy

Sólo borra el archivo creado en el pool, pero no los datasets, porque son filesystems montados:

root@fbsd10:/ztarahui # ll
total 3
drwxr-xr-x  2 root  wheel  2 Oct 30 11:25 comprimido/
drwxr-xr-x  2 root  wheel  2 Oct 30 11:25 sin_comprimir/

Para eliminar datasets se debe utilizar nuevamente la herramienta zfs:

root@fbsd10:/ztarahui # zfs destroy ztarahui/comprimido
root@fbsd10:/ztarahui # zfs destroy ztarahui/sin_comprimir

Junto con el dataset se borra cada directorio donde se monta:

root@fbsd10:/ztarahui # ll
total 0

Al ejecutar el comando "destroy", el sistema de archivos de cada dataset desaparece inmediatamente:

root@fbsd10:/ztarahui # df -h | grep ztarahui
ztarahui               49G     31K     49G     0%    /ztarahui

Deduplicación

La deduplicación es una de las mejores características que tiene ZFS. Deduplicación es el proceso de eliminar datos redundantes a nivel bloque, reduciendo la cantidad total de espacio de almacenamiento utilizado. Si un sistema de archivos tiene la propiedad "dedup" habilitada, los bloques de datos duplicados se remueven de forma sincrónica. El resultado es que sólo los datos únicos son almacenados y los comunes son compartidos entre archivos.

Supongamos que se crea un nuevo archivo y el contenido de uno de sus bloques es idéntico a un bloque existente. Lo que hace ZFS es, en lugar de duplicar el bloque, guardar una referencia al bloque existente. Esta funcionalidad trabaja con CoW al igual que los snapshots. Si el bloque original es modificado, antes se duplica y se guarda en el nuevo archivo (en lugar de la referencia).

Para identificar bloques duplicados ZFS utiliza un checksum de cada bloque. Si los checksums coinciden, asume que se trata de bloques idénticos, aunque es posible forzar a que verifique que sean iguales cuando coincide un checksum. Para más información, buscar la documentación del comando "dedup" en la manpage de zfs (man zfs).

Crear un dataset con deduplicación habilitada es simple, ya que es una característica que se agrega luego de crear el dataset. Por ejemplo, voy a crear ahora el dataset "data1":

root@fbsd10:/ztarahui # zfs create ztarahui/data1

Luego habililito la compresión gzip para el mismo:

root@fbsd10:/ztarahui # zfs set compression=gzip ztarahui/data1

Finalmente habilito la deduplicación en el dataset, con verificación de bloques:

root@fbsd10:/ztarahui # zfs set dedup=verify ztarahui/data1

La verificación de bloques se utiliza que no deduplique basándose sólo en los checksums de los bloques. De esta forma, cuando dos checksums coinciden, antes de deduplicar verifica que sean iguales (se evitan colisiones en hashes).

Como he mencionado anteriormente, la deduplicación es una característica de ZFS que consume mucha memoria, porque la tabla de hashes de bloques se conserva en memoria para que el proceso sea eficiente. Si no hay espacio en memoria para almacenar la tabla de hashes, el rendimiento del sistema sufrirá en gran medida.

Referencias

FreeBSD Handbook - Chapter 20. The Z File System (ZFS)

FreeBSD Handbook - Chapter 20. The Z File System (ZFS) - 20.8. ZFS Features and Terminology

FreeBSD Handbook - Chapter 20. The Z File System (ZFS) - 20.6. Advanced Topics

Wikipedia - ZFS (sistema de archivos)

ArchWiki - ZFS

Open Source Initiative Open Source Initiative - Common Development and Distribution License (CDDL-1.0)


Tal vez pueda interesarte


Compartí este artículo