Compresión ZFS con zstd: elegir niveles sin quemar CPU

¿Te fue útil?

La compresión en ZFS es uno de esos controles raros que pueden hacer el almacenamiento más rápido, barato y silencioso—todo a la vez. También puede convertir un sistema perfectamente sano en un calefactor ligado a la CPU si tratas “zstd-19” como un rasgo de personalidad. El truco es elegir niveles como un SRE: basándote en mediciones, la forma de la carga y los modos de fallo, no en impresiones.

Esta es una guía de campo para ejecutar la compresión zstd en ZFS en producción: cómo se comportan los niveles, qué significa “bueno”, qué comprobar cuando duele y cómo ajustar sin convertirlo en un hobby de benchmarking. Mantendremos la practicidad: comandos que puedes ejecutar hoy, cómo interpretarlos y qué decisiones deberían cambiar.

Por qué la compresión es una característica de rendimiento

La compresión en ZFS es inline. Eso significa que en las escrituras, ZFS comprime los bloques antes de que lleguen al disco; en las lecturas, los descomprime después de salir del disco y antes de que aterricen en los buffers de tu aplicación. La gente clasifica la compresión como “ahorro de capacidad”, pero en la práctica con frecuencia es una herramienta de rendimiento.

Menos bytes movidos suele ser más rápido que menos ciclos de CPU gastados

Los sistemas de almacenamiento suelen estar limitados por una de tres cosas: latencia, ancho de banda o CPU. La compresión intercambia CPU por menos bytes en la red y menos bytes en disco. Si tu carga está limitada por I/O (común), ese intercambio es una victoria.

Aquí está el modelo mental que te mantiene honesto:

  • Si tu almacenamiento es el cuello de botella, la compresión puede aumentar el rendimiento efectivo y reducir la amplificación de lectura.
  • Si tu CPU es el cuello de botella, una compresión agresiva puede hundir el rendimiento y provocar timeouts en cascada.
  • Si tu carga es sensible a la latencia, te importan los p99 y los picos de cola, no el rendimiento medio.

La compresión también es un silencioso desfragmentador del destino: menos bloques escritos significa menos asignaciones, menos actualizaciones de metaslab y, a veces, menos presión de fragmentación con el tiempo. Eso no es magia ni garantía, pero es lo suficientemente real como para aparecer en pools de larga vida.

Un chiste antes de ponernos serios: la compresión es como hacer dieta—todo el mundo ama el “antes/después”, nadie disfruta contar las calorías de CPU.

Cómo se comporta zstd en ZFS (y qué significan realmente los niveles)

Zstandard (zstd) está diseñado para ser rápido en niveles bajos y capaz de alta compresión en niveles más altos. En ZFS, normalmente estableces la compresión a nivel de dataset usando compression=zstd o compression=zstd-N. El nivel afecta cuánto intenta ZFS encontrar patrones compresibles.

Qué comprime ZFS: bloques del tamaño de recordsize (por lo general)

ZFS comprime bloques individuales, típicamente hasta el recordsize del dataset (para filesystems) o el volblocksize (para zvols). Esta es una razón principal por la que “nivel de compresión” no es una respuesta universal: comprimir bloques de 128K para un servidor de archivos es distinto a comprimir 16K para una base de datos, y muy distinto a 8K para un zvol que alimenta un disco de VM.

Los niveles no son lineales—y “mejor ratio” puede ser peor

Los niveles de zstd aumentan el costo de CPU más rápido de lo que aumentan la ratio de compresión. La curva es empinada: los niveles bajos suelen ser “casi gratis”, mientras que los niveles altos pueden ser dramáticamente más caros por ganancias modestas. En CPUs modernas, la descompresión suele ser mucho más barata que la compresión, lo cual importa en cargas con muchas lecturas.

Además: un mejor ratio de compresión no siempre es mejor para ZFS. Cuando los bloques se hacen más pequeños reduces I/O, pero puedes aumentar el tiempo de CPU, reducir la eficiencia de prefetch o cambiar cómo se comportan ARC y L2ARC. El nivel correcto es el que hace tu carga más rápida o más barata sin mover el cuello de botella a un sitio peor.

zstd en ZFS no es “talla única”

Las cargas reales tienen personalidades:

  • Imágenes de VM: muchas lecturas/escrituras aleatorias, compresibilidad mixta; suelen beneficiarse de compresión moderada pero pueden exponer el overhead de CPU rápidamente.
  • Bases de datos: datos estructurados, archivos de log e índices varían; a veces obtienes grandes ganancias, a veces casi nada. Las colas de latencia importan.
  • Backups: típicamente secuenciales, muy compresibles (especialmente texto, JSON, CSV) y tolerantes al uso de CPU—hasta que restaurar se convierte en un evento crítico.
  • Medios: ya están comprimidos; la compresión suele desperdiciar CPU, aunque los metadatos y archivos auxiliares pueden beneficiarse.

