Almacenamiento local en Linux: ZFS y LVM¶
El problema¶
Instalas Proxmox, aceptas el asistente y de pronto tienes un local-lvm que no recuerdas haber creado. O marcas «ZFS (RAID1)» y el instalador te pregunta por un ashift que nunca has necesitado. Las guías de Proxmox, de Proxmox Backup Server y de la estrategia 3-2-1 dan ZFS y LVM por sabidos: hablan de snapshots, de datasets, de thin pools. Si no los conoces, la primera vez que un pool aparece DEGRADED o un thin pool se llena estás improvisando sobre los datos de todas tus máquinas.
Esta página explica los dos sistemas desde el ángulo del disco local de un servidor o nodo de homelab: qué es cada pieza, qué comandos usas a diario, cuándo conviene uno u otro y qué mirar para enterarte de los problemas antes de que lo sean.
Qué cubre y qué no
Almacenamiento local en un único host. El almacenamiento distribuido está en Ceph y el consumo desde Kubernetes en CSI en Kubernetes. El cifrado se menciona, pero el detalle de LUKS vive en Criptografía aplicada.
📋 Tabla de Contenidos¶
- LVM: PV, VG y LV
- Ampliar en caliente
- Thin provisioning
- Snapshots LVM y sus límites
- ZFS: pools y vdevs
- Datasets y propiedades
- Snapshots y replicación con send/receive
- Scrub, ARC y zvols
- Cuándo elegir cada uno
- Cifrado
- Monitorización mínima
- Troubleshooting
- Buenas prácticas
- Referencias
LVM: PV, VG y LV¶
LVM (Logical Volume Manager) añade una capa entre los discos y el sistema de ficheros. Tiene tres niveles y conviene no confundirlos:
| Nivel | Qué es | Comando de listado |
|---|---|---|
| PV (Physical Volume) | Un disco o partición entregado a LVM | pvs |
| VG (Volume Group) | Bolsa de espacio formada por uno o varios PV | vgs |
| LV (Logical Volume) | «Partición» recortada del VG, donde pones el sistema de ficheros | lvs |
La idea clave: el LV no está atado a un disco concreto. Puedes crecerlo con espacio de otro disco, moverlo y hacer snapshots sin tocar el sistema de ficheros.
# Entregar dos discos a LVM y crear un grupo
pvcreate /dev/sdb /dev/sdc
vgcreate vg_datos /dev/sdb /dev/sdc
# Crear un volumen de 100 GiB con un sistema de ficheros
lvcreate -L 100G -n lv_backups vg_datos
mkfs.ext4 /dev/vg_datos/lv_backups
mount /dev/vg_datos/lv_backups /srv/backups
LVM no es redundancia
Un VG con dos discos y LVs lineales suma capacidad, no protege: si falla un disco, pierdes los LV con extensiones en él. La redundancia va debajo (mdadm, RAID hardware) o en las opciones RAID de LVM. Y LVM no calcula checksums: no detecta corrupción silenciosa.
Ampliar en caliente¶
Es el motivo por el que casi todo el mundo usa LVM. Con el LV montado y en uso:
# Si el VG se queda sin espacio libre, añadir un disco
pvcreate /dev/sdd
vgextend vg_datos /dev/sdd
# Crecer el LV y su sistema de ficheros en un solo paso
lvextend -r -L +50G /dev/vg_datos/lv_backups
# O ocupar todo el espacio libre: lvextend -r -l +100%FREE ...
La opción -r (--resizefs) llama a la herramienta adecuada del sistema de ficheros (ext4, XFS…). Sin ella, el LV crece pero el sistema de ficheros sigue con el tamaño antiguo y df no cambia.
Reducir es otra historia: ext4 solo se encoge desmontado, XFS no se puede encoger y un lvreduce sin reducir antes el sistema de ficheros destruye datos.
Thin provisioning¶
Un LV normal reserva todo su espacio al crearlo. Con thin provisioning creas un thin pool y los LV finos consumen del pool solo lo que escriben, así que puedes prometer más espacio del que existe (sobreasignación).
# Un pool de 500 GiB y dos volúmenes finos de 300 GiB cada uno
lvcreate -L 500G --thinpool tpool vg_datos
lvcreate -V 300G --thin -n vm1 vg_datos/tpool
lvcreate -V 300G --thin -n vm2 vg_datos/tpool
Hay 600 GiB prometidos sobre 500 reales. Mientras lo escrito quepa, todo va bien; cuando no, las escrituras fallan.
Un thin pool lleno es una avería, no un aviso
Al llenarse, las máquinas y sistemas de ficheros sobre el pool empiezan a dar errores de E/S y, en el peor caso, se corrompen. Un thin pool tiene además un LV de metadatos que también se puede llenar. Hay que vigilar los dos porcentajes.
# Uso de datos y de metadatos del pool
lvs -o lv_name,lv_size,data_percent,metadata_percent vg_datos
Dos medidas que lo hacen manejable:
- Auto-extensión: en
/etc/lvm/lvm.conf, secciónactivation, los parámetrosthin_pool_autoextend_thresholdythin_pool_autoextend_percenthacen que el pool crezca solo cuando se acerca al umbral, siempre que el VG tenga espacio libre y el monitor de eventos (dmeventd) esté activo. - Devolver espacio: borrar ficheros dentro del LV fino no libera bloques del pool a menos que se emitan descartes. Ejecuta
fstrim -aperiódicamente o monta condiscard.
LVM-thin como backend de Proxmox¶
El instalador de Proxmox con ext4 crea un VG pve con un LV raíz y un thin pool data, expuesto como el almacenamiento local-lvm. Cada disco de VM es un LV fino y los snapshots de Proxmox son snapshots finos. Una entrada típica en /etc/pve/storage.cfg (hereda todos los riesgos anteriores; el panel muestra el uso del pool, pero conviene una alerta propia sobre data_percent):
lvmthin: local-lvm
thinpool data
vgname pve
content rootdir,images
Snapshots LVM y sus límites¶
Un snapshot congela el estado de un LV en un instante. Hay dos tipos y se comportan muy distinto:
| Snapshot clásico (thick) | Snapshot de LV fino (thin) | |
|---|---|---|
| Tamaño | Fijo, lo eliges al crearlo | Sin tamaño propio, consume del pool |
| Si se llena | Se invalida y se pierde | Compite con el resto por el pool |
| Rendimiento del origen | Cae: cada escritura copia el bloque antiguo | Casi sin penalización |
# Snapshot clásico: hay que reservar espacio para los cambios
lvcreate -s -n snap_pre_upgrade -L 10G /dev/vg_datos/lv_backups
# Snapshot de LV fino: sin tamaño
lvcreate -s -n snap_vm1 vg_datos/vm1
# Volver atrás: fusionar el snapshot en el origen
lvconvert --merge vg_datos/snap_pre_upgrade
Límites que conviene tener presentes:
- Un snapshot no es una copia de seguridad: vive en el mismo VG y en los mismos discos. Si el disco muere, se va con el original.
- Los snapshots clásicos largos degradan el rendimiento; úsalos para una operación concreta y bórralos.
- Los snapshots de LV fino se crean con la marca de «saltar en la activación»: para activarlos a mano,
lvchange -ay -K.
ZFS: pools y vdevs¶
ZFS combina gestor de volúmenes y sistema de ficheros en uno. Su rasgo definitorio es que verifica con checksums todo lo que lee, y si tiene redundancia, corrige lo corrupto con la copia buena. LVM más ext4 o XFS no hacen eso.
La jerarquía es distinta: un pool (zpool) se compone de uno o más vdevs, y cada vdev se compone de discos.
| Tipo de vdev | Discos mínimos | Tolera | Cuándo |
|---|---|---|---|
| mirror | 2 | Todos menos uno | VMs, bases de datos, nodos pequeños |
| raidz1 | 3 | 1 disco | Datos fríos con discos pequeños |
| raidz2 | 4 | 2 discos | Almacén grande de ficheros |
| raidz3 | 5 | 3 discos | Vdevs muy anchos |
La redundancia es por vdev, y el pool reparte entre sus vdevs. Perder un vdev entero pierde el pool entero, así que mezclar un vdev sin redundancia con uno en espejo anula la protección del segundo.
# Dos discos en espejo; usa siempre rutas estables by-id
zpool create -o ashift=12 tank mirror \
/dev/disk/by-id/ata-DISK_A /dev/disk/by-id/ata-DISK_B
# Seis discos en raidz2: mismo comando con "raidz2" y seis rutas
ashift es el tamaño de sector que ZFS asume, como potencia de 2 (12 = 4 KiB). No se puede cambiar después de crear el vdev. Muchos discos modernos se anuncian con sectores de 512 B aunque usen 4 KiB; un ashift demasiado bajo causa escrituras desalineadas y pérdida permanente de rendimiento. Con 12 aciertas en casi todos los discos actuales.
Ampliar un pool¶
A diferencia de un RAID clásico, un vdev raidz no se amplía añadiéndole un disco. Las formas habituales de crecer son:
- Añadir otro vdev con
zpool add(por ejemplo, otro espejo), mejor del mismo tipo que los existentes. - Sustituir los discos por otros mayores uno a uno con
zpool replace; el espacio extra aparece cuando se han cambiado todos los del vdev (conautoexpand=onen el pool, ozpool online -e). - Espejos:
zpool attachañade un disco a un espejo yzpool detachlo quita.
La expansión de raidz depende de la versión
Las versiones recientes de OpenZFS (la serie 2.3 en adelante, según el proyecto) incorporan expansión de raidz, que permite añadir un disco a un vdev raidz existente con zpool attach. Comprueba con zfs version qué tienes antes de contar con ello: Proxmox y las distribuciones suelen ir por detrás del proyecto. Además, los datos escritos antes de expandir conservan la proporción antigua de paridad hasta que se reescriben.
Datasets y propiedades¶
Dentro de un pool creas datasets: parecen directorios, pero cada uno tiene sus propias propiedades, cuotas y snapshots. A diferencia de LVM, no reservas tamaño por adelantado: comparten el espacio libre del pool.
zfs create tank/vms
zfs create tank/backups
zfs set quota=500G tank/backups
zfs get compression,recordsize,atime tank/backups
zfs set compression=lz4 tank
zfs set atime=off tank
zfs set recordsize=16K tank/postgres
Las propiedades que más importan en un servidor:
| Propiedad | Valor habitual | Para qué |
|---|---|---|
compression |
lz4 (o zstd) |
Comprime en línea. Con lz4 casi siempre mejora el rendimiento al escribir menos |
recordsize |
128K por defecto; 1M para ficheros grandes; 16K para bases de datos |
Tamaño de bloque máximo de un fichero |
atime |
off |
Evita una escritura por cada lectura |
quota / reservation |
según caso | Tope o espacio garantizado para un dataset |
Las propiedades se heredan del padre. recordsize solo afecta a los datos escritos a partir del cambio. zstd como valor de compression exige una versión de OpenZFS que lo incluya (la serie 2.x).
Snapshots y replicación con send/receive¶
Los snapshots de ZFS son instantáneos y, mientras no cambien los datos, no ocupan nada. Están en el mismo pool, así que valen lo mismo que un snapshot LVM: no son copia de seguridad hasta que salen de ese disco.
zfs snapshot tank/vms@2026-10-11
zfs list -t snapshot tank/vms
zfs rollback tank/vms@2026-10-11 # vuelve a ese momento
zfs destroy tank/vms@2026-10-11
Lo que los convierte en réplica es zfs send/zfs receive: serializa un snapshot y lo reconstruye en otro pool, local o remoto.
# Primera réplica completa
zfs send tank/vms@snap1 | ssh nas zfs receive reserva/vms
# Réplicas siguientes: solo lo que cambió entre dos snapshots
zfs send -i tank/vms@snap1 tank/vms@snap2 | ssh nas zfs receive reserva/vms
El envío incremental solo funciona si el destino conserva el snapshot base. Es la pieza que usa el 3-2-1 para tener una copia fuera del equipo. Para medir cómo se comporta el pool bajo carga, usa fio.
Scrub, ARC y zvols¶
Scrub. Recorre todos los datos del pool, verifica los checksums y repara lo que pueda con la redundancia. Es la forma de detectar la degradación antes de necesitar el dato.
zpool scrub tank
zpool status tank # progreso y resultado
Programa un scrub periódico y revisa el resultado. Carga los discos: no lo lances en horas punta.
ARC. Es la caché de lectura de ZFS en RAM y la razón por la que «ZFS se come la memoria». Su tamaño máximo por defecto ha cambiado entre versiones de OpenZFS, y algunos instaladores, como el de Proxmox, ya fijan un límite propio: comprueba el valor efectivo con arc_summary en vez de suponerlo. Libera memoria cuando el sistema la necesita, pero verás poca memoria «libre» en free. Si el nodo ejecuta VMs, limítala para dejarles sitio:
# Límite de 4 GiB (valor en bytes) de forma persistente
echo "options zfs zfs_arc_max=4294967296" > /etc/modprobe.d/zfs.conf
update-initramfs -u -k all # solo si la raíz está en ZFS; reiniciar después
# En caliente: echo 4294967296 > /sys/module/zfs/parameters/zfs_arc_max
No hay una cifra universal: ajústala mirando los aciertos de caché (arc_summary) y la memoria que necesitan tus VM. Con la deduplicación activada el consumo de RAM se dispara: déjala apagada salvo motivo claro.
Zvols. Un zvol es un dataset que se comporta como un dispositivo de bloque (/dev/zvol/...). Es lo que Proxmox usa para los discos de las VM sobre ZFS: cada disco es un zvol, con snapshots y clones propios.
zfs create -V 32G tank/vm-100-disk-0 # aparece en /dev/zvol/tank/
El tamaño de bloque (volblocksize) se fija al crear el zvol y su valor por defecto cambia entre versiones. Sobre raidz, los zvols pueden ocupar más de lo esperado por el relleno de paridad; para VMs se recomiendan espejos.
Cuándo elegir cada uno¶
| Criterio | LVM (+ ext4/XFS) | LVM-thin | ZFS | mdadm + LVM |
|---|---|---|---|---|
| Integridad de datos | Sin checksums | Sin checksums | Checksums y autocuración | Sin checksums |
| RAM | Mínima | Mínima | Alta (ARC, ajustable) | Mínima |
| Snapshots | Clásicos, con coste | Rápidos, baratos | Instantáneos, sin límite práctico | Los de LVM |
| Ampliación | Muy flexible, en caliente | Muy flexible | Añadir vdevs; raidz limitado | Flexible; crecer el array es más lento |
| Rendimiento | Alto, predecible | Alto; riesgo de fragmentación | Muy bueno con RAM y ajuste | Alto, predecible |
| Complejidad | Baja | Media (vigilar el pool) | Media-alta (modelo propio) | Media (dos capas) |
Un criterio práctico:
- ZFS cuando el dato importa más que el último MiB/s: almacén de ficheros, copias, nodo Proxmox con dos discos en espejo. La integridad y
send/receivejustifican la RAM. - LVM-thin en un nodo con poca RAM, un solo disco o una controladora RAID hardware, donde quieres snapshots de VM baratos. Acepta el riesgo y alerta sobre el pool.
- mdadm + LVM es la tercera vía: mdadm da el RAID por software y LVM la flexibilidad encima. Es la combinación clásica y sobria, sin checksums. Creas el array con
mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sdb /dev/sdc, lo entregas conpvcreate /dev/md0y sigues como en la sección de LVM. - Evita ZFS sobre un RAID hardware que oculte los discos: necesita verlos (HBA en modo paso directo) para detectar y reparar errores.
Cifrado¶
Ambos admiten cifrado, por caminos distintos:
- LUKS bajo LVM: cifras el disco o la partición con
cryptsetup, y sobre el dispositivo descifrado montas el PV. Todo lo que hay encima (VG, LV, snapshots) queda cifrado de una vez. - Cifrado nativo de ZFS: se activa por dataset al crearlo (
zfs create -o encryption=on -o keyformat=passphrase tank/privado). Permite cifrar unos datasets y otros no, y replicar snapshots sin que salgan descifrados, siempre que se envíen en crudo conzfs send -w: unzfs sendnormal transmite los datos ya descifrados.
La gestión de claves, las cabeceras de LUKS y la recuperación están en Criptografía aplicada; no se repiten aquí.
Monitorización mínima¶
No hace falta Prometheus para empezar; estos comandos, a mano o en un cron, cubren casi todos los sustos:
# ZFS
zpool status -x # "all pools are healthy" o el detalle del problema
zpool list # capacidad, ocupación y salud de cada pool
zfs list # espacio por dataset
# LVM
pvs ; vgs ; lvs # discos, grupos y volúmenes
lvs -a -o+data_percent,metadata_percent # incluye pools y metadatos
smartctl -H /dev/sda # SMART: veredicto global
smartctl -a /dev/sda # SMART: atributos completos
Qué vigilar: un pool distinto de ONLINE, errores de lectura/escritura/checksum en zpool status, un pool por encima de un 80 % de ocupación (el rendimiento de ZFS cae al llenarse), data_percent o metadata_percent de un thin pool cerca del 100 %, y sectores reasignados o pendientes en aumento en SMART. Para NVMe, smartctl -a /dev/nvme0 da desgaste y temperatura. El demonio smartd de smartmontools puede avisar por correo.
Troubleshooting¶
| Síntoma | Causa | Arreglo |
|---|---|---|
zpool status marca DEGRADED |
Un disco ha fallado o se ha desconectado | Identificar el disco en zpool status, cambiarlo y zpool replace tank viejo nuevo |
| Las VM dan errores de E/S de golpe | Thin pool lleno (datos o metadatos) | Ampliar el pool (lvextend sobre el thin pool), liberar con fstrim, borrar snapshots |
lvextend dice que no hay extensiones libres |
El VG está lleno | vgextend con otro PV, o reducir lo que sobre |
El LV crece pero df no cambia |
Se omitió -r |
lvextend -r o, a mano, resize2fs (ext4) / xfs_growfs (XFS) |
| Un snapshot LVM clásico desaparece o queda inválido | Se llenó su espacio reservado | Reservar más, o usar snapshots de LV fino; borrarlo tras la operación |
| «Se come la RAM» tras instalar ZFS | El ARC crece mientras haya memoria | Fijar zfs_arc_max y comprobar con free y los contadores de ARC |
| El pool va lento al acercarse al 90 % | Fragmentación y poco espacio libre | Liberar espacio, ampliar con otro vdev, mantener margen |
zpool import rechaza un pool de otra instalación |
El pool no se exportó y consta como en uso | Verificar que no está en uso y zpool import -f nombre; antes, zpool export |
Buenas prácticas¶
- Usa
/dev/disk/by-id/al crear pools y VG. Los nombres/dev/sdXcambian entre arranques. - Redundancia debajo de todo. LVM sin RAID suma capacidad pero no protege; y en ninguno de los dos casos hay copia de seguridad hasta tener otra copia fuera del host (3-2-1, PBS).
- Alerta sobre ocupación de pools y thin pools antes del 80 %, no después del 100 %.
ashift=12ycompression=lz4desde el primer día:ashiftno se corrige después y la compresión solo afecta a lo escrito a partir de ahí.- Scrub mensual y SMART periódico con aviso por correo. Limita el ARC en nodos con VM. Prueba la restauración, no solo la copia.