ZFS en FreeBSD y Linux: coste de RAM en VPS
ZFS ofrece checksums, snapshots, replicación y compresión, pero ARC consume RAM. Aprende a valorar el coste real en un VPS de 2 o 4 GB.
Qué le 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, snapshots 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: ARC (adaptive replacement cache) usa 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 para 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 formas 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 tanto, 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 eso, el código de ZFS no se integra en el kernel principal de Linux y cada distribución decide cómo distribuirlo. FreeBSD no tiene este conflicto, por lo que ZFS está incluido directamente. Esa es toda la diferencia práctica: cambia el empaquetado, pero no es necesario adoptar una postura al respecto.
SSD Nodes no ofrece imágenes de FreeBSD. Por tanto, en un servidor alquilado aquí se aplica la parte de esta guía correspondiente a Linux. Si ejecuta FreeBSD en otro proveedor, un servidor FreeBSD obtiene ZFS sin compilar ningún módulo ni 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 cargó. El paquete se encuentra en el componente universe, que las imágenes de servidor de Ubuntu habilitan de forma predeterminada; si apt no puede encontrarlo, ejecute primero sudo add-apt-repository universe.
En Debian, los paquetes se encuentran 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, después:
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-..., lo que tarda unos minutos. Tenga en cuenta lo que implica: cada actualización del kernel lo vuelve a compilar, y si la compilación falla, el pool no se podrá importar hasta que solucione el problema.
En FreeBSD no hay que instalar nada. Habilite el servicio e inícielo.
sysrc zfs_enable=YES
service zfs startAhora, el pool. Compruebe primero las rutas estables de los dispositivos, porque /dev/vdb asigna los dispositivos en el orden de detección y ese orden 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 el dispositivo incluido en tank. ashift=12 fija en 4 KiB el tamaño de bloque mínimo del pool. Este valor coincide con el de 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 es un pool de datos en un segundo volumen, no el sistema de archivos raíz. Compruebe que el dispositivo sea el que espera antes de usarlo, porque confirmar el disco NVMe que le vendieron lleva un minuto y reconstruirlo lleva toda una tarde.
Los checksums sólo reparan cuando el pool tiene redundancia
Cada bloque que escribe ZFS incluye un checksum, y cada lectura lo verifica. La detección siempre funciona. La reparación necesita una segunda copia.
En un pool de un solo disco, ZFS le muestra el problema y no puede hacer más. zpool status -v lo informa 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 nada, así que esto ya aporta información útil. ZFS todavía no puede corregirlo porque no hay una segunda copia en el pool desde la que pueda recuperarlo.
Con un mirror, la misma lectura se sirve desde la copia correcta, 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 normalmente ya tiene redundancia, a menudo RAID 10 bajo el hipervisor. Eso protege frente al fallo de un disco. No indica que un bloque se haya leído incorrectamente, porque el array no puede saber qué copia es la correcta. ZFS sí lo sabe porque compara los datos con un checksum 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. Duplica el espacio que usa ese 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 las políticas
Un dataset es un sistema de archivos dentro del pool y crearlo apenas tiene coste, así que cree uno por tarea. Las propiedades se heredan desde el pool, por lo que puede establecer un valor predeterminado una sola vez y sobrescribirlo donde sea necesario. En FreeBSD, esta es la forma habitual de ejecutar jails: un dataset por jail permite crear snapshots y revertir cada jail de forma independiente. Esto forma parte de lo que diferencia un jail de un contenedor Docker.
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 muchas personas 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 usar más 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 relación sólo cuenta los datos escritos después de establecer la propiedad.
recordsize es el bloque más grande que escribe un dataset, 128K de forma predeterminada. 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 impide que un dataset llene el pool. Un pool de ZFS casi lleno al 100% se vuelve lento y difícil de limpiar, por lo que conviene dejar espacio libre de forma intencionada.
Las instantáneas no ocupan espacio hasta que cambian los datos
ZFS nunca sobrescribe un bloque en uso. 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 el 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 que sólo mantiene esa instantánea. Al principio es casi cero y aumenta cuando cambia o se elimina información, porque los bloques antiguos ya no se pueden liberar.
Recuperar un archivo no requiere ningún paso 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 se ejecuta sudo zfs set snapdir=visible tank/data. Cree la instantánea antes de necesitarla. Sin una instantánea, un rm -rf accidental le lleva a la ruta de recuperación de ext4, que empieza por desmontar el disco y empeora a partir de ahí.
La reversión descarta todo lo 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 elimina esas instantáneas para poder continuar. Compruebe dos veces el nombre del dataset antes de pulsar Intro.
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 elimina 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 caso completo se explica 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 instantánea en un flujo de bytes en 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 los cambios entre dos instantáneas.
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 receptor también debe conservar la instantánea 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. Realice el envío desde una instantánea que exista en ambos extremos o empiece de nuevo 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 proporciona 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 convencional, 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? La ARC
La ARC (caché de reemplazo adaptativo) es la caché de lectura de ZFS. Reside en la memoria del kernel y no en la caché de páginas normal de Linux, por lo que free -h no la muestra dentro de buff/cache. Aparece como memoria en uso. Un sistema ZFS que parece estar casi lleno normalmente tiene la caché caliente, y eso explica la mayoría de los informes de que «ZFS se ha comido la RAM».
El límite predeterminado es deliberadamente amplio. OpenZFS 2.3 establece el tamaño máximo de la ARC en el mayor valor entre la RAM menos 1 GiB y 5/8 de la RAM. OpenZFS 2.2 y 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 a 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 son la regla predeterminada documentada aplicada a tamaños habituales de instancias, no mediciones de un sistema en ejecución. En una instancia de 4 GB, la regla de 2.3 permite una ARC de 3 GiB. El mismo sistema 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. Su aplicación recibe la memoria restante.
Consulte las cifras reales de 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 muestra bytes. c_max es el límite máximo vigente y size es la cantidad que contiene actualmente la ARC.
La ARC sí devuelve memoria. El kernel señala la presión de memoria y la ARC se reduce. El problema es el momento, porque la reducción se activa por esa presión. Por tanto, un proceso que solicita varios cientos de MiB de una vez puede encontrarse con el OOM (out of memory) killer mientras la ARC todavía está liberando memoria. En un sistema de 2 GB que ejecuta una base de datos y un servidor web, no es un caso excepcional. El manual de OpenZFS indica lo mismo sobre los cambios manuales: bajar el límite «no hará que la ARC se reduzca si no existe presión de memoria que provoque esa reducción».
Cómo limitar el ARC en un VPS pequeño
Determine primero cuánta memoria necesita la carga de trabajo. Sume lo que necesitan la base de datos y la aplicación, reserve un margen para el sistema operativo y asigne el resto al ARC. En una instancia de 4 GB que ejecuta Postgres y una aplicación web, entre 512 MiB y 1 GiB de ARC 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 tras 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 escribir. Después de reiniciar, confirme el valor con la línea c_max de arcstats.
El propio manual establece dos salvedades. No puede volver a establecer el valor en 0 mientras el sistema está en ejecución. Para deshacer este cambio, debe editar el archivo y reiniciar. Además, reducir el valor no disminuye de inmediato el tamaño de un 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.
Tenga en cuenta otras dos reglas de memoria en 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 cada TB de datos únicos. Tampoco coloque swap en un zvol (un dispositivo de bloques creado a partir del pool), porque el intercambio a través del sistema de archivos que intenta liberar memoria puede bloquear el equipo. Mantenga swap en una partición normal o en un archivo de swap situado fuera del pool.
Cuándo ext4 o XFS con restic son una mejor opción
ZFS resulta útil en un servidor con memoria disponible y un segundo volumen. Fuera de ese caso, un sistema de archivos convencional 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 corregirlos.
- El destino de las copias de seguridad es un almacenamiento de objetos o un host Linux convencional, 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 resultan cómodos) 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 prácticamente las mismas necesidades sin consumir memoria.
Modos de fallo, con las cadenas que verá
El pool ha desaparecido 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 lo que se puede importar, sudo zpool import tank lo vuelve a importar y sudo zpool set cachefile=/etc/zfs/zpool.cache tank hace que la configuración persista. Un pool que no se exportó correctamente desde otro sistema muestra cannot import 'tank': pool may be in use from other system, y 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 nuevo kernel, normalmente porque no están instalados los headers correspondientes. dkms status muestra qué se ha compilado 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 recupera el pool.
El pool está lleno, pero ha eliminado los archivos. Los datos eliminados permanecen en el disco mientras una snapshot siga haciendo referencia a ellos, por lo que du y df muestran valores distintos. zfs list -o space -r tank separa el uso en USEDDS y USEDSNAP, y un USEDSNAP elevado confirma la causa. Destruya las snapshots antiguas con sudo zfs destroy tank/data@2026-06-01 para recuperar el espacio.
Los valores de CKSUM aumentan en zpool status. Algo situado por debajo de ZFS devolvió datos incorrectos. En un mirror, el valor es una advertencia y el bloque se reparó. En un pool de un solo disco, el archivo se ha perdido; zpool status -v indica cuál es, y debe restaurar ese archivo desde una copia de seguridad que no esté almacenada en este pool.
El servidor está lento y usa swap. Limite el ARC como se indicó antes, ejecute arc_summary y revise la tasa de aciertos. Un ARC demasiado pequeño para contener el conjunto de trabajo hace que todas las lecturas vayan 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 cuestión real es cuánta memoria queda disponible para la aplicación. Sin ajustes, OpenZFS 2.3 permite que la ARC crezca hasta el mayor valor entre la RAM menos 1 GiB y 5/8 de la RAM, por lo que un sistema 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 confirme el resultado 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 se almacena 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 ejecute 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, 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 la máquina con DKMS. Por eso, una actualización del kernel puede dejar el sistema sin el 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 con el doble de espacio. Esto permite gestionar un bloque defectuoso, pero no un volumen perdido. Un mirror entre dos volúmenes es la solución que realmente permite reparar 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 tiempo de disco que se ahorra. Establezca compression=lz4 en la raíz del pool para que todos los datasets hereden el ajuste y compruebe zfs get compressratio tank cuando ya se hayan escrito datos reales.