Esta web utiliza cookies, puedes ver nuestra política de cookies, aquí Si continuas navegando estás aceptándola

ZFS el sistema de ficheros definitivo


ZFS posee unas características muy interesantes:

  • Pooled storage: El almacenamiento está formado por un pool de dispositivos permitiendo su ampliación de forma transparente
  • Snapshots: Gracias al COW ZFS permite snapshots instantáneos
  • Data integrity: Verificación y reparación automática
  • Huge Storage: Ficheros de hasta 16Exabytes, una capacidad de almacenamiento total de 256 quadrillones de zetabytes
  • Copy-on-write: Cuando se realiza un cambio sobre un fichero NO se sobreescriben los bloques correspondientes si no que se conserva el fichero original, se escriben los cambios en otros bloques y se modifica la metainformación del fichero para saber donde se encuentra la última información del fichero. Esto nos permite hacer snapshots en 0 time ya que el fichero original no se modifica para nada.

Otra peculiaridad de ZFS es que utiliza dos niveles de caché para lecturas:

  • ARC (Adaptive Replacement Cache): Memoria caché en RAM
  • L2ARC (ARC de nivel 2): Extensión del ARC pero en disco duro.
  • ZIL (ZFS Intent Log): Cuando se escribe un dato en ARC-RAM se escribe también en el ZIL de este modo si se apaga de forma abrupta el sistema se pueden leer los datos del ZIL y volcarlos al disco duro principal.

NOTA L2ARC: Los datos almacenados en L2ARC deben ser indexados en RAM reduciendo la cantidad disponible de esta. La regla habitual es que 100GB de L2ARC ocupan 1-2GB de RAM real.

NOTA ZIL: Si no se asigna un ZIL se utilizará el disco principal para tal fín, con la pérdida de rendimiento que ello conlleva.

La información cifrada NUNCA pasa por un L2ARC ya que se considera RAM y los datos en RAM no se cifran, pero además se guardarían los datos descifrados en un soporte no volátil por lo que supondría una brecha de seguridad.

Podemos consultar las estadísticas de ARC y L2ARC con el siguiente comando:

cat /proc/spl/kstat/zfs/arcstats

El kernel que estemos corriendo debe tener ciertos parámetros habilitados para que ZFS pueda funcionar, compilamos nuestro kernel con dichas opciones habilitadas:

emerge -av gentoo-sources

Las opciones a habilitar son:

 * CONFIG_MODULES
 * CONFIG_BLK_DEV_INITRD

Compilamos y arrancamos el nuevo kernel.

cd /usr/src/linux
make menuconfig
make -j8 && make -j8 modules && make install && make modules_install && grub-mkconfig -o /boot/grub/grub.cfg
reboot

Compilamos los módulos de ZFS del kernel desde fuera:

emerge -av sys-kernel/spl
emerge -av zfs sys-fs/zfs-kmod

Arrancamos todos los servicios asociados a ZFS:

for i in zfs*; do /etc/init.d/$i start; done
for i in zfs*; do rc-update add $i default; done

Para realizar nuestras pruebas voy a generar unos ficheros que actuarán a modo de disco duro loopback.

dd if=/dev/zero of=loopbackfile0.img bs=500M count=1
losetup -fP loopbackfile0.img
dd if=/dev/zero of=loopbackfile1.img bs=500M count=1
losetup -fP loopbackfile1.img
dd if=/dev/zero of=loopbackfile2.img bs=500M count=1
losetup -fP loopbackfile2.img
dd if=/dev/zero of=loopbackfile3.img bs=500M count=1
losetup -fP loopbackfile3.img
dd if=/dev/zero of=loopbackfile4.img bs=500M count=1
losetup -fP loopbackfile4.img
losetup -a
/dev/loop1: [2054]:9702894 (/root/loopbackfile1.img)
/dev/loop4: [2054]:9702897 (/root/loopbackfile4.img)
/dev/loop2: [2054]:9702895 (/root/loopbackfile2.img)
/dev/loop0: [2054]:9702893 (/root/loopbackfile0.img)
/dev/loop3: [2054]:9702896 (/root/loopbackfile3.img)

