La gente habla de ZFS compression=lz4 como si fuera un cupón universal: actívalo y todo va más rápido y ocupa menos. En producción, a menudo sí se siente como dinero gratis—hasta que deja de serlo. La clave es que “gratis” depende de dónde tengas el cuello de botella, de cómo estén formateados tus bloques y de lo que realmente creas que ZFS hace bajo el capó.
Este texto está escrito desde la perspectiva de quien ha mirado gráficos de almacenamiento a las 2 a.m., discutido con planificadores de CPU y aprendido (a la mala) que la compresión es tanto una característica de rendimiento como una decisión de diseño de sistemas. Cubriremos cuándo lz4 es efectivamente gratis, cuándo te cuesta y cómo diagnosticarlo rápidamente sin superstición.
Qué significa realmente “gratis” en la compresión ZFS
En sistemas, “gratis” nunca significa coste cero. Significa que el coste se paga en algún sitio donde tienes exceso: ciclos de CPU sobrantes, ancho de banda de memoria no usado, holgura en la canalización o simplemente menos dolor que la alternativa. Con la compresión de ZFS, la compensación básica es:
Gastas CPU para ahorrar E/S. Esas E/S ahorradas pueden ser ancho de banda de disco, IOPS, profundidad de cola o incluso tiempo esperando cálculo de paridad/RAID y latencia del dispositivo. Si tu almacenamiento es el cuello de botella, la compresión puede hacer el sistema más rápido al enviar menos bytes por la parte más lenta de la pila. Si la CPU es el cuello de botella, la compresión puede hacerlo más lento añadiendo trabajo en la ruta crítica.
lz4 es popular porque su descompresión es extremadamente rápida y predecible, y su compresión es lo bastante rápida como para que, en muchos sistemas prácticos limitados por almacenamiento, se sienta “gratis”. Pero ZFS no comprime un archivo; comprime bloques (registros), y el rendimiento depende del tamaño de bloque, patrón de acceso, entropía de los datos y de cómo tu carga golpea ARC y los discos.
Aquí hay un modelo mental útil: la compresión en ZFS es como empaquetar un camión de mudanza. Si la autopista está atasca, empaquetar apretado te hace llegar antes. Si llegas tarde porque aún estás embalando la cocina, empaquetar más cuidadosamente te retrasa más. Mismo viaje, distinto cuello de botella.
Broma #1: La compresión es como afeitarse—cuando va bien te sientes suave, y cuando va mal estás sangrando y fingiendo que “solo es un pequeño corte”.
Datos interesantes y contexto histórico
Algunos puntos de contexto que suelen aclarar decisiones sobre compresión:
- La compresión de ZFS es por dataset y en línea. Puedes activarla sin reescribir bloques existentes; se aplica a los bloques nuevos escritos.
- lz4 se convirtió en el valor por defecto en muchas instalaciones porque está diseñado para velocidad y bajo uso de CPU, no por máxima ratio.
- ZFS almacena bloques ya comprimidos en disco, y (crítico) esos bloques también se almacenan comprimidos en ARC; la descompresión ocurre bajo demanda.
- “Copias” y “paridad” ocurren después de la compresión. Generalmente quieres comprimir primero para espejar/paridad menos bytes (el apilamiento exacto depende de detalles de implementación, pero el efecto neto es: menos bytes escritos).
- Los checksums cubren los datos lógicos. ZFS valida la integridad independientemente de la compresión; la descompresión no es “a ver qué pasa”.
- No todos los datos se comprimen. Datos cifrados, medios ya comprimidos y muchos formatos columnares modernos a menudo son prácticamente incomprimibles a nivel de bloque.
- Recordsize importa más de lo que la gente piensa. La compresión actúa sobre el registro; una descoordinación entre recordsize y el patrón de I/O puede dominar el rendimiento.
- ARC comprimido puede ser una ganancia oculta. Si tu working set es compresible, ARC efectivamente guarda más datos lógicos por GB de RAM.
- Históricamente, se usaron niveles de gzip para exprimir espacio en discos caros. Eso tenía sentido cuando las CPUs estaban ociosas y el almacenamiento escaso; hoy el perfil de costes es distinto, pero el instinto perdura.
Cómo funciona realmente la compresión en ZFS (las partes que importan)
La compresión es una decisión en la ruta de escritura
La compresión en ZFS ocurre cuando se escriben bloques. Para un dataset con compression=lz4, ZFS intenta comprimir cada bloque y solo guarda la versión comprimida si es más pequeña por un umbral (específico de la implementación, pero piensa “no compenses si el ahorro es trivial”). Si el bloque no se comprime de forma significativa, se almacena sin comprimir. Esto importa porque “compresión activada” no significa “todo está comprimido”.
Bloques, recordsize y por qué tu intuición sobre “archivo” engaña
ZFS es un sistema de archivos transaccional copy-on-write. Los archivos se representan como un conjunto de bloques (registros). Para un dataset típico, el recordsize podría ser 128K. Eso significa que las escrituras secuenciales pueden ensamblarse en registros de 128K, y cada registro de 128K recibe su propio intento de compresión. La E/S aleatoria puede fracturar esa historia.
Si tu aplicación hace escrituras aleatorias de 8K dentro de un registro de 128K, ZFS aún tiene que gestionar el registro (a menudo vía semántica de lectura-modificación-escritura en algún nivel). La compresión entonces puede formar parte de un problema mayor de “amplificación por escrituras aleatorias pequeñas”. No es culpa de la compresión, pero sí supone tiempo de CPU encima de una operación ya cara.
ARC almacena datos comprimidos (y esto es importante)
Cuando ZFS lee un bloque comprimido del disco, puede mantenerlo en ARC en forma comprimida. Eso significa que la misma RAM puede cachear más datos lógicos, mejorando las tasas de acierto para cargas con datos compresibles. Si alguna vez viste un sistema “mejorar mágicamente” tras activar lz4, a menudo es por esto: no solo el disco hace menos trabajo, ARC es efectivamente más grande.
La descompresión suele ser barata; el coste de comprimir depende de la carga
La descompresión lz4 es famosamente rápida. En muchas cargas, la descompresión se pierde en el ruido comparada con la latencia del disco. La compresión en escrituras puede ser el coste más relevante, especialmente para sistemas de alto rendimiento con muchas escrituras donde la CPU ya está ocupada con checksums, cifrado (si está activado), red o hilos de aplicación.
La compresión interactúa con cifrado, dedup y vdevs especiales
Tres interacciones para mantener claras:
- Cifrado: comprime antes de cifrar. Cifrar primero destruye la compresibilidad. La mayoría de pilas ZFS comprimen y luego cifran cuando ambos están activados, que es lo que deseas.
- Dedup: dedup busca bloques idénticos. La compresión puede ayudar o perjudicar dependiendo de los datos; pero dedup es otra bestia y suele ser el riesgo mayor en producción.
- Vdevs especiales (metadatos / bloques pequeños): comprimir bloques pequeños puede cambiar la mezcla de E/S y los patrones de metadatos. A veces eso es bueno; a veces traslada la presión al vdev especial.
Cuándo lz4 es efectivamente gratis (y a veces más rápido)
lz4 se siente gratis cuando la CPU no es el factor limitante y sí lo es la E/S. Eso es común porque el almacenamiento es lento, la latencia es brutal y muchas cargas mueven una cantidad vergonzosa de bytes redundantes.
1) Cargas limitadas por almacenamiento: discos lentos, arreglos saturados, alta latencia
Si tu pool está cerca de saturación—alta utilización de dispositivos, latencias crecientes, colas llenándose—la compresión puede reducir bytes escritos y leídos. El disco ve menos sectores, la matemática de paridad toca menos bytes y toda la canalización se acorta. Este es el clásico “menos bytes por la pajita”.
He visto un nodo analítico ruidoso pasar de “siempre retrasado” a “mayormente bien” solo activando lz4 en su dataset temporal. No porque lz4 sea mágico, sino porque los datos temporales eran extremadamente repetitivos y los discos eran el cuello de botella.
2) Datos compresibles: texto, logs, JSON, CSV, imágenes de VM con ceros
La compresión gana cuando los datos tienen patrones: cadenas repetidas, espacios, marcas de tiempo, páginas de ceros y en general baja entropía. Los logs y formatos de texto son los casos típicos. Las imágenes de VM a menudo contienen grandes regiones de ceros o espacio poco usado, que se comprime bien incluso cuando el invitado cree que está “asignado”.
En estos casos, la compresión puede reducir la amplificación de escritura y mejorar la densidad de cacheo en lectura. Tu tasa de aciertos en ARC puede mejorar porque los bloques cacheados representan más datos lógicos.
3) Limitaciones de red o replicación: send/receive y backups
Si replicas con zfs send o envías snapshots por la red, almacenar bloques comprimidos puede reducir bytes transferidos (dependiendo de banderas de send e implementación). Incluso cuando el flujo de envío no es “bloques crudos comprimidos” en tu configuración, el efecto global suele tender a menos churn de datos porque se escriben menos bytes desde el principio.
4) Cuando “CPU es barata” realmente es cierto
En muchos servidores, las CPUs están subutilizadas la mayor parte del día. El almacenamiento no lo está. Si ejecutas en una CPU moderna con holgura, lz4 suele ser una buena compensación: quema un poco de CPU para ahorrar tiempo y desgaste de E/S caro.
5) Eficiencia de ARC y ganancia en la cola larga de latencias
La compresión puede mejorar la cola larga de latencias. Cuando ARC guarda más, más lecturas se sirven desde memoria. No solo reduces la latencia promedio; recortas esos momentos en que “a veces toca disco y todo se detiene” que arruinan los p99. Esto es sutil pero valioso operativamente.
Cuándo lz4 no es gratis (y puede ser doloroso)
La compresión deja de ser “gratis” cuando el trabajo extra de CPU cae en tu ruta crítica, o cuando los datos no se comprimen lo suficiente para justificar el esfuerzo.
1) Sistemas limitados por CPU: alto PPS en red, TLS, bases de datos ocupadas, checksumming pesado
Si tu sistema ya está saturado de CPU—hilos de aplicación al máximo, tormentas de interrupciones, sobrecarga de cifrado, patrones con checksums pesados—añadir compresión puede llevarte al límite. El síntoma suele ser: los discos no están ocupados, pero el rendimiento sigue siendo pobre y la CPU está alta.
En algunos nodos, puedes ver un único dataset volver el sistema de “bien” a “misteriosamente lento” durante una carga masiva. Desactiva la compresión y el throughput sube—no porque el almacenamiento sea más rápido, sino porque la CPU dejó de hacer trabajo extra.
2) Datos incomprimibles: medios ya comprimidos, blobs cifrados
JPEG, H.264/H.265, MP3/AAC, muchos archivos de backup modernos y datos cifrados suelen ser efectivamente aleatorios desde el punto de vista del compresor. ZFS intentará comprimir y con frecuencia almacenará el bloque sin comprimir. El intento en sí tiene sobrecarga.
lz4 es rápido, así que el “impuesto por intentar” suele ser pequeño, pero a alto rendimiento es real. Si escribes decenas de GB/s en NVMe rápidos, aunque sea una pequeña sobrecarga por bloque suma.
3) Escrituras aleatorias pequeñas y desajuste de recordsize
Si tienes una carga que hace escrituras aleatorias de 4K–16K dentro de registros grandes, puede que ya pagues una tasa de lectura-modificación-escritura. La compresión añade CPU, y también puede complicar la rapidez con la que ZFS puede ensamblar, checksummar y comprometer transaction groups.
La solución puede no ser “desactivar la compresión”. Puede ser “usar un recordsize o volblocksize apropiado para ese dataset/zvol”, porque estás perdiendo mucho más por amplificación que lo que ganarías o perderías con lz4.
4) Cuando interpretas mal compressratio y optimizas lo equivocado
compressratio es un número seductor. La gente lo persigue como KPI. Pero no es una medida directa de ahorro en todos los caminos, y puede engañar con cargas mixtas, snapshots y bloques escritos antes de activar la compresión.
5) Sensibilidad a latencia en la ruta caliente en cargas con muchas escrituras
Algunos sistemas se preocupan más por latencia de escritura que por throughput: escrituras síncronas, aplicaciones intensas en fsync, ciertas configuraciones de bases de datos. La compresión añade trabajo de CPU antes de que los bloques se comprometan. Si ya estás ajustado al límite, lz4 puede aumentar un poco la latencia p99 de escritura.
Broma #2: Lo único más comprimido que tus bloques ZFS es tu agenda durante una incidencia.
Guía por cargas: bases de datos, VMs, logs, backups, multimedia
Bases de datos (PostgreSQL/MySQL y similares)
Las bases de datos son el lugar donde la gente se pone nerviosa, y a veces tienen razón. El resultado depende del patrón de I/O, tamaño de bloque y si ya estás limitado por CPU.
- Lecturas intensivas con cuello de botella en almacenamiento: lz4 suele ayudar. Menos I/O de lectura, mejor densidad de ARC.
- Escrituras intensivas, CPU limitado: lz4 puede perjudicar. Vigila CPU, comportamiento de commit de txg y latencia.
- I/O aleatorio: ajusta
recordsizesensiblemente (a menudo 16K para algunos ficheros DB), y no uses un dataset único para todo.
Nota operativa: muchas páginas de base de datos son parcialmente compresibles (estructuras repetidas, ceros). lz4 puede dar ratios modestos pero ahorros de I/O significativos.
Imágenes de VM y capas de contenedores
Los discos de VM pueden ser espectacularmente compresibles, especialmente imágenes thin-provisioned con muchos ceros y bloques OS repetidos. lz4 suele ser una victoria, y el impulso en el “tamaño efectivo” del ARC puede ser dramático.
El principal escollo es volblocksize para zvols: elige uno que coincida con los patrones de I/O del invitado. La compresión no te salvará de una elección patológica de tamaño de bloque.
Logs, métricas, trazas
La telemetría basada en texto es la decisión más fácil: lz4 suele ser una ganancia. Sueles ser write-heavy y los datos se comprimen bien. Los ahorros se traducen en menor desgaste del disco y lecturas/reproducciones más rápidas para datos recientes.
Backups y archivos
Si almacenas backups que ya están comprimidos (muchos lo están), lz4 no hará mucho. Pero activarlo no es una locura: ZFS almacenará los bloques incomprimibles sin comprimir, y la sobrecarga suele ser pequeña. Aun así, en tasas de ingestión extremadamente altas (ventanas de backup en objetivos NVMe), considera hacer pruebas.
Repositorios de medios
Para colecciones de fotos/video, lz4 rara vez mejora mucho el espacio. El valor suele estar en una política uniforme (“compresión activada en todas partes”) y la victoria ocasional para miniaturas, metadatos, subtítulos o archivos sidecar. Si tus servidores de medios están limitados por CPU y sirven alto throughput, considera desactivar la compresión en esos datasets.
Tres mini-historias del mundo corporativo
Mini-historia #1: El incidente causado por una suposición equivocada
El equipo de almacenamiento desplegó un nuevo tier NFS respaldado por ZFS para carga mixta: artefactos de compilación, logs y una canalización de exportación de bases de datos. Alguien hizo una suposición razonable: “lz4 es gratis; actívalo en todas partes.” Pasó la revisión de cambios porque se consideró de bajo riesgo—al fin y al cabo, es solo una propiedad de dataset.
Dos semanas después, durante un cierre trimestral, la canalización de exportación empezó a perder su ventana. Saltaron alertas por lag de aplicación, no por almacenamiento. Los primeros en responder miraron el pool: los discos no estaban saturados, la latencia no era terrible, ARC estaba sano. No olía a almacenamiento.
Pero la CPU en el head de almacenamiento estaba alta y con picos, especialmente en tiempo kernel. La carga de escritura era mayormente incomprensible (exports ya comprimidos), pero ZFS aún tenía que intentar comprimir cada registro. Peor aún, la canalización escribía flujos secuenciales grandes a alta velocidad, lo que llevó los intentos de compresión a la ruta caliente justo cuando la CPU ya servía hilos NFS y checksums.
La solución no fue heroica: desactivar la compresión en el dataset de exportación, mantenerla para logs y artefactos. La ventana volvió. La lección no fue “la compresión es mala.” Fue “la compresión es una decisión de carga, no una religión.” Y sí, el postmortem incluyó la frase “gratis, a menos que no lo sea,” que es señal de que ingenieros lo escribieron.
Mini-historia #2: La optimización que salió mal
Un equipo de plataforma quiso reducir el crecimiento de almacenamiento. Tenían un pool que parecía sano, pero las gráficas de capacidad subían. Un sprint de optimización decidió subir la compresión: cambiar de lz4 a gzip-9 en varios datasets porque “mejor ratio = menos coste.” El cambio se hizo tras una pequeña prueba en un nodo de staging tranquilo.
En producción, el almacenamiento ahorró espacio—no hay discusión. Pero la semana siguiente, los desarrolladores empezaron a reportar lentitud intermitente: jobs de CI con timeout, pulls de contenedores atascándose, picos de latencia “aleatorios”. Las gráficas mostraban CPU incrementada, especialmente durante actividad de escritura y snapshots. El pool no había quedado sin IOPS; había quedado sin paciencia.
El fallo vino de dos lados. Primero, gzip-9 es mucho más pesado que lz4, especialmente en escrituras. Segundo, la carga no era dominada por datos fríos. Era datos activos con escrituras/lecturas frecuentes, así que el impuesto de CPU fue todo el día, no solo una vez. El resultado final: ahorraron disco, pero pagaron en productividad y ruido operacional.
El equipo volvió a lz4 para datasets calientes, mantuvo compresión más fuerte solo para datasets fríos/archivo donde la latencia no importaba, y documentó una regla: optimiza para el cuello de botella que realmente tienes. “El disco es caro” es verdad; “la CPU es gratis” no es una ley universal.
Mini-historia #3: La práctica aburrida pero correcta que salvó el día
Otra organización ejecutaba una flota ZFS con una política aburrida que nunca salió en presentaciones: cada dataset tenía propiedades explícitas (compresión, recordsize, atime, logbias donde relevante), y cualquier cambio mayor venía con una prueba antes/después usando patrones de I/O parecidos a producción. No era glamuroso; era consistente.
Un día, desplegaron una nueva aplicación que escribía telemetría a alta tasa. Todos esperaban que fuera bien—el texto se comprime, ¿no? Pero los ingenieros hicieron lo aburrido: crearon un dataset dedicado, pusieron compression=lz4, usaron un recordsize sensato y ejecutaron una carga controlada con iostat y perfilado de CPU.
La prueba sacó una sorpresa: no era el compresor, sino comportamiento de escrituras síncronas y una opción de montaje del cliente mal configurada que dominaban la latencia. Porque tenían números base, no perdieron dos días discutiendo sobre compresión. Arreglaron el comportamiento sync donde procedía, mantuvieron lz4 y desplegaron la app sin drama.
En la revisión del incidente, la compresión apenas apareció—exactamente el punto. La práctica que salvó el día fue la medición disciplinada. En producción, lo aburrido vence a lo ingenioso cuando suena el pager.
Tareas prácticas: comandos, salidas, interpretación
Abajo hay tareas reales que puedes ejecutar en un sistema ZFS. El objetivo no es memorizar comandos; es ligar observaciones a decisiones.
Tarea 1: Comprobar la configuración de compresión del dataset
cr0x@server:~$ zfs get -o name,property,value,source compression tank
NAME PROPERTY VALUE SOURCE
tank compression lz4 local
Interpretación: Confirma lo que está establecido y si es heredado. Si tu dataset hereda de un padre que olvidaste, perseguirás fantasmas.
Tarea 2: Encontrar datasets que difieran de tu política
cr0x@server:~$ zfs get -r -s local,inherited compression tank | sed -n '1,20p'
NAME PROPERTY VALUE SOURCE
tank compression lz4 local
tank/db compression lz4 inherited from tank
tank/media compression off local
tank/backups compression lz4 inherited from tank
tank/exports compression off local
Interpretación: Quieres excepciones intencionales (como media o exports ya comprimidos), no accidentales.
Tarea 3: Ver efectividad de compresión por dataset
cr0x@server:~$ zfs get -o name,used,logicalused,compressratio -r tank | sed -n '1,12p'
NAME USED LOGICALUSED RATIO
tank 1.20T 1.85T 1.54x
tank/db 420G 560G 1.33x
tank/logs 180G 620G 3.44x
tank/media 300G 305G 1.02x
Interpretación: logicalused vs used da pistas sobre ahorros reales. Media apenas se comprime; logs mucho.
Tarea 4: Entender que los datos existentes no se “recomprimirán” automáticamente
cr0x@server:~$ zfs set compression=lz4 tank/olddata
cr0x@server:~$ zfs get -o name,compressratio tank/olddata
NAME RATIO
tank/olddata 1.01x
Interpretación: Si cambiaste la compresión en un dataset lleno de bloques viejos, la ratio no cambiará mucho hasta que ocurran escrituras nuevas.
Tarea 5: Medir I/O y latencia a nivel de pool
cr0x@server:~$ zpool iostat -v 1 5
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 6.30T 2.70T 820 1300 110M 240M
raidz2-0 6.30T 2.70T 820 1300 110M 240M
sda - - 110 180 14.0M 30.1M
sdb - - 105 175 13.8M 29.8M
sdc - - 115 185 14.2M 30.4M
sdd - - 108 182 14.0M 30.2M
sde - - 112 178 14.1M 30.0M
Interpretación: Si los discos están ocupados y el ancho de banda es alto, la compresión puede ayudar reduciendo bytes. Si los discos están inactivos pero el rendimiento es pobre, el cuello de botella está en otro sitio (CPU, escrituras sync, red, app).
Tarea 6: Vigilar I/O por dataset con ZFS iostat
cr0x@server:~$ zfs iostat -r -v tank 1 5
capacity operations bandwidth
dataset used avail read write read write
--------------- ---- ----- ----- ----- ----- -----
tank 1.20T 2.70T 420 610 52.0M 90.0M
tank/db 420G 2.70T 210 240 18.0M 22.0M
tank/logs 180G 2.70T 20 280 1.2M 38.0M
tank/media 300G 2.70T 180 40 32.0M 6.0M
Interpretación: Identifica quién está empujando I/O. Luego toma decisiones de compresión por dataset en lugar de discutir en abstracto.
Tarea 7: Verificar recordsize y por qué importa
cr0x@server:~$ zfs get -o name,property,value recordsize tank/db tank/logs tank/media
NAME PROPERTY VALUE
tank/db recordsize 16K
tank/logs recordsize 128K
tank/media recordsize 1M
Interpretación: El dataset DB usa registros más pequeños (a menudo mejor para I/O aleatorio). Logs por defecto a 128K. Media usa 1M para favorecer throughput secuencial. La compresión opera por registro.
Tarea 8: Comprobar volblocksize de zvols para discos de VM
cr0x@server:~$ zfs get -o name,property,value volblocksize,compression tank/vmdata/vm-101
NAME PROPERTY VALUE
tank/vmdata/vm-101 volblocksize 16K
tank/vmdata/vm-101 compression lz4
Interpretación: El block size de un zvol se establece al crear y modela la E/S. Las ganancias de compresión están limitadas si tu block size causa amplificación.
Tarea 9: Observar saturación de CPU durante eventos intensos de escritura
cr0x@server:~$ mpstat -P ALL 1 5
Linux 6.1.0 (server) 12/24/2025 _x86_64_ (16 CPU)
12:00:01 PM CPU %usr %sys %iowait %idle
12:00:01 PM all 62.10 22.40 0.80 14.70
12:00:02 PM all 68.90 24.10 0.30 6.70
Interpretación: Bajo iowait con poco idle suele significar CPU-bound. Si el rendimiento es malo pero iowait cercano a cero, desactivar la compresión podría ayudar—si la carga es incomprimible o el objetivo es throughput de escritura.
Tarea 10: Estimar compresibilidad con una muestra rápida (segura)
cr0x@server:~$ dd if=/tank/logs/app.log bs=1M count=256 2>/dev/null | lz4 -q -c | wc -c
41234567
Interpretación: Compara contra los bytes originales (256 MiB). Si los bytes comprimidos son mucho menores, lz4 probablemente valga la pena. Es una comprobación aproximada; ZFS actúa por registro y puede diferir.
Tarea 11: Confirmar qué está realmente comprimido en disco (indirecto)
cr0x@server:~$ zdb -DD tank/logs | sed -n '1,20p'
DDT-sha256-zap-duplicate: 0 entries, size 0 on disk, 0 in core
Dataset tank/logs [ZPL], ID 54, cr_txg 12345, ...
Blocks Logical Physical compress% copies% dedup% checksum
------ ------- -------- --------- ------- ------ --------
... 620G 180G 70.9% 100.0% 100.0% 100.0%
Interpretación: Este tipo de salida varía por plataforma, pero la idea es: contabilidad física vs lógica de bloques. Úsala con cuidado; es poderosa pero afilada.
Tarea 12: Probar throughput de escritura con y sin compresión (controlado)
cr0x@server:~$ zfs create -o compression=off tank/bench_off
cr0x@server:~$ zfs create -o compression=lz4 tank/bench_lz4
cr0x@server:~$ fio --name=write_test --directory=/tank/bench_off --rw=write --bs=128k --size=8g --numjobs=4 --iodepth=16 --direct=1
...
WRITE: bw=820MiB/s (860MB/s), iops=6560, runt=10000msec
cr0x@server:~$ fio --name=write_test --directory=/tank/bench_lz4 --rw=write --bs=128k --size=8g --numjobs=4 --iodepth=16 --direct=1
...
WRITE: bw=980MiB/s (1027MB/s), iops=7840, runt=10000msec
Interpretación: Si lz4 mejora el throughput, probablemente estabas I/O-bound y los datos se comprimen. Si lo reduce mientras los discos no están saturados, estás pagando CPU sin gran ganancia.
Tarea 13: Comprobar estadísticas de ARC para efectos de cacheo (Linux)
cr0x@server:~$ arcstat 1 5
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
12:01:01 1200 180 15 20 2% 160 13% 0 0% 64G 96G
12:01:02 1180 140 12 18 2% 122 10% 0 0% 64G 96G
Interpretación: Tasas de miss más bajas tras habilitar compresión pueden ser una ganancia real. La compresión puede hacer que ARC “se sienta más grande” para datasets compresibles.
Tarea 14: Comprobar si un dataset hace escrituras sync (y por qué importa)
cr0x@server:~$ zfs get -o name,property,value sync logbias tank/db
NAME PROPERTY VALUE
tank/db sync standard
tank/db logbias latency
Interpretación: Si tu problema es latencia de escrituras sync, la compresión puede no ser la palanca principal. La salud del SLOG, ajustes sync y comportamiento fsync de la app pueden dominar.
Guía rápida de diagnóstico
Esta es la secuencia de triage que uso cuando alguien dice “ZFS se puso lento tras habilitar lz4” o “lz4 no ayudó como prometía Internet”. El objetivo es encontrar el cuello de botella rápido, no debatir ideologías.
Primero: Determinar la clase de cuello de botella (CPU vs E/S vs fuente de latencia)
- ¿La CPU está saturada? Revisa CPU global y la cola de ejecución. Si la CPU está pegada y iowait es bajo, no estás limitado por disco.
- ¿Los discos están saturados? Mira utilización del pool/dispositivo, latencia, colas. Si los discos están al máximo, la compresión puede ayudar (si los datos se comprimen).
- ¿Es latencia sync? Si la carga es fsync-heavy, revisa SLOG, settings sync y la distribución de latencias.
Segundo: Verificar compresibilidad y dónde están los bytes
- Revisa
logicalusedvsusedycompressratiodel dataset afectado. - Identifica el dataset con más I/O usando
zfs iostato métricas por dataset. - Chequea el tipo de datos (logs vs media vs blobs cifrados). Si es incomprimible, no esperes magia.
Tercero: Validar dimensionado de bloques y patrón de acceso
- Comprueba
recordsize(filesystems) ovolblocksize(zvols). El desajuste causa amplificación que eclipsa efectos de compresión. - Determina I/O aleatorio vs secuencial usando conocimiento de la carga o reproducción con fio. Escrituras aleatorias pequeñas + registros grandes es una trampa clásica.
Cuarto: Decide el cambio más pequeño y seguro
- Si estás CPU-bound y los datos son incomprensibles: desactiva la compresión en ese dataset, no en todo el pool.
- Si estás I/O-bound y los datos se comprimen: mantén lz4, considera mejorar recordsize y verifica comportamiento de ARC.
- Si los resultados son ambiguos: crea un dataset de prueba y haz benchmarks con I/O representativo.
Errores comunes: síntomas y soluciones
Error 1: Habilitar lz4 y esperar que los datos viejos encojan
Síntoma: Pusiste compression=lz4, pero compressratio se mantiene cerca de 1.0x y el espacio no baja.
Por qué: Los bloques existentes no se reescriben. ZFS comprime bloques escritos nuevos.
Solución: Reescribe los datos (por ejemplo, zfs send | zfs receive a un dataset nuevo, o copia dentro del dataset con cuidado). Hazlo intencionalmente; no “rm -rf y recopy” en producción sin plan.
Error 2: Usar compressratio como métrica de rendimiento
Síntoma: Un dataset muestra ratio 2.0x, pero el rendimiento empeora; o la ratio es 1.1x pero el rendimiento mejora.
Por qué: La ratio mide contabilidad de almacenamiento, no latencia/throughput. Efectos de ARC, patrones de I/O y CPU pueden dominar.
Solución: Mide lo que importa: throughput, latencias p95/p99, CPU, iowait, dispositivo ocupado, tasa de aciertos/miss de ARC.
Error 3: Suponer que los datos incomprimibles no tienen coste
Síntoma: La CPU sube durante grandes escrituras de media/archivos; el disco no está ocupado; el throughput baja algo.
Por qué: ZFS aún intenta comprimir bloques antes de decidir que no merece la pena.
Solución: Desactiva la compresión en ese dataset si la CPU es preciosa y la carga es comprobada como incomprimible. O mantenla si la sobrecarga es aceptable y la simplicidad de política importa.
Error 4: Un solo dataset para todo
Síntoma: No puedes afinar recordsize, sync o compresión sin perjudicar alguna carga.
Por qué: Las propiedades de dataset son el límite de tuning. Mezclar VMs, DBs, logs y media en un dataset obliga a compromisos.
Solución: Separa datasets por clase de carga y fija propiedades explícitas.
Error 5: Ignorar recordsize/volblocksize y culpar a la compresión
Síntoma: Una carga de escrituras aleatorias es lenta; activar/desactivar compresión apenas la cambia; los picos de latencia persisten.
Por qué: El desajuste de tamaño de bloque causa lectura-modificación-escritura y patrones de fragmentación que anulan efectos de compresión.
Solución: Usa tamaños de bloque apropiados (a menudo más pequeños para DB, sensatos para VM). Haz benchmarks y valida.
Error 6: Cambiar a compresión pesada en datos calientes
Síntoma: La CPU sube, la latencia p99 se vuelve desagradable, usuarios quejan “se siente lento”, pero ahorraste espacio.
Por qué: Los niveles de gzip no son lz4. Intercambias disco por CPU en una ruta caliente.
Solución: Usa lz4 para datos calientes. Usa compresión más fuerte solo para datasets fríos/archivo donde la latencia no importa.
Listas de comprobación / plan paso a paso
Checklist A: Decidir si habilitar lz4 en un dataset
- Identifica el tipo de carga (logs, DB, VM, media, backups, blobs cifrados).
- Comprueba el cuello de botella actual (CPU vs disco vs red vs latencia sync).
- Estima la compresibilidad (muestra de datos, conocimiento previo, ratios existentes).
- Confirma el dimensionado de bloques:
recordsizepara ficheros,volblocksizepara zvols. - Activa
compression=lz4en un dataset de prueba primero si el riesgo es no trivial. - Haz benchmarks con I/O representativo y mide percentiles de latencia, no solo throughput.
- Despliega en producción con excepciones intencionales y monitorización.
Checklist B: Desplegar lz4 con seguridad en producción
- Documenta propiedades actuales de datasets:
zfs get -r all(filtra según necesidad). - Elige un dataset canario y activa lz4 allí primero.
- Monitorea CPU, iostat del pool, tasa de miss de ARC y latencias p95/p99 de la aplicación por al menos un ciclo de negocio.
- Expande a otros datasets por clase de carga (logs primero suele ser poco drama).
- Mantén excepciones explícitas (media, blobs de exportación) en lugar de desactivar globalmente.
- Escribe un plan de rollback: conoce el comando y el comportamiento esperado “solo afecta escrituras nuevas”.
Checklist C: Si el rendimiento empeoró tras activar lz4
- Confirma la correlación temporal (¿el rendimiento empeoró justo cuando empezaron nuevas escrituras con compresión?).
- Revisa la saturación de CPU; compara con líneas base previas si las tienes.
- Revisa la compresibilidad del dataset: si la ratio se mantiene ~1.0x, lz4 probablemente está haciendo trabajo inútil.
- Identifica qué dataset está caliente; no desactives la compresión en todo el pool.
- Valida recordsize/volblocksize; arregla el problema mayor primero.
- Desactiva la compresión en el dataset afectado si estás CPU-bound y los datos son incomprimibles, y vuelve a probar.
Preguntas frecuentes
1) ¿Debería activar compression=lz4 en todos los datasets ZFS?
A menudo sí para datasets de propósito general, pero “todos” debería incluir excepciones intencionales. Repositorios de medios y blobs ya comprimidos son candidatos comunes para compression=off si la CPU es crítica.
2) ¿Por qué lz4 a veces hace que las cosas vayan más rápido?
Porque reduces E/S: escribir/leer menos bytes significa menos operaciones de disco y mejor densidad de caché. Si estás limitado por almacenamiento, gastar un poco de CPU para reducir E/S puede mejorar throughput y colas largas de latencia.
3) ¿Por qué lz4 a veces hace que las cosas vayan más lento?
Si estás limitado por CPU, la compresión añade trabajo en la ruta crítica. También, si los datos son incomprimibles, puedes pagar la sobrecarga del intento sin ahorrar E/S.
4) ¿Activar la compresión comprime archivos existentes?
No. Se aplica a bloques escritos nuevos. Los bloques existentes permanecen como estaban hasta que se reescriban.
5) ¿Es compressratio la mejor forma de juzgar éxito?
Es una pista útil pero no el veredicto final. Úsala junto a latencia de aplicación, utilización del pool/dispositivos, carga de CPU y comportamiento de aciertos/miss de ARC.
6) ¿Qué hay de compression=zstd?
zstd puede ofrecer mejores ratios a velocidades razonables según el nivel y soporte de la plataforma. Pero el tema aquí es el perfil “victoria por defecto” de lz4. Si consideras zstd, haz benchmarks con I/O similar a producción y trata el nivel de compresión como un ajuste, no como un checkbox.
7) ¿La compresión ayuda a ARC?
Sí, a menudo. Los bloques comprimidos pueden cachearse en forma comprimida, permitiendo que ARC almacene más datos lógicos por unidad de RAM—si los datos son compresibles.
8) ¿La compresión reduce el desgaste en SSDs?
Puedes reducir desgaste al escribir menos bytes físicos cuando los datos se comprimen. El impacto real depende de la carga y de cuán compresible sea el flujo de escritura.
9) ¿Debería desactivar la compresión para datasets cifrados?
Si usas cifrado nativo de ZFS, la compresión suele ocurrir antes del cifrado, así que todavía obtienes beneficios. Si los datos ya están cifrados a nivel de aplicación (con aspecto aleatorio), la compresión no ayudará mucho y podrá ser sobrecarga.
10) Si lz4 es tan bueno, ¿por qué no usar gzip en todas partes para ahorrar más espacio?
Porque en la ruta caliente importan CPU y latencia. gzip puede ser genial para archivos fríos; puede ser un recaudador de impuestos para cargas activas. Usa la herramienta adecuada según la temperatura del dataset.
Conclusión
La compresión ZFS lz4 es “gratis” cuando intercambia CPU sobrante por I/O escaso y tus datos realmente se comprimen. No es gratis cuando la CPU ya es el reactivo limitante, cuando los datos son incomprimibles o cuando el dimensionado de bloques y los patrones de acceso son los verdaderos villanos escondiéndose tras la compresión.
El enfoque ganador en producción es aburrido y repetible: separa datasets por carga, fija propiedades intencionalmente, mide las señales de cuello de botella correctas y mantén un pequeño playbook de diagnóstico que puedas ejecutar a las 2 a.m. Cuando haces eso, lz4 deja de ser folklore y se convierte en lo que realmente es: una palanca práctica que puedes accionar con confianza.