Hechos y contexto histórico para usar en reuniones

Estos son puntos concretos que ayudan cuando alguien pregunta: “¿Por qué cambiamos la compresión otra vez?”

  1. La compresión en ZFS existe desde hace mucho—no es un añadido de moda. ZFS temprano usaba LZJB; luego lz4 se volvió el predeterminado práctico en muchas implementaciones porque era lo bastante rápido como para estar “siempre activado”.
  2. zstd fue creado por Yann Collet (el mismo ingeniero detrás de LZ4), diseñado para ofrecer un espectro: velocidad tipo lz4 en niveles bajos y ratios fuertes en niveles altos.
  3. La compresión inline cambia el layout físico: los datos se almacenan comprimidos en disco. No estás “ahorrando espacio después”; estás cambiando cuántos sectores golpean el medio ahora mismo.
  4. Las CPUs modernas pueden descomprimir increíblemente rápido en relación con discos giratorios e incluso muchos arreglos SSD; la descompresión a menudo no es el limitador—la compresión sí lo es.
  5. ZFS informa compresión por bloque y por dataset, pero compressratio no es un benchmark; incluye peculiaridades como metadatos, padding y cómo se reescribieron los bloques con el tiempo.
  6. La compresión interactúa con recordsize: bloques más grandes pueden comprimir mejor, pero son más caros de reescribir y pueden aumentar la amplificación de escritura para escrituras pequeñas y aleatorias.
  7. Dedup no es compresión y históricamente ha causado más incidentes que ahorros presupuestarios cuando se habilita a la ligera; la compresión es la palanca más segura.
  8. ZFS “duplica” y suma checksums a todo (copy-on-write + checksumming de extremo a extremo). La compresión debe encajar en esa canalización, por eso el overhead de CPU puede aparecer como picos de latencia bajo carga.

Elegir niveles zstd según la carga (sin encender CPUs)

La postura por defecto: empezar conservador, luego ganarse el aumento

Si quieres una línea base opinionada: usa zstd a un nivel bajo para la mayoría de los datasets y luego incrementa selectivamente donde tengas evidencia de que ayuda. En muchos entornos de producción eso significa compression=zstd (que mapea a un nivel por defecto) o un nivel explícito bajo como zstd-1 a zstd-3 para filesystems de propósito general.

¿Por qué? Porque normalmente puedes obtener una reducción significativa en bytes escritos y leídos con impacto mínimo de CPU. Esa reducción mejora la eficiencia de cache también: ARC y la caché de páginas efectivamente se vuelven más grandes cuando la misma RAM contiene más datos lógicos.

Recomendaciones dirigidas por carga (prácticas, no dogmáticas)

Filesystems de propósito general (home dirs, artefactos de build, logs)

Comienza con zstd-1 a zstd-3. Estos niveles tienden a capturar “ganancias fáciles” (texto, JSON, binarios con regiones de ceros) sin convertir la compresión en un trabajo intensivo de CPU.

Los logs son particularmente buenos: se comprimen extremadamente bien y los picos de escritura pueden ser intensos. zstd en niveles bajos suele seguir el ritmo; niveles más altos pueden volverse visibles en la latencia de escritura p99 durante tormentas de incidentes—justo cuando menos quieres latencia extra.

Almacenamiento de VM (zvols o filesystems que almacenan qcow2/raw)

Usa zstd-1 o zstd-2 primero. El I/O de VM suele ser aleatorio y sensible a la latencia. La compresión puede ayudar porque las imágenes de VM contienen muchos ceros y estructuras repetitivas de filesystem, pero el patrón de escritura puede exponer el overhead de compresión rápidamente.

Si el host hypervisor ya está cargado de CPU (overcommit, cifrado, overlays de red), mantén la compresión barata. Si el arreglo de almacenamiento es el cuello de botella y los hosts tienen CPU libre, puedes probar zstd-3 o zstd-4 con cuidado.

Bases de datos

Sé conservador y mide p99. Las cargas DB suelen ser mixtas: WAL/redo logs (a menudo compresibles), archivos de datos (quizá), e índices (depende). El costo de CPU extra en la ruta de almacenamiento puede aparecer como latencia de cola, que las bases de datos traducen en tickets de “¿por qué va lenta la app?”.