Primero debemos crear el zpool, por ejemplo un RAID1 con L2ARC sería del siguiente modo:

zpool create tank mirror /dev/loop0 /dev/loop1 cache /dev/loop2

Consultamos el zpool:

zpool list
NAME   SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
tank   480M   110K   480M         -     0%     0%  1.00x  ONLINE  -

Comprobamos la topología del zpool:

  pool: tank
 state: ONLINE
  scan: none requested
config:

    NAME        STATE     READ WRITE CKSUM
    tank        ONLINE       0     0     0
      mirror-0  ONLINE       0     0     0
        loop0   ONLINE       0     0     0
        loop1   ONLINE       0     0     0
    cache
      loop2     ONLINE       0     0     0

errors: No known data errors

Ahora imaginemos que queremos meter ZIL espejado al zpool existente:

zpool add tank log mirror /dev/loop3 /dev/loop4
zpool status
  pool: tank
 state: ONLINE
  scan: none requested
config:

    NAME        STATE     READ WRITE CKSUM
    tank        ONLINE       0     0     0
      mirror-0  ONLINE       0     0     0
        loop0   ONLINE       0     0     0
        loop1   ONLINE       0     0     0
    logs
      mirror-1  ONLINE       0     0     0
        loop3   ONLINE       0     0     0
        loop4   ONLINE       0     0     0
    cache
      loop2     ONLINE       0     0     0

errors: No known data errors

En los zpools podemos crear volumenes que es realmente lo que el usuario final utilizará:

zfs create tank/data
zfs list
NAME        USED  AVAIL  REFER  MOUNTPOINT
tank        117K   352M    24K  /tank
tank/data    24K   352M    24K  /tank/data

Para montar un volumen ejecutamos:

zfs mount tank/data

Para desmontarlo:

zfs unmount tank/data

Para eliminarlo:

zfs destroy tank/data

NOTA: Un volumen no puede ser eliminado si existe algún snapshot.

Según nuestras necesidades optaremos por un tipo de raid u otro:

  • RAIDZ: Maximiza el espacio en disco y se comporta bien cuando las lecturas y escrituras se hacen en bloques de 128K o superior.
  • RAIDZ2: El rendimiento es prácticamente igual que RAIDZ pero es mas tolerante a fallos.
  • RAIDZ3: El rendimiento es prácticamente igual que RAIDZ pero es mas tolerante a fallos incluso que RAIDZ2.
  • MIRROR: Apropiado para lecturas grandes, aleatorias y no cacheables.

Las properties de ZFS son las opciones de configuración que permite, a continuación algunos valores típicos y como deshabilitarlos:

  • quota=20m,none -> Cota de 20MB
  • reservation=20m,none -> Reserva 20MB dentro del zpool para el volumen indicado
  • compression=zle,gzip,on,off -> Habilita la compresión de datos
  • sharenfs=on,off,ro,nfsoptions -> Comparte el volumen vía NFS
  • exec=on,off -> Controla si se permitirá la ejecución de binarios en el volumen
  • setuid=on,off -> Controla si el SUID o GUID puede ser asignado al volumen
  • readonly=on,off -> Configura el volumen como RO
  • atime=on,off -> Actualiza la hora de acceso a los ficheros del volumen
  • dedup=on,off -> Habilita la deduplicación de ficheros
  • mountpoint=none,path -> Asigna un punto de montaje al volumen, un volumen sin punto de montaje no puede ser montado

Para asignar properties es tan sencillo como:

zfs set <property> ZPOOL/VOLUME
zfs umount tank/data
zfs set mountpoint=/mnt/data tank/data
mkdir /mnt/data
zfs mount tank/data

df -h
S.ficheros     Tamaño Usados  Disp Uso% Montado en
tank/data        352M   201M  152M  57% /mnt/data

Para consultar las properties:

zfs get <property> ZPOOL/VOLUMEN
zfs get all

Los snapshots son realmente útiles, sobretodo en servidores de virtualización. Vamos a hacer una prueba muy simple para comprobar que podemos recuperar un fichero.

Creamos el fichero con un contenido:

cd /tank/data
echo AA > fichero
cat fichero
AA

