ZFS en FreeBSD y Linux: coste de RAM en un VPS
Conoce qué aporta ZFS en FreeBSD y Linux y cuánto RAM puede usar la ARC. Evalúa snapshots, compresión y replicación en un VPS de 2 o 4 GB.
Qué ofrece ZFS y qué recursos requiere
ZFS en FreeBSD y Linux usa ahora una única base de código, OpenZFS, por lo que las funciones son las mismas en ambos sistemas. Un servidor que ejecuta ZFS obtiene datos con sumas de comprobación, instantáneas que no consumen espacio hasta que cambian los datos, replicación con zfs send y compresión que se activa con una sola propiedad. El coste principal es la memoria: la ARC (caché de reemplazo adaptativo) ocupa de forma predeterminada una parte importante de la RAM, y en un VPS (servidor privado virtual) de 2 GB o 4 GB esa memoria es precisamente la que necesita la aplicación.
Esta guía evalúa ZFS en un VPS alquilado con uno o dos discos virtuales, no en un sistema de almacenamiento con cuarenta bahías de unidades. Las funciones que siguen siendo útiles en ese entorno son las que merecen su tiempo. Conviene conocer las que no se mantienen antes de crear un pool.
OpenZFS en FreeBSD y Linux: una base de código, dos modelos de empaquetado
FreeBSD incluye ZFS en el sistema base desde FreeBSD 7.0, publicado en 2008, inicialmente como una función experimental. Desde OpenZFS 2.0, publicado en diciembre de 2020, FreeBSD y Linux se compilan a partir del mismo árbol de código fuente, por lo que zfs y zpool se comportan igual en ambos sistemas y un pool creado en uno se puede importar en el otro.
La razón por la que ZFS es un paquete en Linux y forma parte del sistema base en FreeBSD es la licencia. OpenZFS utiliza la CDDL (licencia común de desarrollo y distribución). El kernel de Linux utiliza la GPL (licencia pública general) versión 2. El proyecto del kernel considera que ambas licencias son incompatibles, por lo que el código de ZFS no se integra en la rama principal de Linux y cada distribución decide cómo distribuirlo. FreeBSD no tiene este conflicto, así que ZFS ya está incluido. Esa es toda la diferencia práctica de empaquetado. No necesita adoptar una postura al respecto.
SSD Nodes no ofrece imágenes de FreeBSD, por lo que en un servidor alquilado aquí se aplica la parte de esta guía dedicada a Linux. Si ejecuta FreeBSD en otro proveedor, un servidor FreeBSD obtiene ZFS sin tener que compilar ningún módulo y sin depender de una actualización del kernel.
Instalar ZFS y crear un pool
En Ubuntu, el módulo se incluye en los paquetes del kernel, por lo que sólo hay que instalar los comandos.
sudo apt update
sudo apt install -y zfsutils-linux
zfs versionzfs version muestra dos líneas: la versión de userland y la versión del módulo del kernel. Si sólo aparece una línea, el módulo no se ha cargado. El paquete está en el componente universe, que las imágenes de Ubuntu Server habilitan de forma predeterminada. Si apt no lo encuentra, ejecute primero sudo add-apt-repository universe.
En Debian, los paquetes están en el componente contrib y DKMS (dynamic kernel module support) compila el módulo en su máquina. Añada contrib a la línea Components: de /etc/apt/sources.list.d/debian.sources, ejecute sudo apt update y, a continuación:
sudo apt install -y linux-headers-$(dpkg --print-architecture) zfs-dkms zfsutils-linuxLa instalación compila el módulo y muestra Building initial module for 6.12.0-..., una operación que tarda unos minutos. Tenga en cuenta lo que significa: cada actualización del kernel lo vuelve a compilar, y si la compilación falla, el pool no se podrá importar hasta que corrija el problema.
En FreeBSD no hay que instalar nada. Habilite el servicio e inícielo.
sysrc zfs_enable=YES
service zfs startAhora, el pool. Primero, compruebe las rutas estables de los dispositivos, porque /dev/vdb asigna los dispositivos según el orden de detección, que puede cambiar al conectar otro volumen.
ls -l /dev/disk/by-id/
sudo zpool create -o ashift=12 tank /dev/disk/by-id/virtio-abc123def456
zpool status tankzpool status debería mostrar state: ONLINE con su dispositivo incluido en tank. ashift=12 fija en 4 KiB el tamaño mínimo de bloque del pool. Esto coincide con los SSD actuales y no se puede cambiar después de crearlo.
La mayoría de las imágenes alquiladas arrancan desde una raíz ext4, por lo que aquí ZFS se utiliza como pool de datos en un segundo volumen, no como sistema de archivos raíz. Compruebe que el dispositivo sea el que espera antes de usarlo, porque confirmar el disco NVMe que le vendieron tarda un minuto y reconstruirlo tarda toda una tarde.
Las sumas de comprobación sólo reparan cuando el pool tiene redundancia
Cada bloque que ZFS escribe incluye una suma de comprobación, y cada lectura la verifica. La detección siempre funciona. La reparación necesita una segunda copia.
En un pool de un solo disco, ZFS informa de la verdad y se detiene ahí. zpool status -v lo muestra así:
status: One or more devices has experienced an error resulting in data
corruption.
action: Restore the file in question if possible. Otherwise restore the
entire pool from backup.
errors: Permanent errors have been detected in the following files:
/tank/data/archive.tarSe identifica el archivo dañado. ext4 habría devuelto esos bytes sin informar del problema, así que esto ya aporta información. ZFS tampoco puede repararlo, porque no hay una segunda copia en el pool desde la que pueda hacerlo.
Con un mirror, la misma lectura se sirve desde el lado correcto, el bloque dañado se vuelve a escribir y el evento aparece en la columna CKSUM de zpool status. Esto es autorreparación y requiere dos dispositivos.
sudo zpool create -o ashift=12 tank mirror /dev/disk/by-id/DISK1 /dev/disk/by-id/DISK2En un VPS, el almacenamiento del host ya suele tener redundancia, a menudo RAID 10 bajo el hipervisor. Esto protege frente al fallo de una unidad. No indica cuándo un bloque se devuelve incorrectamente, porque el array no puede saber qué copia es correcta. ZFS sí lo sabe, porque compara los datos con una suma de comprobación que él mismo escribió.
Si tiene un solo disco virtual y quiere cierta capacidad de reparación, sudo zfs set copies=2 tank/important almacena dos copias de cada bloque de ese dataset en el mismo disco. Esto duplica el espacio que usa el dataset, permite sobrevivir a un bloque dañado y no sirve de nada si desaparece todo el volumen.
Un scrub lee todo el pool y lo verifica.
sudo zpool scrub tank
zpool status tankUn pool en buen estado termina con una línea como scan: scrub repaired 0B in 00:04:11 with 0 errors. Prográmelo con una periodicidad fija; una vez al mes es suficiente para un pool pequeño.
systemctl list-unit-files 'zfs-scrub*'
sudo systemctl enable --now zfs-scrub-monthly@tank.timerLos datasets son la unidad de aplicación de políticas
Un dataset es un sistema de archivos dentro del pool, y crearlo tiene un coste bajo, así que cree uno por trabajo. Las propiedades se heredan desde el pool, por lo que puede establecer un valor predeterminado una sola vez y sobrescribirlo donde sea necesario.
sudo zfs create tank/data
sudo zfs create tank/pg
sudo zfs set compression=lz4 tank
sudo zfs set atime=off tank
sudo zfs set quota=20G tank/data
sudo zfs set recordsize=16K tank/pg
zfs get -r compression,compressratio,quota tankLa compresión es la propiedad que muchos omiten por precaución, pero ese enfoque es incorrecto. lz4 consume una pequeña cantidad de CPU y reduce los bytes que deben llegar al disco, por lo que normalmente acelera las lecturas y escrituras cuando los datos se pueden comprimir. zstd comprime más a cambio de un mayor consumo de CPU, por lo que resulta adecuada para registros y archivos que rara vez se vuelven a leer. Compruebe el resultado real con zfs get compressratio tank y recuerde que la proporción sólo incluye los datos escritos después de establecer la propiedad.
recordsize es el bloque más grande que escribe un dataset, y su valor predeterminado es 128K. Una base de datos que escribe páginas de 8 KiB en registros de 128 KiB convierte una escritura pequeña en una lectura del registro completo, un cambio y una nueva escritura. Establezca recordsize=16K en el dataset de la base de datos antes de cargar los datos, porque la propiedad sólo se aplica a los bloques escritos posteriormente.
quota permite evitar que un dataset llene el pool. Un pool de ZFS casi lleno al 100% se vuelve lento y difícil de limpiar, así que reserve espacio libre de forma intencionada.
Las instantáneas no ocupan espacio hasta que cambian los datos
ZFS nunca sobrescribe un bloque activo. Escribe un bloque nuevo y actualiza los punteros. Eso es lo que significa copy-on-write. Una instantánea indica que se deben conservar los bloques a los que apuntaba este dataset en ese momento. Por eso crearla es instantáneo y no consume espacio.
sudo zfs snapshot tank/data@2026-08-11
zfs list -t snapshot -o name,used,refer -r tank/dataLa columna USED de una instantánea muestra el espacio ocupado únicamente por esa instantánea. Al principio es casi cero y aumenta cuando cambia o elimina datos, porque los bloques antiguos ya no se pueden liberar.
Para recuperar un archivo no hace falta ejecutar ningún proceso de restauración.
ls /tank/data/.zfs/snapshot/
cp /tank/data/.zfs/snapshot/2026-08-11/notes.txt /tank/data/notes.txtEl directorio .zfs permanece oculto incluso para ls -a hasta que ejecute sudo zfs set snapdir=visible tank/data. Cree la instantánea antes de necesitarla, porque sin ella un rm -rf accidental le obliga a seguir la ruta de recuperación de ext4, que empieza por desmontar el disco y después sólo puede complicarse.
La reversión descarta todo lo que se haya escrito desde la instantánea.
sudo zfs rollback tank/data@2026-08-11La operación se rechaza si existen instantáneas más recientes. -r destruye esas instantáneas para poder continuar. Compruebe dos veces el nombre del dataset antes de pulsar Enter.
Una instantánea no es una copia de seguridad. Se encuentra en el mismo pool, en el mismo volumen y en el mismo servidor. Un fallo del volumen o un zpool destroy se lleva las instantáneas junto con los datos. Las instantáneas protegen frente a sus propios rm y frente a una actualización defectuosa. Eso cubre muchos incidentes reales, pero no protegen frente a nada que afecte al propio pool. El análisis completo está aquí: por qué una instantánea de VPS no es una copia de seguridad.
Enviar y recibir: replicación con un solo comando
zfs send convierte una snapshot en un flujo de bytes por la salida estándar, y zfs receive convierte ese flujo de nuevo en un dataset. La primera copia es un envío completo.
sudo zfs snapshot tank/data@daily-2026-08-11
sudo zfs send tank/data@daily-2026-08-11 | ssh backup.example.com "sudo zfs recv -F backup/data"Después, envíe sólo lo que cambió entre dos snapshots.
sudo zfs snapshot tank/data@daily-2026-08-12
sudo zfs send -i tank/data@daily-2026-08-11 tank/data@daily-2026-08-12 | ssh backup.example.com "sudo zfs recv backup/data"El lado receptor también debe conservar la snapshot desde la que realiza el envío. Si no la conserva, la recepción se detiene con cannot receive incremental stream: most recent snapshot of backup/data does not match incremental source, porque ZFS no tiene una base sobre la que aplicar la diferencia. Envíe desde una snapshot que exista en ambos lados o vuelva a empezar con un envío completo.
Conceda permisos en el destino en lugar de usar root remoto: sudo zfs allow -u backupuser create,mount,receive backup/data.
Esto es una copia de seguridad externa real, con una condición. El extremo remoto debe ser un pool de ZFS, porque el almacenamiento de objetos no puede recibir un flujo. Si el destino es un almacenamiento compatible con S3 o un host Linux normal, use una herramienta que se comunique con él; las copias de seguridad de restic desde un VPS cubren ese caso.
¿Por qué ZFS usa tanta RAM? El ARC
El ARC (caché de reemplazo adaptable) es la caché de lectura de ZFS. Se encuentra en la memoria del kernel y no en la caché de páginas normal de Linux, por lo que free -h no lo muestra en buff/cache. Aparece como memoria en uso. Un equipo con ZFS que parece casi lleno suele tener la caché cargada, y eso explica la mayoría de los informes de que «ZFS se ha comido la RAM».
El límite predeterminado es amplio de forma intencionada. OpenZFS 2.3 establece el tamaño máximo del ARC en el mayor valor entre la RAM menos 1 GiB y 5/8 de la RAM. OpenZFS 2.2 y versiones anteriores usaban la mitad de la RAM en Linux, mientras que FreeBSD ya usaba la regla nueva. Ejecute zfs version para saber cuál se aplica en su sistema.
The data behind this chart
[
{
"label": "2 GB VPS",
"openzfs_2_2_linux_gib": 1,
"openzfs_2_3_gib": 1.25
},
{
"label": "4 GB VPS",
"openzfs_2_2_linux_gib": 2,
"openzfs_2_3_gib": 3
},
{
"label": "8 GB VPS",
"openzfs_2_2_linux_gib": 4,
"openzfs_2_3_gib": 7
},
{
"label": "16 GB VPS",
"openzfs_2_2_linux_gib": 8,
"openzfs_2_3_gib": 15
}
]Esas cifras corresponden a la regla predeterminada documentada aplicada a tamaños de instancia habituales, no a mediciones de un equipo en ejecución. En una instancia de 4 GB, la regla de 2.3 permite un ARC de 3 GiB. El mismo equipo con 2.2 se detiene en 2 GiB. Una instancia de 2 GB con la regla de 2.3 todavía permite 1.25 GiB. La aplicación obtiene la memoria restante.
Consulte las cifras reales en su propio servidor en lugar de confiar en la tabla:
grep -E '^(size|c_max) ' /proc/spl/kstat/zfs/arcstats
arc_summary | head -n 20La tercera columna está expresada en bytes. c_max es el límite vigente en este momento y size es la cantidad que contiene actualmente el ARC.
El ARC sí devuelve memoria. El kernel indica que existe presión de memoria y el ARC se reduce. El problema es el momento en que ocurre, porque la reducción depende de esa presión. Por tanto, un proceso que solicita varios cientos de MiB de una vez puede encontrarse con el OOM (sin memoria) killer mientras el ARC todavía está liberando memoria. En un equipo de 2 GB que ejecuta una base de datos y un servidor web, no es un caso raro. El manual de OpenZFS indica lo mismo sobre los cambios manuales: reducir el límite «no hará que el ARC se reduzca si no existe presión de memoria que provoque esa reducción».
Cómo limitar la ARC en un VPS pequeño
Determine primero la memoria que necesita la carga de trabajo. Sume las necesidades de la base de datos y de la aplicación, reserve un margen para el sistema operativo y asigne el resto a la ARC. En una instancia de 4 GB que ejecute Postgres y una aplicación web, una ARC de 512 MiB a 1 GiB es un punto de partida razonable.
Aplíquelo en caliente, en bytes. Este valor es 1 GiB.
echo 1073741824 | sudo tee /sys/module/zfs/parameters/zfs_arc_maxHaga que el cambio persista después de un reinicio.
echo 'options zfs zfs_arc_max=1073741824' | sudo tee /etc/modprobe.d/zfs.conf
sudo update-initramfs -uEl paso de initramfs es importante porque el módulo puede cargarse desde initramfs antes de montar el sistema de archivos raíz. En ese caso, nunca leería el archivo que acaba de crear. Después del reinicio, confirme el valor con la línea c_max de arcstats.
El propio manual indica dos advertencias. No puede volver a establecer el valor en 0 mientras el sistema está en ejecución. Para deshacer el cambio, debe editar el archivo y reiniciar. Además, reducir el valor no disminuye de inmediato el tamaño de una ARC grande.
En FreeBSD, el mismo límite se configura mediante un sysctl bajo vfs.zfs.arc. Ejecute sysctl vfs.zfs.arc para ver los valores actuales y el nombre exacto que usa su versión. Después, escriba el valor máximo en /boot/loader.conf.
Hay otras dos reglas de memoria para un servidor pequeño. Mantenga la deduplicación desactivada, porque la tabla de deduplicación reside en la memoria y la regla general publicada habitualmente es de 1 a 3 GB de RAM por TB de datos únicos. Además, no coloque el espacio de intercambio en un zvol, que es un dispositivo de bloques creado a partir del pool, porque intercambiar mediante el sistema de archivos que intenta liberar memoria puede bloquear el equipo. Mantenga el espacio de intercambio en una partición independiente o en un archivo de intercambio fuera del pool.
Cuándo ext4 o XFS junto con restic son una opción mejor
ZFS resulta útil en un servidor con memoria disponible y un segundo volumen. Fuera de ese caso, un sistema de archivos estándar junto con una herramienta de copias de seguridad adecuada suele ser mejor. Elija ext4 o XFS cuando:
- La instancia tiene 2 GB o 4 GB de RAM y la carga de trabajo necesita toda esa memoria.
- Sólo hay un disco virtual y no existe una segunda copia, por lo que ZFS permite detectar problemas, pero no repararlos.
- El destino de las copias de seguridad es un almacenamiento de objetos o un host Linux estándar, de modo que ningún sistema puede recibir un flujo
zfs send. - Usa Debian con DKMS y no puede permitirse una actualización del kernel que deje el módulo sin compilar.
- Necesita ZFS en el sistema de archivos raíz y las imágenes del proveedor sólo ofrecen ext4.
Mantenga ZFS cuando tenga un volumen de datos independiente, memoria suficiente (8 GB o más resulta cómodo) y un plan que use instantáneas y zfs send, en lugar de limitarse a activarlos. En los demás casos, ext4 con restic, que escribe copias de seguridad cifradas y deduplicadas en un almacenamiento que el servidor no controla, cubre casi las mismas necesidades sin consumir memoria.
Modos de fallo y mensajes que verá
El pool desaparece después de reiniciar. zpool status muestra no pools available. El servicio de importación lee /etc/zfs/zpool.cache, por lo que un pool que no figure en ese archivo nunca se importa durante el arranque. sudo zpool import muestra los pools que se pueden importar, sudo zpool import tank lo vuelve a importar y sudo zpool set cachefile=/etc/zfs/zpool.cache tank hace que el cambio sea permanente. Un pool que no se exportó correctamente desde otro sistema muestra cannot import 'tank': pool may be in use from other system. sudo zpool import -f tank fuerza la importación cuando haya confirmado que ningún otro host lo tiene importado.
modprobe: FATAL: Module zfs not found in directory /lib/modules/6.12.0-... en Debian después de actualizar el kernel. DKMS no se compiló para el kernel nuevo, normalmente porque no están instalados los headers correspondientes. dkms status muestra qué módulos se compilaron para cada kernel. sudo apt install -y linux-headers-$(uname -r) y después sudo dkms autoinstall lo vuelven a compilar, y sudo zpool import tank vuelve a importar el pool.
El pool está lleno, pero eliminó los archivos. Los datos eliminados permanecen en el disco mientras un snapshot siga haciendo referencia a ellos, por lo que du y df muestran valores distintos. zfs list -o space -r tank divide el uso entre USEDDS y USEDSNAP. Un USEDSNAP elevado confirma la causa. Destruya los snapshots antiguos con sudo zfs destroy tank/data@2026-06-01 y se liberará el espacio.
Los valores de CKSUM aumentan en zpool status. Algo situado por debajo de ZFS devolvió datos incorrectos. En un mirror, el contador es una advertencia y el bloque se reparó. En un pool de un solo disco, el archivo se pierde. zpool status -v indica cuál es, y debe restaurar ese archivo desde una copia de seguridad que no esté en este pool.
El servidor está lento y usa swap. Limite el ARC como se indicó antes. Después, ejecute arc_summary y revise la tasa de aciertos. Si el ARC es demasiado pequeño para contener el conjunto de trabajo, todas las lecturas van al disco. En ese punto, un sistema de archivos convencional que use la caché de páginas ofrecería un mejor rendimiento.
FAQ
¿Cuánta RAM necesita ZFS en un VPS?
ZFS funciona en una instancia de 2 GB. La pregunta real es cuánta memoria queda para la aplicación. Sin ajustes, OpenZFS 2.3 permite que ARC crezca hasta el mayor valor entre la RAM menos 1 GiB y 5/8 de la RAM, por lo que un equipo con 4 GB puede asignar 3 GiB a la caché. Establezca zfs_arc_max en un valor que su carga de trabajo pueda reservar y confírmelo leyendo la línea c_max de /proc/spl/kstat/zfs/arcstats.
¿Una instantánea de ZFS es una copia de seguridad?
No. Una instantánea reside en el mismo pool que los datos. Sobrevive a un rm defectuoso y a una actualización fallida, pero se pierde si se pierde el pool o la instancia. Conviértala en una copia de seguridad enviándola a otra máquina con zfs send o ejecutando una herramienta de copia de seguridad que escriba en un almacenamiento que este servidor no controle.
¿ZFS funciona igual en FreeBSD y Linux?
Usan la misma base de código desde OpenZFS 2.0, publicado en diciembre de 2020. También usan los mismos comandos y el mismo formato en disco, y los pools se pueden mover entre ambos sistemas. La diferencia está en el empaquetado. FreeBSD incluye ZFS en el sistema base. En Linux, cada distribución decide cómo integrarlo: Ubuntu compila el módulo en sus paquetes del kernel, mientras que Debian lo compila en su máquina mediante DKMS. Por ello, una actualización del kernel puede dejarle sin módulo hasta que la compilación termine correctamente.
¿Puede ZFS reparar la corrupción en un VPS con un solo disco?
Detecta la corrupción e identifica el archivo, pero no puede repararla porque la reparación necesita una segunda copia del bloque. zfs set copies=2 en un dataset proporciona esa segunda copia a cambio del doble de espacio. Esto permite corregir un bloque defectuoso, pero no un volumen perdido. Un mirror entre dos volúmenes es la opción que realmente permite recuperar los datos.
¿La compresión ralentiza el servidor?
lz4 normalmente lo hace más rápido. Los bloques comprimidos implican menos bytes escritos y menos bytes leídos, y el coste de CPU por bloque es reducido frente al trabajo de disco que evita. Establezca compression=lz4 en la raíz del pool para que todos los datasets lo hereden y compruebe zfs get compressratio tank cuando ya se hayan escrito datos reales.