Problema

Los homelabs que ejecutan contenedores y máquinas virtuales suelen mezclar workloads de alta IOPS (bases de datos, aplicaciones) con grandes volúmenes de medios estáticos. Un pool ZFS monolítico resuelve la integridad, pero obliga a activar todos los discos para cualquier acceso, lo que incrementa consumo energético y dificulta la mezcla de discos de diferentes capacidades. Además, la pérdida de dos discos en un RAIDZ2 implica la indisponibilidad total del pool, algo inaceptable cuando solo una fracción de los datos se ve afectada. El reto es diseñar una arquitectura que:

  • Mantenga integridad y autocuración para datos críticos.
  • Permita que los discos de bajo uso permanezcan en modo sleep.
  • Soporte discos de tamaños heterogéneos sin sacrificar disponibilidad.
  • Ofrezca una capa de paridad económica para archivos de gran tamaño que no requieran alta disponibilidad inmediata.

Causa

  1. Uso indiscriminado de RAIDZ/RAIDZ2: agrupa todos los discos bajo una única lógica de paridad, obligando a que cada I/O atraviese todo el conjunto.
  2. Falta de separación de perfiles de acceso: los workloads de alta latencia (bases de datos) y los de baja latencia (streaming de medios) comparten el mismo pool, generando cuellos de botella y consumo innecesario.
  3. Incompatibilidad de tamaños: ZFS requiere que los discos de un vdev tengan la misma capacidad para evitar “wasted space”. Cuando se añaden discos más pequeños, el espacio restante se pierde.
  4. Ausencia de capa de paridad ligera: SnapRAID solo protege contra la pérdida de un disco, pero no ofrece rendimiento en tiempo real; sin embargo, su bajo coste lo hace atractivo para datos “cold”.

Solución

Dividir el almacenamiento en cuatro capas lógicas, cada una implementada con la tecnología que mejor se adapta a su perfil de acceso.

1. Hot Tier – ZFS Mirrors (NVMe)

  • Objetivo: OS, contenedores LXC, bases de datos.
  • Implementación: Dos NVMe de 512 GB en espejo (mirror). ZFS brinda checksumming, autocuración y latencia mínima.
  • Ventaja: Cada I/O se resuelve en un solo disco activo, sin necesidad de activar los HDDs.

2. Critical Data Tier – ZFS Mirrors (HDD)

  • Objetivo: archivos personales, backups de máquinas, Time Machine.
  • Implementación: Vdev espejo con discos de 4 TB. El pool (tank) se exporta como dataset con compression=lz4 y recordsize=128K.
  • Ventaja: Integridad garantizada, rendimiento suficiente para lecturas aleatorias moderadas.

3. Bulk Media Tier – MergerFS + SnapRAID

  • Objetivo: biblioteca de medios, archivos de gran tamaño que pueden tolerar latencia.
  • Implementación:
    • Cada disco se formatea con su propio FS (ZFS single‑disk, ext4).
    • MergerFS crea un punto de montaje unificado (/mnt/eternity) con política epmfs (existing path, most free space).
    • SnapRAID se ejecuta cada 6 h para generar una paridad de 4 TB en un disco dedicado.
  • Ventaja: Sólo el disco que contiene el archivo solicitado se despierta; los demás permanecen en standby. La pérdida de un disco implica la pérdida de los archivos que residían en él, pero el resto del pool sigue accesible como FS tradicional.

4. Ephemeral Churn Tier – SSD aislado

  • Objetivo: descargas, extracción, staging de datos temporales.
  • Implementación: SSD de 500 GB montado en /scratch. No participa en ninguna capa de paridad.
  • Ventaja: Reduce la fragmentación y el desgaste de los HDD y NVMe.

Montaje y orden de arranque

  1. Importar los pools ZFS (rpool, tank).
  2. Montar /mnt/eternity después de que los discos subyacentes estén disponibles.
  3. Activar SnapRAID al iniciar el cron.
# /etc/fstab (fragmento relevante)
tank   /tank   zfs   defaults,noatime  0 0
rpool  /rpool  zfs   defaults,noatime  0 0
# MergerFS mount, depende de ZFS import
/mnt/eternity  /mnt/eternity  fuse.mergerfs  defaults,allow_other,nonempty,moveonenospc,category.create=ff,func.getattr=newest,func.getxattr=newest,func.statfs=ff,func.symlink=ff,x-systemd.requires=zfs-import.target  0 0

SnapRAID cron (ejemplo)

# /etc/cron.d/snapraid
0 */6 * * * root /usr/local/sbin/snapraid -c /etc/snapraid.conf sync

Cuándo aplicar esta solución

  • Síntomas: consumo de energía elevado al reproducir un solo archivo, latencia inesperada en bases de datos, o preocupación por la pérdida total de datos ante fallos múltiples.
  • Entorno: homelab con Proxmox VE o similar, al menos dos NVMe y varios HDD de distintas capacidades.
  • No recomendado: entornos donde la única prioridad sea el máximo rendimiento de I/O continuo (por ejemplo, bases de datos de producción críticas) o donde la complejidad de SnapRAID no sea aceptable por requisitos de RPO estrictos.

Verificación

  1. Comprobar que los discos HDD permanecen en standby: hdparm -C /dev/sdX debe devolver standby.
  2. Validar integridad ZFS: zpool status -v muestra ONLINE y no errors.
  3. Confirmar MergerFS: crear archivo en /mnt/eternity/test.txt y verificar que se escribe en el disco con mayor espacio libre (df -h).
  4. Revisar SnapRAID: snapraid -c /etc/snapraid.conf status debe listar los discos y la paridad sin errores.
  5. Prueba de fallo: desconectar un disco del Bulk Media Tier, acceder a archivos que no residían en él; el resto del pool debe seguir funcionando.

Notas adicionales

  • Ajuste de ARC: limitar ZFS ARC a 8 GB evita que el host con 32 GB de RAM compita con las VM.
  • Política de MergerFS: epmfs minimiza la fragmentación y favorece discos con mayor espacio libre, pero ff (full path) puede ser útil si se desea que cada contenedor tenga su propio disco.
  • SnapRAID parity size: el disco de paridad debe ser al menos tan grande como el disco más grande del pool para evitar “partial parity” y simplificar la recuperación.
  • Backups externos: SnapRAID no sustituye a un backup fuera del sitio; combinar con Proxmox Backup Server en una Raspberry Pi 5 garantiza recuperación ante desastres.
  • Monitoreo: zpool iostat -v y smartctl -a /dev/sdX pueden integrarse en Grafana para detectar aumentos de latencia o errores SMART antes de que provoquen fallos.