Empieza con zstd-1 o zstd-2 para datos, quizá más alto para tablespaces archivados si tu diseño de BD permite separación.

Repositorios de backups

Aquí puedes justificar niveles más altos—a veces. Si la carga de backup es secuencial y el repositorio se escribe en una ventana, zstd-3 a zstd-6 puede tener sentido si tienes CPU libre y el almacenamiento es caro o lento. Pero recuerda las restauraciones: la descompresión suele ser barata, sin embargo el proceso de restaurar puede ser intensivo en CPU por otras razones (checksums, red, cifrado).

Si tu software de backup ya comprime (o deduplica y comprime), la compresión en ZFS puede aportar poco. Mide antes de declarar victoria.

Medios ya comprimidos (JPEG, MP4, ZIP)

Usa nivel bajo o no te molestes, pero “no molestarse” no es obligatorio. ZFS intentará comprimir cada bloque y puede decidir que no vale la pena; pero el intento en sí cuesta CPU. En sistemas con CPU limitada que sirven medios, fija la compresión baja. En pools de propósito general, dejar compresión de bajo nivel activada suele estar bien porque la ruta rápida de “no comprimible” es razonablemente eficiente.

El “consumo” de CPU generalmente es por concurrencia, no por un solo hilo

En producción, la compresión rara vez te mata porque un bloque tardó demasiado. Te mata porque miles de bloques se están comprimiendo en concurrente, y de repente tus nodos de almacenamiento parecen servidores de procesamiento por lotes. ZFS usará CPU con gusto para mantener el ritmo del I/O, y si estás en el edge (común), el edge se moverá.

Segundo chiste, y esa es la cuota: el mejor nivel de compresión es el que no convierte tu appliance de almacenamiento en un benchmark distribuido de CPU.

Tres mini-historias del mundo corporativo

1) Incidente causado por una suposición equivocada: “La compresión solo afecta al uso de disco”

Una empresa donde trabajé ejecutaba un repositorio interno de artefactos en ZFS. Era el clásico “funciona hasta que no funciona”: los desarrolladores subían mucho durante el horario laboral, CI era ruidoso y el pool de almacenamiento se dimensionó por capacidad con “suficiente” CPU porque la máquina parecía sobrepotenciada en papel.

Alguien cambió el dataset principal de compression=lz4 a compression=zstd-15 luego de una revisión de capacidad. La suposición fue simple y muy humana: “la compresión es algo de almacenamiento.” El cambio salió durante un periodo tranquilo, las pruebas iniciales parecían bien y el número de compressratio mejoró lo suficiente como para que todos se sintieran listos.

Dos días después hubo una gran liberación de rama de producto. CI se convirtió en una manguera: tarballs, contenedores, logs y muchos archivos pequeños. El almacenamiento no se quedó sin espacio—se quedó sin tiempo. La latencia de escritura se disparó, los hilos de aplicación se acumularon y el servicio de artefactos empezó a devolver timeouts. Los ingenieros culparon a la red, luego al DNS (un rito de iniciación), y solo después notaron los nodos de almacenamiento con CPU alta y el tiempo de sistema subiendo.

La resolución no fue complicada: volver a un nivel zstd bajo, reiniciar los servicios afectados para limpiar el backlog e implementar un proceso de cambios para las propiedades de almacenamiento. La lección quedó porque fue cara de la manera que duele: sin pérdida de datos, solo un día de tiempo de ingeniería y mucho ruido de “¿por qué todo va lento?”.

La conclusión del postmortem que importó: la compresión es parte de la canalización de I/O. Trátala como tratarías activar cifrado o cambiar recordsize—mide, haz staging y vigila las colas de latencia.

2) Una optimización que salió mal: “Vamos a subir todo para mejores ratios”

En otro entorno, un equipo ejecutaba una plataforma VM con respaldo en ZFS. El coste de almacenamiento estaba bajo escrutinio, así que un ingeniero propuso subir los niveles de compresión en todo. La idea lucía genial en una hoja de cálculo: menos terabytes, menos discos, menos compras futuras. La plataforma tenía margen de CPU—hasta que no lo tuvo.

El traspié vino por una interacción que nadie modeló: los hosts más ocupados también ejecutaban cifrado en reposo y hacían mucho churn de snapshots. Compresión, cifrado, checksumming, metadata de snapshots—cada uno individualmente “bien”, juntos formaron una canalización que empezó a amplificar la latencia bajo carga. El primer síntoma ni siquiera fueron alarmas de almacenamiento; fue deriva del tiempo de los huéspedes VM y quejas del filesystem cuando los huéspedes experimentaban paradas largas de I/O.