Tomamos el snapshot:

zfs snapshot tank/data@snapshot0

zfs list -t snapshot -o name,creation
NAME                 CREATION
tank/data@snapshot0  vie nov 30  9:12 2018

Eliminamos el fichero:

rm fichero
ls -la fichero
ls: no se puede acceder a 'fichero': No existe el fichero o el directorio

Ejecutamos un rollback del volumen:

zfs rollback tank/data@snapshot0

ls -la fichero
-rw-r--r-- 1 root root 3 nov 30 09:11 fichero

cat fichero
AA

Si hay snapshots intermedios se debe utilizar la opción -r, esto nos eliminará los snapshots intermedios PERDIENDO los datos de los estados intermedios.

zfs list -t snapshot -o name,creation
NAME                 CREATION
tank/data@snapshot0  vie nov 30  9:12 2018
tank/data@snapshot1  vie nov 30  9:15 2018
tank/data@snapshot2  vie nov 30  9:15 2018

zfs rollback tank/data@snapshot0 -r
zfs list -t snapshot -o name,creation
NAME                 CREATION
tank/data@snapshot0  vie nov 30  9:12 2018

Como se puede ver solo existe el snapshot0 por lo tanto los datos del snapshot1/2 se han eliminado siendo imposible recuperarlos.

Si solo queremos consultar los datos de un snapshot sin tener que revertir podemos clonar el snapshot:

zfs clone tank/data@snapshot0 tank/data_snapshot0_restored

cat /tank/data_snapshot0_restored/fichero
AA

Para eliminar snapshots ejecutaremos:

zfs destroy tank/data@snapshot0

Cuando se accede a un fichero ZFS comprueba si este está corrupto en caso de estarlo lo repara automaticamente, si queremos podemos forzar la comprobación de todos los ficheros de un zpool pero debemos tener en cuenta que esta tarea penalizará mucho el rendimiento del sistema.

zpool scrub tank

Cada vez que actualicemos los ebuilds(sys-kernel/spl sys-fs/zfs-kmod) se debe actualizar la info de los zpools, de este modo se podrán utilizar las properties añadidas y novedades de esa versión de ZFS:

zpool upgrade tank

Se puede hacer en todos de forma simultánea:

zpool upgrade -a

Algunos comando que nos pueden resultar útiles son:

zpool history
zfs get all
zfs mount
tank                            /tank
tank/data                       /tank/data
zfs list -r -t filesystem -o name,used,available
NAME        USED  AVAIL
tank        870K   351M
tank/data    24K   351M

 TROUBLESHOOTING:

Uno de los mayores problemas de ZFS es el consumo de RAM para cacheo de ficheros, podemos controlar su consumo ajustando ciertos parámetros, en este caso asignamos 512MB como máximo y mínimo:

zfs_arc_min: echo 536870912 >> /sys/module/zfs/parameters/zfs_arc_min
zfs_arc_max: echo 536870912 >> /sys/module/zfs/parameters/zfs_arc_max

O por fichero de configuración para que los cambios sean permanentes:

echo "options zfs zfs_arc_min=536870912" >> /etc/modprobe.d/zfs.conf
echo "options zfs zfs_arc_max=536870912" >> /etc/modprobe.d/zfs.conf

NOTA: La ram a utilizar es la ram útil que tiene ARC, si existe fragmentación podría llegar a consumir mas ram de la calculada

Podemos obtener información detallada sobre la configuración de ZFS mediante la herramienta zsb.

Información de los pools:

zdb -C tank

