Introducción
ZFS es un sistema de ficheros que cuenta con una serie de características avanzadas, tales como auto-reparación o copy-on-write. No obstante, aún siendo extremádamente útil en el entorno de servidores, ZFS no está tan extendido como cabría esperar. Su licencia CDDL (incompatible con la licencia GPL de Linux) y diversos acontecimientos durante su desarrollo pusieron bastantes trabas en la implementación de este sistema de ficheros en el Kernel Linux. Dicho esto vamos a simular un escenario con Vagrant donde tendremos una máquina a la que le agregaremos varios discos, para posteriormente, instalar ZFS y “jugar” un poco con él.
Preparación del escenario
Si queréis probarlo, os dejo el Vagrantfile donde básicamente creamos una máquina Debian Buster con 5 discos adicionales de 400Mb cada uno, y añadimos los repositorios de back-ports de Debian. Estos repositorios nos harán falta a la hora de instalar el paquete, ya que al no tener una licencia GPL, el propio Debian no puede incluirlo en la rama main y mucho menos en los paquetes de la instalación.
Una vez creada la máquina, actualizamos el sistema e instalamos el paquete zfsutils-linux. Pero antes debemos instalar los linux-headers, que en mi caso corresponde con la versión del kernel 4.19.0.6.
apt upgrade -y
apt install -y linux-headers-4.19.0-6-amd64
apt install -yt buster-backports dkms spl-dkms
apt install -yt buster-backports zfs-dkms zfsutils-linuxPara comprobar que zfs está funcionando podemos ejecutar:
root@zfsMachine:~# systemctl status zfs-mount
● zfs-mount.service - Mount ZFS filesystems
Loaded: loaded (/lib/systemd/system/zfs-mount.service; enabled; vendor preset: enabled)
Active: active (exited) since Tue 2020-01-21 21:20:39 CET; 19min ago
Docs: man:zfs(8)
Main PID: 6631 (code=exited, status=0/SUCCESS)
Tasks: 0 (limit: 1150)
Memory: 0B
CGroup: /system.slice/zfs-mount.service
ene 21 21:20:39 zfsMachine systemd[1]: Starting Mount ZFS filesystems...
ene 21 21:20:39 zfsMachine systemd[1]: Started Mount ZFS filesystems.Creación y configuración de los “pool”
Un pool en ZFS sería algo así lo que un grupo de volúmenes en LVM. La principal diferencia es que con ZFS fusionamos lo que es la capa de volúmenes lógicos y la capa de RAID software. Es por esto que durante la creación y configuración de un pool, podemos definir el tipo de RAID que vamos a crear, así como otras diversas opciones; discos caché, tamaño de sectores, etc. Los tipos de RAID soportados por ZFS son los siguientes.
- RAID0. Es igual que el tradicional. Mejora velocidad lectura/escritura pero no ofrece redundancia.
- RAID1. Es igual que el tradicional. Ofrece una redundancia igual a n-1
- RAID10. No hay diferencia con el tradicional. Es la combinación del RAID 1 y 0. Es decir, es la agrupación de RAID 1 en RAID 0.
- RAIDZ 1, 2 y 3. Dependiendo del tipo tiene uno, dos o tres bit de paridad, necesitándose 3, 4 o 5 discos respectivamente.
En esta ocasión vamos a trabar con RAIDZ-2 por lo que necesitaremos 4 discos. La creación de estos pool se realiza con el comando zpool.
zpool create -f EjemploRaidZ raidz2 /dev/sdb /dev/sdc /dev/sdd /dev/sde
zpool status
pool: EjemploRaidZ
state: ONLINE
scan: none requested
config:
NAME STATE READ WRITE CKSUM
EjemploRaidZ ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sdb ONLINE 0 0 0
sdc ONLINE 0 0 0
sdd ONLINE 0 0 0
sde ONLINE 0 0 0
errors: No known data errorsDe la misma forma que en los RAID tradicionales (como cuando los gestionamos con mdadm), podemos añadir discos de reserva (hot spare). De esta manera, si uno de los discos falla, el hot spare se reemplazaría de forma automática. Para añadir un disco en modo reserva ejecutamos:
zpool add EjemploRaidZ spare sdf
zpool status
pool: EjemploRaidZ
state: ONLINE
scan: none requested
config:
NAME STATE READ WRITE CKSUM
EjemploRaidZ ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sdb ONLINE 0 0 0
sdc ONLINE 0 0 0
sdd ONLINE 0 0 0
sde ONLINE 0 0 0
spares
sdf AVAIL
errors: No known data errorsSimulación de fallos y pruebas de redundancia
Vamos a ejecutar una serie de comandos para simular un fallo de un disco con el parámetro offline y vamos a obsevar como se reemplaza automáticamente y sin perder información. Antes vamos a crear varios ficheros para comprobar que siguen manteniendo su integridad.
Aunque a priori la gestión de zfs pueda parecerse en gran medida a la gestión de RAID con mdadm, la verdad es que conceptualmente no tienen nada que ver. Ya de primeras cuando gestionamos un RAID software con mdadm, necesitamos (tras haber particionado, aplicado una capa de LVM, o no) montar el dispositivo de bloques que se nos ha generado. En contraposición, el pool que se nos genera con zfs se monta automáticamete en la raiz del sistema con el nombre que le hayamos asignado. No obstante, también podríamos generar volúmenes y posteriormente darles el formato que queramos (con la ventaja de que seguiría funcionando por debajo con zfs). Aunque esto último lo veremos en el siguiente apartado.
Por el momento vamos a generar una serie de ficheros en /EjemploRaidZ.
#Creamos un arbol de directorios
mkdir -p /EjemploRaidZ/directorio/subdirectorio/
#Creamos ficheros aleatorios
dd if=/dev/urandom of=/EjemploRaidZ/ficheroRandom bs=64K count=300
dd if=/dev/urandom of=/EjemploRaidZ/directorio/ficheroRandom bs=64K count=600
echo "Prueba de un fichero" > /EjemploRaidZ/directorio/subdirectorio/fichtestAntes de hacer fallar uno de los discos, vamos a generar un checksum de los dos ficheros aleatorios con el comando md5sum. De esta manera si cambia aunque sea un byte de alguno de los dos ficheros, el checksum será completamente distinto.
md5sum ficheroRandom
935a8851f013f41e0dab7afad20b7377 ficheroRandom
md5sum directorio/ficheroRandom
49b5591a6b7daecbecd185bae9e6f769 directorio/ficheroRandomPara simular el fallo del disco, vamos a ejecutar el siguiente comando.
zpool offline -f EjemploRaidZ sdc
zpool status
pool: EjemploRaidZ
state: DEGRADED
status: One or more devices are faulted in response to persistent errors.
Sufficient replicas exist for the pool to continue functioning in a
degraded state.
action: Replace the faulted device, or use 'zpool clear' to mark the device
repaired.
scan: none requested
config:
NAME STATE READ WRITE CKSUM
EjemploRaidZ DEGRADED 0 0 0
raidz2-0 DEGRADED 0 0 0
sdb ONLINE 0 0 0
sdc FAULTED 0 0 0 external device fault
sdd ONLINE 0 0 0
sde ONLINE 0 0 0
spares
sdf AVAIL
errors: No known data errors
md5sum ficheroRandom
935a8851f013f41e0dab7afad20b7377 ficheroRandom
md5sum directorio/ficheroRandom
49b5591a6b7daecbecd185bae9e6f769 directorio/ficheroRandomComo podemos comprobar, aunque el RAID esté degradado, gracias a que tiene una tolerancia a fallos (gracias a los 2 bits de paridad repartidos por todos los discos), seguimos obteniendo los mismos checksum por lo tanto la integridad de los ficheros está garantizada. No obstante ahora mismo nos encontramos sin redundancia, por lo que si quisiésemos acoplar el disco de reserva solo tenemos que ejecutar:
zpool replace -f EjemploRaidZ sdc sdf
zpool status
pool: EjemploRaidZ
state: DEGRADED
status: One or more devices are faulted in response to persistent errors.
Sufficient replicas exist for the pool to continue functioning in a
degraded state.
action: Replace the faulted device, or use 'zpool clear' to mark the device
repaired.
scan: resilvered 28.7M in 0 days 00:00:00 with 0 errors on Sun Jan 26 17:27:07 2020
config:
NAME STATE READ WRITE CKSUM
EjemploRaidZ DEGRADED 0 0 0
raidz2-0 DEGRADED 0 0 0
sdb ONLINE 0 0 0
spare-1 DEGRADED 0 0 0
sdc FAULTED 0 0 0 external device fault
sdf ONLINE 0 0 0
sdd ONLINE 0 0 0
sde ONLINE 0 0 0
spares
sdf INUSE currently in use
errors: No known data errorsAhora tenemos dos opciones; podemos indicar que hemos reparado el disco que nos ha fallado, o podemos eliminarlo del RAID y dejar funcionando el disco que antes teníamos de reserva. Si optamos por la primera opción, tal y como nos indica la propia salida del estado del zpool, ejecutamos zpool clear EjemploRaidZ sdc para indicar que ya hemos reparado el disco.
Si por el contrario, el disco que nos ha fallado no podemos repararlo, el método correcto sería eliminarlo del RAID (dejar trabajando al antiguo disco de reserva) y añadir un nuevo disco como reserva. En este segundo escenario ejecutaríamos zpool detach EjemploRaidZ sdc para extraerlo del RAID y después añadir otro disco como reserva, tal y como hicimos antes.
Restauración de un RAID con “rollback”
ZFS tiene una funcionalidad parecida al rollback de las bases de datos de Oracle, y es que en un determinado momento en el que hemos tenido un número de fallos mayor al nivel de redundancia que teníamos disponible, podemos volver a un estado de este mismo RAID, anteior a dichos fallos. Para poder hacer esto primero tendremos que guardar una snapshot, que será nuestro “punto de guardado” al que podremos volver posteriormente. Para crearlo tan solo ejecutamos:
zpool checkpoint EjemploRaidZVamos a generar los checksum igual que antes para comprobar la integridad de los archivos una vez que restauremos el checkpoint.
md5sum directorio/ficheroRandom
49b5591a6b7daecbecd185bae9e6f769 directorio/ficheroRandom
md5sum ficheroRandom
935a8851f013f41e0dab7afad20b7377 ficheroRandomAhora establecemos como FAULTED dos de los discos del RAID.
zpool offline -f EjemploRaidZ sdc
zpool offline -f EjemploRaidZ sde
zpool status
pool: EjemploRaidZ
state: DEGRADED
status: One or more devices are faulted in response to persistent errors.
Sufficient replicas exist for the pool to continue functioning in a
degraded state.
action: Replace the faulted device, or use 'zpool clear' to mark the device
repaired.
scan: resilvered 28.6M in 0 days 00:00:00 with 0 errors on Sun Jan 26 17:37:59 2020
checkpoint: created Sun Jan 26 17:49:02 2020, consumes 482K
config:
NAME STATE READ WRITE CKSUM
EjemploRaidZ DEGRADED 0 0 0
raidz2-0 DEGRADED 0 0 0
sdb ONLINE 0 0 0
sdf FAULTED 0 0 0 external device fault
sdd ONLINE 0 0 0
sde FAULTED 0 0 0 external device fault
errors: No known data errorsPara restaurar el estado del RAID, lo exportamos e importamos utilizando el parámtero --rewind-to-checkpoint.
zpool export EjemploRaidZ
zpool import --rewind-to-checkpoint EjemploRaidZ
zpool status
pool: EjemploRaidZ
state: ONLINE
scan: none requested
config:
NAME STATE READ WRITE CKSUM
EjemploRaidZ ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sdb ONLINE 0 0 0
sdf ONLINE 0 0 0
sdd ONLINE 0 0 0
sde ONLINE 0 0 0Y comprobamos los checksum
md5sum ficheroRandom
935a8851f013f41e0dab7afad20b7377 ficheroRandom
md5sum directorio/ficheroRandom
49b5591a6b7daecbecd185bae9e6f769 directorio/ficheroRandomComo podemos ver, todo está correcto!
Gestión eficiente del almacenamiento
Copy on write [COW]
Básicamente COW es una funcionalidad cuyo fin es el ahorro de espacio (tanto en capacidad como en inodos) a través de un tipo de copia diferencial. Para hacer uso de esto, tenemos que especificarlo con el parámetro específico de cada paquete. Por ejemplo, en el caso del comando cp, tendríamos que utilizar reflink=always. De esta forma, se crearía un fichero que funcionaría como un puntero al original e iría aumentando de tamaño conforme se fuese diferenciando del original.
No obstante, si nos encontramos en la versión de OpenZFS, empaquetada para Debian Buster, a día de hoy, esta funcionalidad no está completamente soportada.
root@zfsMachine:/EjemploRaidZ# cp --reflink=always ficheroRandom ficheroRandom2
cp: failed to clone 'ficheroRandom2' from 'ficheroRandom': Operation not supportedDeduplicación
En esencia es igual que el COW, solo que cuando lo activamos, no nos haría falta especificarlo como hicimos antes. Para activarlo tan solo ejecutamos:
# Sintaxis
# zfs set dedup=on|verify zfspool[/vol]
zfs set dedup=on EjemploRaidZCreación de volúmenes lógicos
Esta funcionalidad es de gran utilidad ya que podríamos utilizar ZFS como base de una SAN, gracias a que estos volúmenes se comportan como cualquier dispositivo de bloques a ojos del sistema operativo. Podríamos particionarlos, darles un formato, etc, y todo esto funcionando por debajo ZFS, incluyendo todas las ventajas que hemos mencionado antes! Para crear estos dispositivos de bloques necesitamos tener un zpool, como el que hicimos antes. La sintaxis básica sería la siguiente:
zfs create -V [tamaño] [nombre-del-pool]/[nombre-del-volumen]En mi caso sería:
zfs create -V 200mb EjemploRaidZ/vol1
zfs list
NAME USED AVAIL REFER MOUNTPOINT
EjemploRaidZ 209M 428M 35.9K /EjemploRaidZ
EjemploRaidZ/vol1 208M 637M 17.9K -Para poder darle algún tipo de uso dentro del sistema, tendríamos que darle un formato reconocible, en este caso lo formatearemos con ext4 y lo montaremos en /home/vagrant/vol1:
mkfs.ext4 /dev/zvol/EjemploRaidZ/vol1
mount /dev/zvol/EjemploRaidZ/vol1 /home/vagrant/vol1Comprobamos como se ha montado
lsblk -f
NAME FSTYPE LABEL UUID FSAVAIL FSUSE% MOUNTPOINT
...
zd0 174.2M 1% /home/vagrant/vol1Cifrado
Esta funcionalidad nos sería bastante util en casos como por ejemplo, almacenamiento de datos crítios en copias de seguridad. Para activarlo sobre una unidad de nuestro sistema de ficheros debemos ejecutar un comando con la siguiente sintaxis:
zpool create -O encryption=off|on|distintos-algoritmos -O keyformat=passphrase \
-O keylocation=prompt NombreDelPool /dev/DispositivoDeBloqueEn mi caso voy a utilizar el volumen que creamos antes
zpool create -O encryption=on -O keyformat=passphrase -O keylocation=prompt \
PoolCifrado /dev/zvol/EjemploRaidZ/vol1Y comprobamos que se ha creado correctamente con el cifrado correspondiente
zfs get encryption PoolCifrado
NAME PROPERTY VALUE SOURCE
PoolCifrado encryption aes-256-ccm -Snapshots
El sistema de snapshots utilizado por ZFS permite realizar instantáneas del sistema que, se almacenan en el mismo dispositivo de bloques donde se está utilizando dicho sistema de ficheros. Esto nos impediría utilizarlas en caso de desastre, pero siempre podemos recurrir a la replicación y copiarlas en otro dispositivo separado de ZFS. Aunque al principio estas snapshots no ocupan espacio, comenzarán a crecer en función de los cambios que experimente el sistema desde que se creó la instantánea. Para crear o eliminar un snapshot la sintaxis es la siguiente.
zfs snapshot zpool/vol@nombre-de-snapshot
zfs destroy zpool/vol@nombre-de-snapshotY en caso de que quisiésemos volver a una snapshot que ya hicimos con anterioridad ejecutaríamos un comando como este:
# utilizaríamos el parámetro -r en caso de que
# quisiésemos eliminar automáticamente la snapshot
# tras hacer el "rollback"
zfs rollback -r zpool/vol@nombre-de-snapshotOtras funcionalidades
Tal y como hemos visto a lo largo de esta entrada, ZFS es verdaderamente un sistema de ficheros avanzado, pero no se queda ahí. Además de todo lo que ya hemos visto (COW, RAID, Volumenes, etc), dispone de otras aplicaciones.
Discos caché y log en RAID
Para un aumento del rendimient ZFS nos ofrece la posibilidad de añadir discos caché. Esto tendría sentido en el supuesto de tener el almacenamiento principal del RAID en discos mecánicos y añadir un disco de estado sólido como un M.2 NVME PCIE.
También nos permite añadir especificar un disco log. Inicialmente pensaríamos que es un disco para guardar los ficheros de log del sistema, como los de las unidades systemd, aplicaciones como apache2, nginx, etc. Sin embargo, es una unidad también de tipo caché, que se encarga de hacer más liviano el copy-on-write, sobre todo cuando se necesitan estructuras síncronas. A este tipo de dispositivo se le conoce como ZFS Intent Log o ZIL.
Si quisiésemos definir este tipo de unidades en el RAID, tan solo tenemos que añadir a la derecha de la unidad en cuestión el parámetro cache en caso de disco caché convencional o log en caso de un disco orientado al ZIL que hemos explicado antes.
Conclusión
ZFS es verdaderamente un sistema de ficheros avanzado. Aporta una serie de funcionalidades que lo hacen sumamente útil en el caso de que necesitemos un sistema de ficheros robusto. Más allá de la redundancia que aporta según el tipo de RAID que utilicemos, hemos podido comprobar otras funciones adicionales respecto a los sistemas tradicionales como el copy-on-write o la posibilidad de generar dispositivos de bloques completamente funcionales, además de la creación de snapshots. No obstante, debido a la complejidad de su instalación y la incompatibilidad de la licencia CDDL, incompatible con la licencia de Linux GPL, hace que su uso no esté tan extendido. Dicho esto, aunque creo que el uso ZFS merece la pena debido a todo el potencial que tiene, su licencia lo condenó a caer cada vez más en el desuso, y todavía más con el desarrollo contínuo de BTRFS, el cual sí tiene una licencia compatible con el Kernel Linux