Intentaron arreglarlo como suelen hacer los ingenieros bienintencionados: ajustar más controles. Aumentaron ARC, afinaron prefetch y cambiaron profundidades de cola. Ayudó un poco, pero el problema subyacente era saturación de CPU en la pila de almacenamiento durante picos de escritura. La compresión a niveles altos era el multiplicador.

La solución eventual fue casi aburrida: restablecer la mayoría de datasets a un nivel zstd bajo, mantener un nivel más alto solo para volúmenes fríos y compresibles, y añadir un dashboard que correlacionara latencia (p95/p99), CPU e IOPS con las configuraciones de compresión. Los ahorros de capacidad disminuyeron—pero la plataforma dejó de generar tickets de “la VM está poseída”.

En la retrospectiva, la mejor frase fue: “Optimizamos para un número con el que podíamos presumir, no para lo que los usuarios sienten.” Buena regla para la vida, no solo para ZFS.

3) Una práctica aburrida pero correcta que salvó el día: “Políticas por dataset + canarios”

Una organización más madura trataba las propiedades de ZFS como configuración de aplicación: versionadas, revisadas y desplegadas por etapas. No porque amaran el proceso, sino porque ya se habían quemado. Tenían una política clara: datasets generales reciben zstd bajo; datasets especiales (backups, archivos) pueden usar niveles más altos si pasan benchmarks; datasets de base de datos deben demostrar que no empeoran p99.

También usaban canarios: un nodo de almacenamiento y una pequeña porción de cargas recibirían el cambio primero. La clave no era la perfección; era la visibilidad. Observaban un puñado de señales: percentiles de latencia de escritura, utilización de CPU (user/system) y timeouts a nivel de aplicación. Si cualquiera de esas señales se movía en sentido incorrecto, el rollback era inmediato y sin controversia porque estaba previsto.

Durante una renovación de hardware, pasaron de una generación de CPU más vieja a una nueva y aprovecharon para revisar la compresión. Porque tenían métricas base, pudieron demostrar que zstd-3 era seguro para un conjunto de cargas que previamente necesitaron zstd-1. Eso compró capacidad y mejoras de rendimiento reales sin drama.

El día que “salvó el día” fue un evento de crecimiento sorpresa: un nuevo equipo comenzó a almacenar grandes volúmenes de logs semi-estructurados. En una plataforma menos disciplinada, eso habría causado una emergencia de capacidad o un incidente de rendimiento. Aquí, el dataset ya tenía el recordsize y el nivel de compresión adecuados, y la plataforma absorbió el crecimiento como si lo esperara—que, en cierto sentido, sí lo esperaba.

Tareas prácticas: comandos + interpretación (12+)

Todo lo siguiente está pensado para poder ejecutarse en un sistema Linux típico con utilidades ZFS disponibles. La salida varía por distro y versión de ZFS; los patrones de interpretación son lo importante.

Tarea 1: Ver ajustes de compresión actuales en los datasets

cr0x@server:~$ zfs get -r -o name,property,value,source compression tank
NAME                PROPERTY     VALUE     SOURCE
tank                compression  zstd      local
tank/vm             compression  zstd-2    local
tank/db             compression  zstd-1    local
tank/backups        compression  zstd-6    local
tank/media          compression  off       local

Interpretación: Esto te dice qué está establecido y de dónde viene (local vs inherited). Si ves un nivel alto inesperado heredado de un padre, así es como un “cambio pequeño” se convierte en “incidente a nivel de plataforma”.

Tarea 2: Comprobar resultados reales de compresión (no adivinar)

cr0x@server:~$ zfs get -o name,used,logicalused,compressratio -r tank
NAME         USED  LOGICALUSED  RATIO
tank         4.20T 6.10T        1.45x
tank/vm      1.80T 2.10T        1.17x
tank/db      900G  1.05T        1.19x
tank/backups 1.10T 2.70T        2.45x
tank/media   400G  410G         1.02x

Interpretación: logicalused vs used te da una comprobación de realidad. Backups se comprimen bien; media no. Si compressratio está cercano a 1.0x, un nivel alto de zstd es más cosplay de CPU que beneficio.

Tarea 3: Encontrar datasets que están desperdiciando CPU (alto nivel, bajo ratio)

cr0x@server:~$ zfs get -H -o name,value compression,compressratio -r tank | paste - - | head
tank	zstd	tank	1.45x
tank/vm	zstd-2	tank/vm	1.17x
tank/db	zstd-1	tank/db	1.19x
tank/backups	zstd-6	tank/backups	2.45x
tank/media	off	tank/media	1.02x

