La mayoría de los “misterios” de rendimiento de Proxmox+ZFS no son misterios. Son valores predeterminados. Valores elegidos para ser seguros, genéricos y ampliamente compatibles—y luego desplegados silenciosamente en tu realidad de almacenamiento muy específica: SSDs de consumo con protección contra pérdida de energía inestable, pools RAIDZ haciendo I/O aleatorio, invitados emitiendo escrituras sync, y un hipervisor que adora cachear encima de otro cache.
Si tus VMs se sienten rápidas hasta que dejan de serlo—hasta que un checkpoint de base de datos, una actualización de Windows o una ventana de backup golpea y todo se vuelve lento—esto es para ti. Cambiaremos los valores predeterminados que realmente importan, explicaremos por qué, y te mostraremos cómo comprobar los resultados con comandos que no mienten.
La mentalidad: deja de aceptar almacenamiento que “funciona en mi laboratorio”
ZFS tiene opiniones fuertes. Proxmox tiene opiniones fuertes. Tu carga de trabajo también es opinada—especialmente si incluye bases de datos, servidores de correo, runners de CI, o cualquier cosa con muchas escrituras sync pequeñas. Cuando esas tres opiniones no coinciden, obtienes picos de latencia que parecen “lentitud aleatoria”, y pierdes días culpando a la capa equivocada.
La trampa central es asumir que la virtualización “alisa las cosas”. Hace lo contrario. La virtualización toma muchos patrones de I/O—secuenciales, aleatorios, en ráfagas, pesados en sync, pesados en metadatos—y los multiplexa en un pool compartido. Ese pool luego tiene que cumplir promesas: promesas de durabilidad (semántica sync), promesas de asignación (copy-on-write), promesas de caché (ARC/L2ARC) y promesas de equidad (scheduler). Los valores predeterminados son un punto de partida, no una estrategia.
Este es el marco que uso en producción:
- Sabe qué escrituras deben ser seguras. Si el invitado pidió sync, asume que importa a menos que estés deliberadamente intercambiando durabilidad por velocidad.
- Hace coincidir los tamaños de bloque con la realidad. ZFS no puede leer lo que no escribió. Si eliges un volblocksize para un zvol que pelea con tu carga, pagarás por ello indefinidamente.
- Minimiza el “trabajo doble”. Cachés dobles, checksums dobles, capas dobles de CoW: cada una es defendible por separado; combinadas, son un impuesto.
- Mide en la capa correcta. iostat dentro del invitado puede verse bien mientras el host arde. Al revés, ZFS puede parecer bien mientras el invitado hace bucles patológicos de fsync.
Hechos interesantes y contexto histórico (breve y útil)
- ZFS popularizó la suma de verificación de extremo a extremo en despliegues mainstream, convirtiendo la corrupción silenciosa de “mítica” en “medible”. Cambió cómo los equipos de operaciones confían en el almacenamiento.
- Copy-on-write (CoW) es por qué los snapshots son baratos, y también por qué las escrituras aleatorias pueden ser caras—especialmente en RAIDZ bajo virtualización.
- La compresión en ZFS suele ser una característica de rendimiento, no solo de espacio, porque mover menos bytes puede vencer el coste de CPU (particularmente con lz4).
- “Las escrituras sync son lentas” solía ser un problema de bases de datos; ZFS lo convirtió en una cuestión de diseño del sistema al honrar las semánticas sync muy estrictamente.
- Los dispositivos SLOG se convirtieron en una industria secundaria porque la gente aprendió a la mala que “un SSD” no es lo mismo que “un dispositivo de log seguro y de baja latencia”.
- Proxmox migró a muchos usuarios de LVM-thin a ZFS porque los snapshots y la replicación son adictivos operativamente—hasta que descubres qué hacen los valores predeterminados a la latencia.
- La industria pasó años redescubriendo la amplificación de escritura: pequeñas escrituras aleatorias en sistemas de archivos CoW pueden explotar en trabajo físico mucho mayor, especialmente con RAID de paridad.
- Errores de ashift son para siempre (prácticamente hablando): si construyes un pool con la suposición de tamaño de sector equivocada, el rendimiento puede quedar permanentemente limitado.
Los valores predeterminados de Proxmox+ZFS que merecen escepticismo inmediato
1) Comportamiento sync: ya no puedes ignorarlo
Los valores predeterminados de Proxmox no te salvarán de la latencia de escrituras sync. Tus invitados pueden emitir escrituras sync (fsync, O_DSYNC, barriers/flushes), y ZFS tratará esas escrituras como “deben ser estables ante pérdida de energía”. Si no tienes SLOG y tu pool es HDDs o SSDs saturados, las cargas pesadas en sync se sentirán como una casa encantada.
Pero lo peor es la ambigüedad: algunas cargas son pesadas en sync solo durante fases específicas—commits de base de datos, vaciados de journal, backups de VM que disparan comportamiento del sistema de archivos. Así obtienes miseria intermitente y una falsa sensación de “está mayormente bien”.
Punto de decisión: si te importa la durabilidad, mantén sync=standard y construye el pool para manejarlo. Si no te importa (laboratorio, CI efímero), puedes elegir sync=disabled deliberadamente—nunca accidentalmente.
2) volblocksize: la configuración que decide silenciosamente tu economía de I/O
Los ZVOLs tienen volblocksize. Los datasets tienen recordsize. La gente los confunde, luego se pregunta por qué su tuning no movió la aguja.
volblocksize se establece al crear el zvol y es efectivamente permanente (puedes cambiarlo, pero los bloques existentes no se reescriben; normalmente migras para beneficiarte plenamente). Proxmox a menudo crea zvols con un valor predeterminado que puede no coincidir con tu carga.
Guía típica (no es dogma):
- 16K: a menudo bueno para discos de VM generales, cargas mixtas y bases de datos que realizan muchas I/O aleatorias pequeñas.
- 8K: puede ayudar para patrones particularmente pesados en sync o logs, pero puede aumentar la sobrecarga de metadatos.
- 64K/128K: puede ser excelente para cargas secuenciales grandes (media, backups), a menudo equivocado para discos de SO.
En RAIDZ, bloques más pequeños pueden ser especialmente punitivos debido a la paridad y al comportamiento read-modify-write. Aquí nacen los rumores de “ZFS es lento”.
3) Compresión: estás dejando rendimiento sobre la mesa
Si no estás usando compression=lz4 en almacenamiento de VM, básicamente eliges mover más bytes de los necesarios. Para muchas cargas de VM (archivos de SO, logs, texto, repositorios de paquetes), la compresión reduce I/O físico y mejora la latencia bajo presión.
La compresión puede salir mal en hosts ya limitados por CPU o en cargas incomprimibles (medios precomprimidos, volúmenes encriptados). Pero para la mayoría de los hipervisores Proxmox, lz4 es el valor predeterminado que deberías querer.
4) atime: muerte por mil lecturas
atime=on significa que las lecturas se convierten en escrituras porque se actualizan tiempos de acceso. En almacenamiento de VM, eso suele ser desgaste inútil. Si te importa la resistencia del SSD y la latencia, pon atime=off en datasets de VM.
5) Caché primaria: el doble caché no es una característica
ZFS ARC cachea agresivamente. Los invitados también cachéan. Si dejas que ZFS cachee datos de VM que el invitado volverá a cachear, quemas memoria en ambos lados y obtienes menos caché eficiente en general.
Enfoque común: para discos de VM basados en zvol, considera primarycache=metadata (cachea metadatos, no datos) para reducir el doble caché. Esto es situacional: si tus invitados son pequeños y tu host tiene mucha RAM, cachear datos aún puede ayudar. Pero debes tomar esa decisión intencionalmente.
6) Provisionamiento fino (thin): el “espacio libre” es un constructo social
Los zvols thin se sienten eficientes hasta que el pool llega a un precipicio. Una vez que un pool ZFS queda demasiado lleno, el rendimiento puede colapsar debido a presión de asignación y fragmentación. “Pero todavía tenemos 15% libre!” es cómo la gente habla justo antes de un mal día.
Regla operativa: mantiene espacio libre significativo. Para muchos pools con muchas VMs, trata el 20–30% libre como normal. Si eso te parece derroche, estás a punto de aprender cómo se siente la adquisición urgente de almacenamiento.
Broma #1: RAIDZ con un pool casi lleno es como una reunión que “debería haber sido un correo”. Sigue y sigue, se vuelve más lenta y nadie puede irse.
ZVOL vs archivos en dataset (raw/qcow2): elige lo menos peor para tu uso
ZVOLs (dispositivos de bloque): camino simple, semántica fuerte
Los ZVOLs son dispositivos de bloque respaldados por ZFS. A Proxmox le gustan porque los snapshots y la replicación se integran limpiamente, y evitas cierta rareza de sistema de archivos sobre sistema de archivos.
Compensaciones:
- volblocksize importa mucho, y no obtienes do-overs infinitos.
- El comportamiento de Discard/TRIM puede ser complicado dependiendo de versiones y configuraciones. Necesitas verificar que la recuperación de espacio realmente funcione.
- Las semánticas de caché (primarycache) se vuelven importantes para evitar pelear con el invitado.
Archivos en dataset (raw/qcow2): flexibilidad con una capa extra
Almacenar discos de VM como archivos en un dataset ZFS puede estar perfectamente bien. El riesgo principal es apilar capas CoW (qcow2 es CoW; ZFS es CoW). Eso puede amplificar la fragmentación y la sobrecarga de metadatos, especialmente bajo presión de escrituras aleatorias.
Orientación con opinión:
- Prefiere raw sobre qcow2 en ZFS a menos que necesites específicamente una característica de qcow2.
- Usa qcow2 con precaución para casos de nicho (esparcido + snapshots internos), pero entiende que pagas por esa flexibilidad.
Cómo decidir rápidamente
- Si ejecutas bases de datos o servicios sensibles a la latencia: zvols con volblocksize sensato, y planifica para escrituras sync.
- Si ejecutas datos mayormente secuenciales y masivos: los archivos en datasets pueden estar bien, ajusta recordsize y mantenlo simple.
- Si ejecutas muchas VMs pequeñas y valoras la sencillez operativa: zvols suelen ser más fáciles de razonar en las herramientas de Proxmox.
Los cambios que hago el primer día (y por qué)
Cambio 1: Habilitar compresión lz4 en almacenamiento de VM
Hazlo a menos que tengas evidencia en contra. lz4 es de baja latencia, y los discos de VM suelen ser comprimibles. La ganancia suele ser más visible bajo carga cuando el pool está ocupado.
Cambio 2: Desactivar atime para datasets de VM
Este es un ajuste clásico “pequeño” que evita desgaste inútil. El almacenamiento de VM no necesita escrituras por tiempos de acceso.
Cambio 3: Decide tu política sync explícitamente
La mayoría de la gente ejecuta accidentalmente sync=standard en hardware que no puede sostenerlo, luego lo “arregla” desactivando sync globalmente, y después olvida que lo hizo. No seas esa persona.
Elige uno:
- Ruta duradera:
sync=standard, añade un SLOG proper si es necesario, y verifica la latencia. - Ruta velocidad a cualquier costo:
sync=disableden datasets/zvols específicos donde la pérdida de datos sea aceptable.
Cambio 4: Configurar primarycache con criterio para almacenamiento con muchos zvols
Si el host está limitado de memoria, ARC compitiendo con los invitados es una pelea mortal. Para muchos discos de VM respaldados por zvol, primarycache=metadata es un predeterminado sensato. Si tienes mucha RAM y invitados mayormente intensivos en lectura, cachear datos puede ayudar. Mide, no vibes.
Cambio 5: Deja de sobrellenar pools
Escríbelo: un pool ZFS al 85–90% de uso no está “bien”. Es un incidente de latencia programado.
Cambio 6: Usa las opciones de disco de virtualización correctas (y verifica)
Configuraciones de disco de Proxmox como cache, discard, iothread y el modelo de controlador importan. Pero “importan” significa “aparecen en las mediciones”, no “suena bien en un foro”. Tu línea base debe ser latencia estable y modos de fallo previsibles.
Broma #2: Activar todos los controles de rendimiento a la vez es como beber cinco energizantes para “dormir mejor”. Aprenderás algo, pero no será lo que querías.
Tareas prácticas: comandos, salidas y la decisión que tomas
Estas son comprobaciones reales que ejecuto en un host Proxmox cuando el almacenamiento de VM es lento, inconsistente o sospechosamente “bien hasta que no lo está”. Cada tarea incluye un comando, salida de ejemplo, qué significa la salida y la decisión siguiente.
Tarea 1: Identificar pools, salud y señales obvias
cr0x@server:~$ zpool status
pool: rpool
state: ONLINE
status: Some supported features are not enabled on the pool.
action: Upgrade the pool to enable all features.
scan: scrub repaired 0B in 00:12:44 with 0 errors on Sun Dec 22 03:12:26 2025
config:
NAME STATE READ WRITE CKSUM
rpool ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_A ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_B ONLINE 0 0 0
errors: No known data errors
Qué significa: Pool en línea, sin errores, scrub limpio. La advertencia de características no es un problema de rendimiento por sí misma.
Decisión: Si ves vdevs degradados, errores de checksum o resilvers constantes, deja de tunear y arregla hardware primero. Afinar rendimiento en un pool que falla es cómo obtienes informes creativos de caída del servicio.
Tarea 2: Comprobar el llenado del pool (el asesino silencioso de rendimiento)
cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint -r rpool
NAME USED AVAIL REFER MOUNTPOINT
rpool 720G 180G 104K /rpool
rpool/data 680G 180G 104K /rpool/data
rpool/data/vmdata 640G 180G 96K /rpool/data/vmdata
Qué significa: ~80% usado. Estás entrando en la zona donde la fragmentación y la sobrecarga de asignación empiezan a mostrarse.
Decisión: Si estás por encima de ~80–85% en un pool con muchas VMs, planifica trabajo de capacidad ahora: añade vdevs, migra VMs frías o separa cargas. No “optimices” saliendo de la física.
Tarea 3: Inspeccionar propiedades críticas del dataset (compresión, atime, sync)
cr0x@server:~$ zfs get -o name,property,value -s local,default compression,atime,sync,primarycache rpool/data/vmdata
NAME PROPERTY VALUE
rpool/data/vmdata compression off
rpool/data/vmdata atime on
rpool/data/vmdata sync standard
rpool/data/vmdata primarycache all
Qué significa: Compresión off y atime on: estás pagando I/O extra. Sync standard: las semánticas duraderas están en juego. primarycache all: ARC puede estar cacheando doblemente datos de invitados.
Decisión: Habilita compression=lz4 y atime=off en datasets de VM salvo que haya una razón en contra. Evalúa primarycache según la presión de RAM y el cacheo del invitado.
Tarea 4: Aplicar cambios de dataset seguros y reversibles (lz4 + atime off)
cr0x@server:~$ sudo zfs set compression=lz4 atime=off rpool/data/vmdata
cr0x@server:~$ zfs get -o name,property,value compression,atime rpool/data/vmdata
NAME PROPERTY VALUE
rpool/data/vmdata compression lz4
rpool/data/vmdata atime off
Qué significa: Las escrituras futuras se comprimirán; las actualizaciones de tiempo de acceso dejan de generar ruido.
Decisión: Típicamente esto es una ganancia neta. Si la CPU se convierte en cuello de botella (raro con lz4), lo verás en métricas de CPU del host bajo carga de I/O.
Tarea 5: Listar zvols y comprobar volblocksize
cr0x@server:~$ zfs list -t volume -o name,volblocksize,used,refer,logicalused -r rpool/data/vmdata
NAME VOLBLOCKSIZE USED REFER LOGICALUSED
rpool/data/vmdata/vm-101-disk-0 128K 64G 64G 120G
rpool/data/vmdata/vm-102-disk-0 8K 20G 20G 22G
Qué significa: Tienes volblocksize inconsistentes. Un disco de SO de 128K a menudo rinde mal en I/O aleatorio. LOGICALUSED > REFER indica compresión/snapshots o efectos de thin provisioning.
Decisión: Para discos de VM de propósito general, estandariza (a menudo 16K) salvo que tengas una razón medida en contra. Para discos existentes, planifica una migración para beneficiarte plenamente.
Tarea 6: Comprobar si estás abusando de semánticas sync (picos de latencia)
cr0x@server:~$ sudo zpool iostat -v rpool 1 5
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
rpool 720G 180G 150 980 12.4M 5.1M
mirror-0 720G 180G 150 980 12.4M 5.1M
ata-SAMSUNG_SSD_1TB_A - - 75 490 6.2M 2.6M
ata-SAMSUNG_SSD_1TB_B - - 75 490 6.2M 2.6M
Qué significa: Ancho de banda moderado pero operaciones de escritura altas: carga típica de escrituras pequeñas. Si la latencia es mala durante esto, las escrituras sync pueden estar forzando esperas.
Decisión: A continuación, inspecciona latencia de ZFS y comportamiento sync (tareas abajo). Si este es un host de bases de datos, asume que sync importa hasta demostrar lo contrario.
Tarea 7: Comprobar latencia de ZFS directamente
cr0x@server:~$ sudo zpool iostat -rlv rpool 1 3
read write
pool r/s w/s rMB/s wMB/s rlat wlat cholat dlat
---------- ---- ---- ----- ----- ---- ---- ------ ----
rpool 120 950 10.1 4.9 2ms 38ms 42ms 1ms
Qué significa: Latencia de escritura ~38ms, mayor cuando está ocupado. Eso es territorio de “las VMs se sienten lentas”, especialmente para metadatos y journaling.
Decisión: Si wlat salta regularmente a decenas/centenas de ms, necesitas abordar la ruta sync, la saturación del pool o el comportamiento del dispositivo (firmware/PLP). Afinar invitados no arreglará la latencia del host.
Tarea 8: Ver si tienes un log separado (SLOG)
cr0x@server:~$ zpool status -v rpool
pool: rpool
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
rpool ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_A ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_B ONLINE 0 0 0
errors: No known data errors
Qué significa: No hay sección logs. Las escrituras sync están aterrizando en los vdevs principales.
Decisión: Si tienes cargas pesadas en sync y dolor de latencia, evalúa un SLOG proper (espejado, protegido contra pérdida de energía). Si no tienes PLP, solo estás comprando nuevas formas de perder datos rápidamente.
Tarea 9: Comprobar presión de ARC y realidad de memoria
cr0x@server:~$ grep -E 'MemTotal|MemFree|MemAvailable' /proc/meminfo
MemTotal: 131900192 kB
MemFree: 4021184 kB
MemAvailable: 18944128 kB
cr0x@server:~$ cat /proc/spl/kstat/zfs/arcstats | egrep '^(size|c |c_min|c_max|hits|misses) '
size 4 82463313920
c 4 85899345920
c_min 4 4294967296
c_max 4 85899345920
hits 4 2840093011
misses 4 390129220
Qué significa: ARC es ~82G, puede crecer hasta ~85G. MemAvailable ~18G sugiere que el host no está famélico, pero los invitados podrían estarlo.
Decisión: Si el host está intercambiando o MemAvailable es consistentemente pequeño, reduce ARC (o añade RAM). Si los invitados están con poca memoria, considera primarycache=metadata para discos zvol de VM para que el host deje de “ayudar” tanto.
Tarea 10: Verificar que discard/TRIM esté habilitado de extremo a extremo
cr0x@server:~$ lsblk -D
NAME DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO
sda 0 512B 2G 0
sdb 0 512B 2G 0
cr0x@server:~$ sudo zpool get autotrim rpool
NAME PROPERTY VALUE SOURCE
rpool autotrim off default
Qué significa: Los discos soportan discard, pero autotrim del pool está off.
Decisión: Considera habilitar autotrim en pools SSD donde la recuperación de espacio importe y tu carga no se vea afectada por actividad adicional de trim. Luego verifica que discard de invitados esté habilitado en Proxmox para los discos de VM.
Tarea 11: Habilitar autotrim (si procede) y observar
cr0x@server:~$ sudo zpool set autotrim=on rpool
cr0x@server:~$ sudo zpool get autotrim rpool
NAME PROPERTY VALUE SOURCE
rpool autotrim on local
Qué significa: El pool pasará trims hacia abajo. Esto puede ayudar al rendimiento a largo plazo del SSD y al comportamiento del espacio.
Decisión: Si habilitar trim se correlaciona con picos de latencia en algunos SSDs, puedes deshabilitarlo y en su lugar correr trims programados en ventanas tranquilas.
Tarea 12: Comprobar fragmentación (especialmente en pools de VM de larga vida)
cr0x@server:~$ zpool list -o name,size,alloc,free,frag,cap,dedupratio
NAME SIZE ALLOC FREE FRAG CAP DEDUP
rpool 900G 720G 180G 42% 80% 1.00x
Qué significa: 42% de fragmentación no es catastrófico, pero puede contribuir a latencia de I/O aleatorio en pools ocupados, especialmente combinado con alta ocupación.
Decisión: Si frag es alto y el pool también está lleno, detente. Planifica una migración o expansión. El “tuning” de fragmentación es mayormente gestión de capacidad disfrazada.
Tarea 13: Comprobar si dedup está habilitado accidentalmente
cr0x@server:~$ zfs get -o name,property,value dedup -r rpool/data/vmdata
NAME PROPERTY VALUE
rpool/data/vmdata dedup off
Qué significa: Dedup está off. Bien.
Decisión: Si dedup está on para almacenamiento de VM y no lo diseñaste así, apágalo para nuevas escrituras y planifica remediación. Dedup sin dimensionamiento y pruebas convierte RAM en cuello de botella de rendimiento.
Tarea 14: Observar latencia por vdev con iostat
cr0x@server:~$ iostat -x 1 3
Linux 6.8.12-pve (server) 12/25/2025 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
8.12 0.00 2.91 11.44 0.00 77.53
Device r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 85.0 490.0 6200.0 2600.0 27.4 3.10 38.2 3.1 44.1 0.8 46.2
sdb 85.0 490.0 6200.0 2600.0 27.4 3.06 37.9 3.0 43.7 0.8 46.0
Qué significa: iowait del host no es trivial (11%). Las escrituras tienen await ~44ms: esto coincide con wlat de ZFS. Los dispositivos no están al 100% de utilización, pero la latencia sigue siendo alta—común cuando el dispositivo realiza garbage collection interna o maneja flushes.
Decisión: Si await es alto mientras %util no está al máximo, sospecha comportamiento de flush, firmware o presión de sync más que saturación pura de throughput.
Tarea 15: Comprobar la configuración de disco VM en Proxmox por modos de cache riesgosos
cr0x@server:~$ qm config 101 | egrep 'scsi|virtio|ide|sata|boot'
boot: order=scsi0;net0
scsi0: rpool/data/vmdata/vm-101-disk-0,discard=on,iothread=1,cache=writeback,ssd=1
Qué significa: cache=writeback puede ser rápido, pero cambia las semánticas de fallo. Con writeback, el host puede reconocer escrituras antes de que sean seguras en disco.
Decisión: Para bases de datos y cualquier cosa que importe la corrección, prefiere modos de cache más seguros (y confía en ZFS + hardware adecuado). Si eliges writeback conscientemente, documéntalo como si fuera un arma cargada.
Tarea 16: Confirmar ashift del pool (porque no se puede arreglar después)
cr0x@server:~$ sudo zdb -C rpool | egrep 'ashift|vdev_tree' -n | head
54: vdev_tree:
86: ashift: 12
Qué significa: ashift=12 (sectores de 4K). Eso suele ser correcto para discos modernos.
Decisión: Si alguna vez ves ashift=9 en discos que en realidad son 4K, espera dolor de rendimiento. Arreglarlo usualmente significa reconstruir el pool. Planifica en consecuencia.
Tarea 17: Comprobar bloat de snapshots (porque el “espacio libre” puede estar atrapado)
cr0x@server:~$ zfs list -o name,used,usedbysnapshots,usedbydataset,logicalused -r rpool/data/vmdata | head
NAME USED USEDSNAP USEDDS LOGICALUSED
rpool/data/vmdata 640G 210G 96K 1.1T
Qué significa: 210G usado por snapshots. No es “malo”; es una decisión de política. Pero impacta la ocupación del pool y el rendimiento.
Decisión: Si los snapshots están comiendo espacio y te empujan hacia la zona de peligro de alta ocupación, ajusta la retención o mueve backups a otro lugar. “Guardamos todo para siempre” no es una estrategia de almacenamiento.
Tarea 18: Verificar que la compresión realmente funcione (chequeo de ratio)
cr0x@server:~$ zfs get -o name,property,value compressratio -r rpool/data/vmdata | head
NAME PROPERTY VALUE
rpool/data/vmdata compressratio 1.38x
Qué significa: 1.38x es una ganancia significativa. Estás reduciendo I/O físico para muchas cargas.
Decisión: Si compressratio está ~1.00x para datos encriptados/incomprensibles, es esperado. Aun así, la sobrecarga de lz4 suele ser lo suficientemente baja como para mantenerlo activado.
Idea parafraseada — John Allspaw: La fiabilidad viene de diseñar sistemas para fallar de manera segura, no de asumir que no fallarán.
Guion de diagnóstico rápido (primeras/segundas/terceras comprobaciones)
Este es el flujo rápido de triage cuando el ticket es “el almacenamiento de VM está lento” y tienes 15 minutos antes de la siguiente reunión que de todos modos vas a ignorar.
Primero: ¿está enferma la capa de almacenamiento del host o solo está ocupada?
- Ejecuta
zpool status: busca dispositivos degradados, errores de checksum, resilvers o scrubs corriendo durante el pico. - Ejecuta
zpool iostat -rlv 1 3: comprueba la latencia de escritura (wlat). Si wlat es alto, la capa de almacenamiento es el problema. - Ejecuta
iostat -x 1 3: confirma await de dispositivo e iowait. Await alto confirma que el dolor es real a nivel de dispositivo.
Segundo: ¿estás ahogándote en escrituras sync?
- Comprueba la propiedad
syncdel dataset/zvol (y no asumas). Sisync=standard, las escrituras sync esperarán por media estable. - Confirma si tienes un SLOG. Si no lo tienes, la latencia sync se paga en los vdevs principales.
- Busca cargas que disparen tormentas de sync: bases de datos, correo, NFS dentro de invitados, sistemas de archivos con journaling bajo estrés.
Tercero: ¿estás limitado por capacidad y fragmentación?
- Comprueba
capyfragdel pool. Alta capacidad más alta frag es un multiplicador de latencia. - Comprueba uso de snapshots. Los snapshots pueden atrapar espacio y acelerar el comportamiento de “pool demasiado lleno”.
- Comprueba sorpresas de thin provisioning: los invitados creen tener espacio, el pool no.
Si esas tres comprobaciones están limpias
Entonces miras la configuración a nivel de VM: modo de cache, bus de disco, iothread, profundidad de cola y comportamiento del sistema de archivos invitado. Pero no lo hagas primero. Así es como terminas afinando el panel mientras falta un cilindro en el motor.
Errores comunes: síntoma → causa raíz → solución
1) Síntoma: “Todo se congela 1–5 segundos aleatoriamente”
Causa raíz: Picos de latencia de escrituras sync (flushes, tormentas de fsync) en un pool sin un SLOG apropiado, a menudo combinado con SSDs de consumo que se bloquean bajo presión de flush.
Solución: Mantén sync=standard para datos importantes, añade un SLOG espejado y con capacidad PLP si es necesario, y valida con zpool iostat -rlv. Si los datos son desechables, establece sync=disabled en ese dataset/zvol específico y documenta el riesgo.
2) Síntoma: “Las VMs rinden en benchmarks, pero las apps reales son lentas”
Causa raíz: Los benchmarks atacan rutas secuenciales; las apps golpean patrones aleatorios pesados en sync y metadatos. También común: mismatch de volblocksize para zvols.
Solución: Haz coincidir volblocksize con la carga (a menudo 16K para discos de VM generales), evita qcow2 sobre ZFS cuando no lo necesitas, y mide latencia no solo throughput.
3) Síntoma: “El pool tiene espacio, pero el rendimiento es terrible”
Causa raíz: El pool está demasiado lleno (80–95%), snapshots atrapan espacio, el asignador está bajo presión; la fragmentación sube.
Solución: Reduce la retención de snapshots, migra datos, expande el pool. Trata el espacio libre como reserva de rendimiento, no como sugerencia.
4) Síntoma: “Tras habilitar autotrim, la latencia empeoró”
Causa raíz: Algunos SSDs manejan mal trims continuos; las operaciones de trim compiten con escrituras de primer plano.
Solución: Deshabilita autotrim y ejecuta trims programados en ventanas tranquilas. Considera SSDs empresariales con comportamiento de trim predecible.
5) Síntoma: “El host tiene mucha RAM, pero los invitados siguen intercambiando bajo carga”
Causa raíz: ARC crece agresivamente y roba memoria que los invitados necesitan, o estás cacheando doblemente datos de VM en host y en invitado.
Solución: Considera primarycache=metadata para zvols de VM; limita ARC si es necesario; valida con arcstats y métricas de memoria de los invitados.
6) Síntoma: “Los backups hacen que producción sea inutilizable”
Causa raíz: I/O de snapshot/backup colisiona con I/O aleatorio de producción; los backups pueden inducir amplificación de lectura y churn de metadatos adicional.
Solución: Programa backups, aplica throttling si es posible, aísla almacenamiento de backups y evita poner objetivos de backup en el mismo pool estresado.
7) Síntoma: “Agregamos una caché SSD rápida y nada mejoró”
Causa raíz: L2ARC no ayuda la latencia de escritura; ayuda el cacheo de lectura, y solo si tu working set y patrones de acceso encajan. Además, dispositivos de cache pueden robar RAM y añadir sobrecarga.
Solución: Resuelve la latencia de escritura en el vdev/capa sync. Añade L2ARC solo después de confirmar que las lecturas son el cuello de botella y que la tasa de aciertos de ARC es insuficiente.
Tres micro-historias corporativas desde las trincheras del almacenamiento
Micro-historia #1: El incidente causado por una suposición equivocada
Migraron una pequeña flota de VMs de aplicación a Proxmox con mirrors ZFS en “buenos SSDs”. Era un diseño sensato y aprobado por presupuesto: dos discos en mirror, muchos IOPS en el papel. Las apps eran mayormente servicios web sin estado con una pequeña VM de base de datos y un broker de mensajes.
La suposición equivocada fue sutil: “Si es mirror SSD, las escrituras sync son básicamente gratis.” Nadie lo dijo en voz alta, que es cómo sobreviven las suposiciones. También asumieron que las configuraciones de durabilidad de la base de datos eran conservadoras pero no agresivas. La plataforma se puso en marcha, se vio genial, y luego empezó a producir picos cortos y bruscos de latencia durante el tráfico pico.
El equipo on-call persiguió fantasmas: jitter de red, vecinos ruidosos, steal de CPU, incluso “tal vez Linux tiene una regresión del scheduler”. Mientras tanto, la VM de la base de datos estaba haciendo cosas perfectamente razonables—commits con fsync—y ZFS estaba haciendo cosas perfectamente razonables—esperar a storage estable.
Cuando trazaron la latencia de escritura del host junto con los timeouts de la aplicación, la historia se escribió sola. Los SSDs eran modelos de consumo con latencia de flush inconsistente. Cuando la base de datos golpeó una ráfaga de escrituras sync, los dispositivos se bloquearon. El mirror no los salvó; solo proporcionó dos dispositivos que podían bloquearse al unísono.
La solución no fue exótica. Desplegaron un SLOG espejado en dispositivos con protección contra pérdida de energía y dejaron de fingir que la latencia de flush no importaba. Los picos desaparecieron. El equipo también documentó qué datasets podían tolerar sync=disabled (pocos) y cuáles no (la base de datos y el broker). La lección clave fue operacional: nunca asumas que tu almacenamiento honra la durabilidad rápidamente solo porque es “SSD”.
Micro-historia #2: La optimización que salió mal
Otra organización quería “rendimiento máximo” y se puso agresiva con el tuning. Apagaron sync globalmente. Pusieron discos de VM en writeback cache. Activaron todos los toggles de rendimiento que pudieron encontrar en el invitado. También eligieron qcow2 porque hacía mover discos “más fácil”.
Por un tiempo, funcionó. Los benchmarks parecían heroicos. Las implementaciones fueron rápidas. Todos se felicitaron y volvieron a su trabajo. Entonces hubo un reboot de host—actualización rutinaria del kernel, nada dramático—y un puñado de VMs volvieron con sistemas de archivos corruptos. La base de datos se recuperó. La VM de correo no. El postmortem fue… educativo.
El retroceso no fue porque alguna configuración individual fuera “mala” en el vacío. Fue la combinación: writeback cache más sync deshabilitado más los propios patrones de escritura de qcow2 crearon un sistema que reconocía escrituras de forma optimista. El sistema fue rápido porque, en términos prácticos, mentía sobre lo que era durable.
Revirtieron a defaults más seguros, pero no a ciegas. Movieron el tuning de rendimiento a una política: para cargas desechables, la velocidad importaba más que la durabilidad; para cargas con estado, optimizaron la ruta de hardware de almacenamiento en lugar de apagar la corrección. También migraron de qcow2 a raw donde fue posible para reducir apilamiento de CoW y sobrecarga de metadatos.
El coste real no fue la corrupción en sí—fue la semana de confianza perdida. A los usuarios no les importa que puedas explicar semánticas de cache. Les importa que sus datos no regresaron.
Micro-historia #3: La práctica aburrida pero correcta que salvó el día
Una empresa mediana ejecutaba clusters Proxmox para servicios internos. Nada llamativo: controladores de dominio, Git, monitorización, algunas bases de datos pequeñas y sorprendente cantidad de sincronización de archivos. Su almacenamiento era mirrors ZFS y algo de RAIDZ para datos masivos. Tenían una práctica que parecía dolorosamente aburrida: scrubs semanales, monitorización SMART y umbrales estrictos de capacidad de pool.
También estandarizaron datasets de almacenamiento de VM con propiedades consistentes: compresión lz4 activada, atime off y decisiones explícitas sobre sync. Lo más importante, tenían una regla: ningún pool de VM por encima del 80% sin un plan de capacidad aprobado. La gente se quejaba. Finanzas se quejaba. Todos se quejan cuando les dices “no”.
Un trimestre, un lote de SSDs empezó a mostrar errores de medio aumento. Nada explotó. Ninguna luz roja. Solo una tendencia en SMART y algunas lecturas lentas que aparecieron como pequeñas subidas de latencia durante scrubs. Porque los scrubs corrían regularmente y las alertas estaban vinculadas a cambios, lo detectaron temprano.
Reemplazaron discos durante horario laboral, uno a la vez, con resilvers controlados. Ningún bridge de incidente. Ninguna caída visible para el cliente. La práctica aburrida—disciplina de scrubs y disciplina de capacidad—hizo que el pool nunca llegara a la zona de “demasiado lleno para resilver cómodamente”. No ganaron un premio. Simplemente no tuvieron una semana mala.
Listas de verificación / plan paso a paso
Lista A: Valores predeterminados de almacenamiento del día uno para un nuevo pool ZFS de Proxmox
- Crea el pool con el ashift correcto (usualmente 12). Verifícalo con
zdb -Cantes de poner datos. - Crea un dataset dedicado para almacenamiento de VM (no metas todo en datasets raíz).
- Configura
compression=lz4en el dataset de VM. - Configura
atime=offen el dataset de VM. - Decide la política sync por dataset: duradero por defecto; deshabilita solo donde puedas perder datos.
- Si usas zvols, estandariza volblocksize (a menudo 16K para discos de VM). Decide antes de crear discos.
- Decide el comportamiento de primarycache para discos de VM (considera metadata-only si hay contención de memoria).
- Establece y aplica umbrales de capacidad (alerta al 70–75%, acción al 80%).
Lista B: Cuando una VM se siente lenta (triage de 15 minutos)
- Comprueba
zpool status(¿errores? ¿resilver? ¿scrub?). Si sí, detente y estabiliza. - Comprueba
zpool iostat -rlv 1 3(¿latencia de escritura?). Si es alta, la ruta de almacenamiento es el cuello de botella. - Comprueba
iostat -x 1 3(await del dispositivo, iowait). Confirma que no es solo percepción del invitado. - Comprueba llenado y frag del pool (
zpool list,zfs listuso de snapshots). Si está muy lleno, necesitas capacidad, no vibras. - Comprueba modo de cache del disco de VM (
qm config) y propiedades del dataset (zfs get).
Lista C: Migración controlada para arreglar mal volblocksize
- Crea un nuevo zvol con el deseado
volblocksize. - Usa migración de almacenamiento de Proxmox o una copia de bloque controlada mientras la VM está apagada (preferido para corrección).
- Valida rendimiento y latencia con
zpool iostat -rlvy comprobaciones de la aplicación. - Elimina el zvol antiguo y monitoriza fragmentación y espacio.
Preguntas frecuentes
1) ¿Debo usar ZFS o LVM-thin para almacenamiento de VM en Proxmox?
Si quieres snapshots/replicación simples e integridad de extremo a extremo, ZFS es una fuerte opción. Si prefieres modelos mentales más sencillos para bloque y menos interacción CoW, LVM-thin puede ser más fácil. Para muchas organizaciones, ZFS gana operativamente—siempre que trates sync, capacidad y dimensionado de bloques como prioridades de primera clase.
2) ¿Es compression=lz4 seguro para discos de VM?
Sí. Es transparente y comúnmente desplegado. El “riesgo” es principalmente la sobrecarga de CPU, que suele ser menor comparada con I/O ahorrado. El verdadero riesgo es no usar compresión y luego preguntarte por qué el pool siempre está ocupado moviendo bytes innecesarios.
3) ¿Qué volblocksize debo usar para zvols de VM?
Los valores comunes para discos de VM generales son 16K (a menudo un buen equilibrio). Para cargas especializadas, mide: las bases de datos a veces prefieren 8K o 16K; cargas secuenciales grandes pueden preferir 64K+. La clave es consistencia e intención: elige según la carga, no por superstición.
4) ¿Puedo cambiar volblocksize después de crear el zvol?
Puedes cambiar la propiedad, pero los bloques ya escritos permanecen con el tamaño antiguo. Para beneficiarte realmente, normalmente migras datos a un nuevo zvol creado con el volblocksize correcto.
5) ¿Debo deshabilitar sync para acelerar Proxmox?
Solo si estás dispuesto a perder escrituras recientes en caso de pérdida de energía o crash—y solo para los datasets donde eso sea aceptable. Para sistemas reales con datos reales, construye una ruta de almacenamiento que pueda manejar sync=standard en lugar de apagar la corrección globalmente.
6) ¿Necesito un SLOG para ZFS en mirrors SSD?
No siempre. Si tu carga es mayormente escrituras asíncronas y lecturas, puede que estés bien. Si tienes escrituras sync significativas y te importa la latencia, un SLOG adecuado puede ayudar mucho. “Adecuado” significa baja latencia y protección contra pérdida de energía, y idealmente espejado.
7) ¿Es qcow2 una mala idea en ZFS?
A menudo, sí—porque apila CoW sobre CoW, incrementando fragmentación y sobrecarga de metadatos. Si necesitas funciones de qcow2, úsalo conscientemente. De lo contrario, raw en ZFS suele ser la opción más calmada y predecible.
8) ¿Por qué colapsa el rendimiento cuando el pool se llena?
ZFS necesita espacio libre para asignar eficientemente. A medida que el espacio libre disminuye, las asignaciones se vuelven más difíciles, la fragmentación aumenta y la amplificación de escritura crece—especialmente con I/O aleatorio de VM. Mantener 20–30% libre no es desperdicio; es comprar latencia estable.
9) ¿Debo poner primarycache=metadata para todo el almacenamiento de VM?
Es un buen predeterminado cuando los invitados son grandes y hay presión de memoria, porque reduce el doble caché. Si el host tiene RAM abundante y los invitados son pequeños/lectura-intensivos, cachear datos puede ayudar. No adivines: verifica el comportamiento de ARC y la salud de memoria de invitados.
10) ¿Autotrim siempre ayuda en pools SSD?
A menudo ayuda al comportamiento de espacio a largo plazo y puede mantener el rendimiento del SSD, pero algunos dispositivos manejan mal trims continuos. Habilítalo, observa latencia y estate dispuesto a cambiar a trims programados si hace falta.
Conclusión: próximos pasos prácticos
Si ejecutas Proxmox sobre ZFS y no has tocado los valores predeterminados de almacenamiento, probablemente estés ejecutando un sistema que funciona genial el martes y te traiciona el jueves. Arreglarlo no es magia. Es política.
- Activa compresión lz4 y atime off en datasets de almacenamiento de VM hoy mismo. Es bajo riesgo y suele dar gran recompensa.
- Audita el comportamiento sync. Decide qué debe ser durable y diseña la arquitectura para ello. No deshabilites sync por accidente en todo el sistema.
- Estandariza volblocksize para discos VM nuevos (a menudo 16K) y planifica migraciones para los peores casos.
- Deja de sobrellenar pools. La capacidad es una característica de rendimiento. Hazla un SLO monitorizado, no una sorpresa nocturna.
- Mide latencia, no solo throughput. Usa
zpool iostat -rlvyiostat -xpara mantenerte honesto.
Haz esas cinco cosas y la mayoría de las quejas “ZFS es lento” desaparecerán. Las que queden serán problemas honestos—límites de hardware, realidades de carga y la ocasional decisión que tomaste a propósito.