MOS Configuration:
        version: 5000
        name: 'tank'
        state: 0
        txg: 460
        pool_guid: 10382341371660161881
        errata: 0
        hostname: 'DirtyCow'
        com.delphix:has_per_vdev_zaps
        vdev_children: 2
        vdev_tree:
            type: 'root'
            id: 0
            guid: 10382341371660161881
            create_txg: 4
            children[0]:
                type: 'mirror'
                id: 0
                guid: 12373406537112306084
                metaslab_array: 256
                metaslab_shift: 24
                ashift: 9
                asize: 519569408
                is_log: 0
                create_txg: 4
                com.delphix:vdev_zap_top: 129
                children[0]:
                    type: 'disk'
                    id: 0
                    guid: 3391309208964634861
                    path: '/dev/loop0'
                    whole_disk: 0
                    DTL: 657
                    create_txg: 4
                    com.delphix:vdev_zap_leaf: 130
                children[1]:
                    type: 'disk'
                    id: 1
                    guid: 11015478610334838947
                    path: '/dev/loop1'
                    whole_disk: 0
                    DTL: 656
                    create_txg: 4
                    com.delphix:vdev_zap_leaf: 131
            children[1]:
                type: 'mirror'
                id: 1
                guid: 14701153478747927520
                metaslab_array: 384
                metaslab_shift: 24
                ashift: 9
                asize: 519569408
                is_log: 1
                create_txg: 16
                com.delphix:vdev_zap_top: 133
                children[0]:
                    type: 'disk'
                    id: 0
                    guid: 8139351152555853795
                    path: '/dev/loop3'
                    whole_disk: 0
                    DTL: 655
                    create_txg: 16
                    com.delphix:vdev_zap_leaf: 134
                children[1]:
                    type: 'disk'
                    id: 1
                    guid: 11777569905756971852
                    path: '/dev/loop4'
                    whole_disk: 0
                    DTL: 654
                    create_txg: 16
                    com.delphix:vdev_zap_leaf: 135
        features_for_read:
            com.delphix:hole_birth
            com.delphix:embedded_data

Información de los datasets:

zdb -d tank

Dataset mos [META], ID 0, cr_txg 4, 821K, 86 objects
Dataset tank/data [ZPL], ID 515, cr_txg 26, 24.0K, 6 objects
Dataset tank [ZPL], ID 51, cr_txg 1, 25.0K, 7 objects
Verified large_blocks feature refcount of 0 is correct
Verified large_dnode feature refcount of 0 is correct
Verified sha512 feature refcount of 0 is correct
Verified skein feature refcount of 0 is correct
Verified edonr feature refcount of 0 is correct
Verified userobj_accounting feature refcount of 2 is correct

También podemos consultar el I/O:

zpool iostat -v

              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank         964K   479M      0      5  1,55K   201K
  mirror     964K   479M      0      5  1,19K   199K
    loop0       -      -      0      2    623  99,4K
    loop1       -      -      0      2    599  99,4K
logs            -      -      -      -      -      -
  mirror        0   480M      0      0    366  2,38K
    loop3       -      -      0      0    183  1,19K
    loop4       -      -      0      0    183  1,19K
cache           -      -      -      -      -      -
  loop2       34K   495M      0      0     49  72,8K
----------  -----  -----  -----  -----  -----  -----

Si observamos mediante iostat que el I/O sube a los límites del enlace de la controladora de disco con el disco, podemos modificar el recordsize(tamaño de bloque), solo afectará a los ficheros nuevos.

zfs set recordsize=64k ZPOOL/VOLUME

https://blogs.oracle.com/roch/entry/tuning_zfs_recordsize
Tuning recordsize is aimed at improving workloads that intensively manage large files using small random reads and writes.

Algunos aspectos importantes a tener en cuenta cuando se está utilizando ZFS son:

  • No es posible retirar discos de un zpool una vez creado
  • Mas de 9 discos en un RAIDZ penaliza el rendimiento
  • No es posible meter mas discos a un RAIDZ1 y RAIDZ2, solo spares, pero si que podemos quitar un disco, sustituirlo por uno de mayor tamaño, luego el segundo disco consuiguiendo así ampliar el espcio disponible.
  • Mantener la ocupación de los pools por debajo del 80% es muy importante, dada la naturaleza del sistema copy-on-write, el pool puede sufrir una alta fragmentación, ZFS no cuenta con una herramienta de desfragmentación integrada. La única forma de desfragmentar un pool es clonar a otro medio, ya sea mediante zpool attach o ZFS send / ZFS recv.

Algunos consejos útiles:

  • No utilizar particiones para zpools si no discos completos
  • Habilitar la compresion en discos SSD
  • Programar Scrubbings a horas de poca actividad

Autor: Kr0m -- 06/12/2018 13:22:54