Interpretación: Esta vista rápida te ayuda a detectar “zstd-12 con 1.05x.” Si encuentras eso, probablemente hayas hallado CPU libre que puedes ahorrar.

Tarea 4: Cambiar la compresión de forma segura (y entender qué hace)

cr0x@server:~$ sudo zfs set compression=zstd-2 tank/db
cr0x@server:~$ zfs get compression tank/db
NAME     PROPERTY     VALUE   SOURCE
tank/db  compression  zstd-2  local

Interpretación: Esto afecta a los bloques escritos nuevos. Los datos existentes mantienen su compresión antigua hasta que se reescriben (por churn normal o una reescritura deliberada).

Tarea 5: Medir latencia y rendimiento I/O rápidamente con iostat

cr0x@server:~$ iostat -x 1 5
Linux 6.6.0 (server) 	12/24/2025 	_x86_64_	(32 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          22.10    0.00    8.50    1.20    0.00   68.20

Device            r/s     w/s   rkB/s   wkB/s  r_await  w_await aqu-sz  %util
nvme0n1         120.0   900.0  6400.0 51200.0    0.45    2.10   1.20   82.0

Interpretación: Si %util está alto y los awaits suben, estás bound por almacenamiento. Si los awaits están bien pero la app va lenta, puedes estar bound por CPU (compresión o checksumming) o bloqueado en otro lugar.

Tarea 6: Vigilar I/O y latencia a nivel de pool ZFS

cr0x@server:~$ zpool iostat -v 1 5
                              capacity     operations     bandwidth
pool                        alloc   free   read  write   read  write
--------------------------  -----  -----  -----  -----  -----  -----
tank                        4.20T  1.80T    800   1200   90M   140M
  mirror                    4.20T  1.80T    800   1200   90M   140M
    nvme0n1                    -      -    400    600   45M    70M
    nvme1n1                    -      -    400    600   45M    70M
--------------------------  -----  -----  -----  -----  -----  -----

Interpretación: El ancho de banda y las operaciones te dicen si estás empujando muchas I/O pequeñas o pocas grandes. La compresión suele importar más cuando estás bound por ancho de banda; puede perjudicar más cuando estás bound por IOPS y latencia con CPU apretada.

Tarea 7: Comprobar la presión del ARC y la salud de la memoria

cr0x@server:~$ arcstat 1 5
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  arcsz     c
12:00:01   900   120     13    40   4     60   7     20   2   48.0G  64.0G
12:00:02   880   140     15    55   6     65   7     20   2   48.1G  64.0G

Interpretación: La compresión cambia la densidad efectiva de cache. Si tu tasa de miss es alta, incluso una ratio de compresión modesta puede reducir lecturas físicas al caber más contenido lógico en ARC.

Tarea 8: Comprobar recordsize por dataset y por qué importa para compresión

cr0x@server:~$ zfs get -o name,property,value recordsize tank/vm tank/db tank/backups
NAME         PROPERTY    VALUE
tank/vm      recordsize  128K
tank/db      recordsize  16K
tank/backups recordsize  1M

Interpretación: Un recordsize mayor puede mejorar la ratio de compresión para cargas secuenciales (como backups) pero puede aumentar la amplificación de escritura para escrituras aleatorias pequeñas (como bases de datos). No “estandarices” esta propiedad a menos que disfrutes incidentes evitables.

Tarea 9: Confirmar qué está realmente comprimible (muestreo rápido)

cr0x@server:~$ zfs get -o name,compression,compressratio -r tank | egrep 'tank/(vm|db|backups|media)'
tank/vm      zstd-2  1.17x
tank/db      zstd-1  1.19x
tank/backups zstd-6  2.45x
tank/media   off     1.02x

Interpretación: Un dataset que se mantiene consistentemente cerca de 1.0x te está contando una historia: o los datos son incomprensibles, o tu tamaño de bloque/forma de carga impide ganancias. Subir el nivel zstd raramente arregla eso.

Tarea 10: Forzar una reescritura (con cuidado) para aplicar nueva compresión

cr0x@server:~$ sudo zfs snapshot tank/backups@pre-recompress
cr0x@server:~$ sudo rsync -a --inplace --info=progress2 /tank/backups/ /tank/backups/
cr0x@server:~$ zfs get -o name,used,logicalused,compressratio tank/backups
NAME         USED  LOGICALUSED  RATIO
tank/backups 1.05T 2.70T        2.57x

Interpretación: Reescribir datos puede aplicar la nueva compresión, pero también genera I/O, riesgo de fragmentación y potencialmente mucho churn. Haz snapshot primero, prográmalo y vigila la salud del pool. (Y sí, rsync a sí mismo es una herramienta tosca; úsala con cuidado y entendimiento.)

Tarea 11: Observar saturación de CPU durante carga

cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.6.0 (server) 	12/24/2025 	_x86_64_	(32 CPU)

12:05:01 PM  CPU   %usr %sys %iowait %irq %soft %idle
12:05:02 PM  all   72.0 18.0    0.5   0.0   0.5   9.0
12:05:02 PM   10   95.0  4.0    0.0   0.0   0.0   1.0

Interpretación: Si la CPU está al 100% mientras iowait es bajo, el sistema no está “esperando disco”—está haciendo trabajo. Compresión, checksum, cifrado y overhead del kernel son sospechosos habituales.

Tarea 12: Comprobar salud del pool y contadores de errores antes de culpar a la compresión

cr0x@server:~$ zpool status -v tank
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 02:14:33 with 0 errors on Sun Dec 21 03:00:00 2025
config:

	NAME        STATE     READ WRITE CKSUM
	tank        ONLINE       0     0     0
	  mirror    ONLINE       0     0     0
	    nvme0n1  ONLINE       0     0     0
	    nvme1n1  ONLINE       0     0     0

errors: No known data errors

Interpretación: Ajustar la compresión no va a arreglar un disco que arroja errores o un pool que está constantemente resilverando. Verifica siempre la salud base.

Tarea 13: Inspeccionar propiedades del dataset que suelen acompañar decisiones de compresión

cr0x@server:~$ zfs get -o name,property,value atime,sync,logbias,primarycache,secondarycache -r tank/vm | head -n 12
NAME     PROPERTY        VALUE
tank/vm  atime           off
tank/vm  sync            standard
tank/vm  logbias         latency
tank/vm  primarycache    all
tank/vm  secondarycache  all

Interpretación: La gente suele cambiar la compresión junto con otros controles y luego no puede atribuir la causa. Captura estas propiedades antes de los experimentos para poder revertir limpiamente.

Tarea 14: Validar lo que se envía durante la replicación (la compresión importa)

cr0x@server:~$ sudo zfs send -nPv tank/db@hourly-001 | head
send from @ to tank/db@hourly-001 estimated size is 12.3G
total estimated size is 12.3G

Interpretación: El tamaño de replicación está influenciado por los bloques cambiados y su tamaño comprimido en disco. Si ajustas la compresión y reescribes datos, el tráfico de replicación puede cambiar materialmente—a veces para bien, a veces como una factura de ancho de banda inesperada.

Guion de diagnóstico rápido

Este es el orden de operaciones cuando “está lento ahora”. El objetivo es encontrar el cuello de botella en minutos, no ganar una discusión sobre la ideología de compresión.

Primero: decide si estás bound por almacenamiento o por CPU

  1. Comprueba saturación de CPU: si las CPUs están al máximo y iowait es bajo, sospecha compresión/checksum/cifrado.
  2. Comprueba awaits y utilización de dispositivos: si los awaits suben y los dispositivos están calientes, estás bound por almacenamiento (o las colas son demasiado profundas).
  3. Comprueba síntomas de la aplicación: los timeouts durante picos suelen correlacionar con picos de latencia I/O en p99.
cr0x@server:~$ mpstat 1 3
cr0x@server:~$ iostat -x 1 3
cr0x@server:~$ zpool iostat 1 3

Segundo: identifica qué datasets están involucrados

No ajustes todo el pool porque un dataset se porta mal.

cr0x@server:~$ zfs list -o name,used,logicalused,compressratio,mountpoint -r tank | head -n 20

Qué buscas: los datasets más activos, los que tienen bajo ratio pero niveles altos de compresión, y cualquier dataset que guarde cargas sensibles a la latencia.

Tercero: correlaciona nivel de compresión con la forma de la carga

Pregunta: ¿es escritura aleatoria intensiva? ¿secuencial? ¿ya está comprimido? ¿muchos archivos pequeños? ¿zvols de VM? ¿BD con recordsize 16K? Luego comprueba las propiedades reales.

cr0x@server:~$ zfs get -o name,compression,recordsize,volblocksize,sync -r tank/vm tank/db tank/backups

Cuarto: haz el cambio más pequeño y seguro

Si sospechas overhead de CPU por compresión:

  • Reduce el nivel de compresión en el dataset afectado primero.
  • No reescribas todo durante el incidente.
  • Deja que las nuevas escrituras tomen el nuevo ajuste y reevalúa.
cr0x@server:~$ sudo zfs set compression=zstd-1 tank/vm
cr0x@server:~$ zfs get compression tank/vm

Quinto: confirma la mejora con las mismas métricas que usaste para declarar el problema

cr0x@server:~$ iostat -x 1 5
cr0x@server:~$ zpool iostat 1 5

Interpretación: La mejora debería mostrarse como reducción de latencia de escritura, reducción de saturación de CPU, menos timeouts. Si no, la compresión no era el cuello de botella—sigue investigando.

Listas de verificación / plan paso a paso

Un plan sensato para cambiar niveles zstd

  1. Inventario del estado actual: registra compresión, recordsize/volblocksize, ajustes de sync y ratios actuales.
  2. Elige datasets candidatos: selecciona los que tienen alto coste I/O o alto coste de capacidad, no todo.
  3. Define métricas de éxito: elige latencia p95/p99, utilización de CPU, throughput y tasas de error.
  4. Canario primero: un dataset, un nodo o un tenant.
  5. Cambia una variable: no mezcles cambios de nivel de compresión con cambios de recordsize en el mismo despliegue.
  6. Observa durante un ciclo comercial completo: al menos un periodo pico.
  7. Avanza o revierte: basado en impacto medido, no solo en compressratio.

Un método paso a paso para elegir un nivel para un dataset nuevo

  1. Clasifica la carga: VM, BD, backup, logs, medios, mixto.
  2. Configura recordsize apropiadamente (no asumas el valor por defecto).
  3. Empieza bajo: compression=zstd-1 o zstd-2.
  4. Mide la compresibilidad después de que caigan datos reales (no sintéticos).
  5. Si la ratio es buena y hay CPU disponible, prueba un nivel superior.
  6. Detente cuando las ganancias marginales se aplanen o las colas de latencia empiecen a moverse.

Errores comunes (síntomas y soluciones)

Error 1: Establecer un nivel zstd alto globalmente “porque el almacenamiento es caro”

Síntomas: saturación de CPU repentina en nodos de almacenamiento, aumento de latencia de escritura p99, timeouts de aplicación durante picos y mucha culpa hacia “la red”.

Solución: baja a un nivel bajo en los datasets calientes primero (VMs, BD). Mantén niveles más altos solo para datasets fríos/secuenciales que demuestren beneficio. Valida con métricas p99 y de CPU.

Error 2: Juzgar el éxito solo por compressratio

Síntomas: “Ahorramos 20% de espacio” seguido de “¿Por qué los despliegues son más lentos?” o “¿Por qué nuestras VMs se quedan colgadas?”

Solución: sigue los resultados de la carga: percentiles de latencia I/O, throughput en picos y margen de CPU. Los ahorros de capacidad son reales, pero no son el único KPI.

Error 3: Olvidar que cambiar la compresión no recomprime bloques antiguos

Síntomas: cambias el nivel de compresión y nada parece suceder; las ratios no se mueven; equipos concluyen “zstd es inútil”.

Solución: entiende que solo las escrituras nuevas usan el ajuste nuevo. Si necesitas recomprimir datos antiguos, planifica una reescritura controlada (y espera I/O extra y implicaciones de snapshots).

Error 4: Usar un “recordsize único para todo”

Síntomas: bases de datos van lentas tras fijar recordsize 1M “para mejor compresión”, o latencia de VM tras cambiar recordsize en un dataset que almacena imágenes.

Solución: fija recordsize por carga. Compresión y recordsize están acoplados; afinadlos en pareja, pero cambiad uno a la vez.

Error 5: Culpar a la compresión por un pool que falla

Síntomas: degradación de rendimiento que coincide con aumento de errores de lectura/escritura/checksum, scrubs que duran una eternidad o resilvers en curso.

Solución: comprueba zpool status y salud SMART/NVMe primero. Un pool en reparación será lento independientemente de la compresión.

Error 6: Pasar por alto la interacción con cifrado y escrituras sync

Síntomas: picos de CPU y colas de latencia tras habilitar cifrado y subir el nivel zstd; cargas síncronas empeoran.

Solución: trata el nivel de compresión como parte de una canalización. Si el cifrado está habilitado, sé más conservador con la compresión en datasets calientes. Valida cargas sync específicamente.

Preguntas frecuentes

1) ¿Debo habilitar compresión zstd en todas partes?

Habilítala ampliamente a un nivel bajo si tus CPUs tienen margen y quieres operaciones más simples. Pero “en todas partes a un nivel alto” es cómo creas almacenamiento ligado a la CPU. Si tienes sistemas con CPU muy limitadas que sirven datos mayormente incomprensibles, considera mantener la compresión baja o desactivada para esos datasets.

2) ¿Qué nivel zstd es el mejor por defecto?

Para muchos datasets de propósito general, zstd-1 a zstd-3 es el punto óptimo: ahorros significativos, bajo overhead. Usa niveles más altos solo cuando hayas medido tanto ratios mejoradas como latencia aceptable.

3) ¿Por qué no cambió mi compressratio después de fijar un nuevo nivel?

Porque los bloques existentes mantienen su compresión original. Solo las escrituras nuevas usan el nuevo ajuste. Para cambiar datos históricos necesitas churn o una reescritura planificada (y deberías hacer snapshot primero).

4) ¿La compresión ayuda más a lecturas o escrituras?

Ambas pueden beneficiarse. Las escrituras pueden mejorar porque menos bytes llegan al disco; las lecturas pueden mejorar porque menos bytes salen del disco y caben mejor en caches. Pero la compresión cuesta CPU en la escritura (compresión) y en la lectura (descompresión). En muchos sistemas la descompresión es barata; la compresión es el centro de coste.

5) ¿zstd siempre es mejor que lz4 en ZFS?

No. lz4 es extremadamente rápido y a menudo “suficientemente bueno”. zstd en niveles bajos puede acercarse en velocidad mientras ofrece mejores ratios, pero la elección depende del margen de CPU y la carga. Si eres sensible a la latencia y tienes CPU limitado, lz4 puede seguir siendo el predeterminado más seguro.

6) ¿Cómo sé si estoy ligado por CPU debido a la compresión?

Mira uso de CPU alto con iowait bajo, aumento de latencia de escritura durante periodos de escritura intensiva y mejora cuando reduces el nivel de compresión en el dataset caliente. Usa mpstat, iostat -x y zpool iostat juntos para triangular.

7) ¿Los niveles más altos reducirán el ancho de banda de replicación?

En general sí, porque los streams de zfs send reflejan los tamaños de bloque en disco y los bloques comprimidos son más pequeños. Pero si reescribes muchos datos para aplicar nueva compresión podrías aumentar temporalmente el tráfico de replicación debido al mayor churn. Mide antes y después en ciclos normales.

8) ¿Debo recomprimir datasets antiguos después de cambiar niveles?

Sólo si tienes una razón de negocio (presión de capacidad, almacenamiento caro, limitaciones de replicación) y una ventana de mantenimiento. Las reescrituras generan I/O intenso y pueden interactuar con snapshots y fragmentación. En muchos casos, dejar que el churn natural migre bloques lentamente es la opción más segura.

9) ¿Cómo afecta recordsize a la elección del nivel zstd?

Con bloques más grandes, a menudo obtienes mejores ratios de compresión, y los niveles zstd más altos pueden dar algo más de beneficio. Con bloques pequeños y escrituras aleatorias, los niveles altos pueden costar más CPU por ganancia mínima. Por eso los datasets de VM y BD tienden a mantenerse en niveles bajos.

10) ¿Cuál es la forma más segura en producción de experimentar?

Cambios por dataset, canarios y una variable a la vez. Mantén un plan de rollback: siempre puedes bajar la compresión para nuevas escrituras inmediatamente y posponer la recompresión de bloques antiguos hasta estar seguro.

Conclusión

Elegir niveles de compresión zstd en ZFS no se trata de encontrar “el número perfecto”. Se trata de colocar el cuello de botella donde puedas pagarlo. Los niveles bajos de zstd a menudo entregan el mejor retorno: ahorros sólidos de espacio, mejor ancho de banda efectivo y dolor mínimo de CPU. Niveles más altos pueden justificarse—especialmente para datasets secuenciales, fríos o de backups—pero sólo cuando hayas medido que las ganancias marginales valen el riesgo de CPU y latencia.

Si recuerdas una regla operativa: afina la compresión como afinas cualquier cosa en producción—ámbito pequeño, resultados medibles, despliegue por etapas y rollback que no requiera hazañas heroicas. Tu yo futuro, en el peor día del trimestre, te lo agradecerá.

← Anterior
Ubuntu 24.04: Fail2ban no está bloqueando nada — flujo rápido de verificación
Siguiente →
Debian 13: Tiempos de espera de NFS — las opciones de montaje que mejoran la estabilidad (y cuándo no lo hacen)

Deja un comentario