Activaste el cifrado porque seguridad lo pidió amablemente (o porque los auditores lo pidieron groseramente). Luego activaste la compresión
porque el almacenamiento es caro y la pool siempre está “misteriosamente” más llena de lo previsto. Y ahora el rendimiento es extraño:
picos de CPU, latencias variables y “¿por qué este dataset es más lento que el no cifrado?” se convierte en un ritual semanal.
ZFS es determinista. Tu carga de trabajo no lo es. La brecha entre esos dos es donde viven la mayoría de los dolores en producción. Cerremos esa brecha:
qué orden usa el pipeline, qué perillas importan y cómo demostrar qué es lo que realmente te está limitando.
El orden del pipeline: qué sucede primero y por qué debes importarte
ZFS no “más o menos” comprime ni “algo” cifra. Hace ambas cosas en un pipeline muy específico, y los resultados de rendimiento
siguen ese orden como una sombra.
Qué hace ZFS con tus datos (modelo simplificado pero preciso)
Para el cifrado nativo de ZFS (la funcionalidad en el dataset), la secuencia importante es:
- La aplicación escribe bloques lógicos (archivos, páginas de BD, bloques de VM) dentro del mundo de recordsize/volblocksize del dataset.
-
La compresión ocurre primero (si está activada). ZFS intenta comprimir cada registro (p. ej., 128K) de forma independiente.
Si el resultado no es lo bastante más pequeño, puede almacenarlo sin comprimir (comportamiento dependiente del algoritmo, pero el resultado es simple:
no desperdiciará espacio sin ganancia). -
El cifrado sucede después de la compresión. Esto es lo importante. Cifrar texto aleatorio resulta básicamente
incomprimible, así que si cifras primero estás muerto; la compresión se convierte en un elegante no-op. - Se calculan checksums para integridad, y ZFS escribe los bloques en el layout de vdev de la pool, con semántica copy-on-write.
El orden (comprimir luego cifrar) es por qué puedes tener seguridad y eficiencia de espacio—sin magia. También es por qué ciertos
problemas de rendimiento aparecen solo después de activar el cifrado: la compresión aún puede ahorrar E/S, pero has movido trabajo
hacia la CPU. Si no tienes margen de CPU, la latencia se convierte en tu nuevo pasatiempo.
El modelo mental que evita errores tontos
Piénsalo así: la compresión reduce bytes; el cifrado destruye patrones. Por eso quieres reducir bytes mientras los patrones
todavía existen. Después encriptas.
Si usas cifrado nativo de ZFS, obtienes el orden correcto por diseño. Si haces “cifrado” en la aplicación
o encima de ZFS (archivos cifrados dentro de un dataset no cifrado), podrías estar cifrando antes de que ZFS vea los datos,
y ahora la compresión de ZFS es mayormente decorativa.
Chiste #1: Activar compresión para datos ya cifrados es como instalar un turbo en una bicicleta—técnicamente impresionante, funcionalmente confuso.
Qué significa “orden” en el mundo real
Este artículo no discute sobre orden filosófico; trata sobre hacia dónde van los ciclos de CPU y la E/S. El orden que te importa es:
- ¿Dónde ocurre el cifrado? ¿Cifrado nativo de ZFS? ¿Nivel de aplicación? ¿Sistema de archivos arriba de ZFS?
- ¿Dónde ocurre la compresión? ¿Propiedad del dataset en ZFS? ¿Compresión en la aplicación? ¿Herramienta de backup?
- ¿Cuándo los datos se vuelven incomprimibles? Más comúnmente: después del cifrado, después de formatos ya comprimidos (JPEG, MP4),
o después de compresión a nivel de aplicación (p. ej., compresión de páginas de BD).
Hechos e historia que cambian las decisiones
Algo de contexto paga la renta. Aquí hechos concretos y puntos históricos cortos que importan cuando haces cambios en una pool de producción.
- El cifrado de ZFS es nativo y por dataset. No es una capa de dispositivo de bloque separada añadida después; es una característica del dataset con opciones de herencia de claves.
- El cifrado nativo llegó mucho después que ZFS. ZFS se creó a mediados de los 2000; el cifrado nativo aterrizó años después, tras largo debate sobre manejo de claves y flags de características.
- La compresión en ZFS existe “desde siempre” en términos de ZFS, y ha sido predeterminada en muchas organizaciones durante años porque a menudo mejora el rendimiento reduciendo E/S.
- AES-GCM es común para el cifrado en ZFS porque provee cifrado autenticado (confidencialidad + integridad). Esa integridad es separada de, pero complementaria a, los checksums de ZFS.
- Los checksums de ZFS son end-to-end: se almacenan y verifican en lecturas, permitiendo detectar corrupción silenciosa. El cifrado no reemplaza esto; se sitúa al lado.
- La compresión es por-bloque (registro) y local. ZFS no comprime “archivos”; comprime bloques, por eso recordsize y la forma de la carga importan tanto.
- ARC cachea datos comprimidos (y los datasets cifrados tienen sus propias implicaciones). La efectividad de la caché depende del tamaño post-compresión y los patrones de acceso.
- zfs send/receive soporta modos de replicación cifrada. Puedes enviar streams cifrados en bruto que no requieren claves en el receptor—útil para destinos de backup no confiables.
- Los CPUs modernos tienen aceleración AES (AES-NI en x86, similar en otras plataformas), convirtiendo “el cifrado es lento” en “el cifrado suele estar bien, hasta que no lo está.”
Una cita, porque es dolorosamente cierta en operaciones. Gene Kranz dijo: “Failure is not an option.” (Es un lema cultural, no un parámetro del kernel.)
Realidades de rendimiento: cifrado, compresión y la CPU que realmente tienes
A la gente le gustan respuestas simples: “La compresión es rápida,” “el cifrado es lento,” “NVMe lo arregla todo.” La realidad es más fea y más interesante.
El rendimiento es una negociación a tres bandas entre ciclos de CPU, ancho de banda de memoria/comportamiento de caché y latencia/IOPS de almacenamiento.
La compresión puede acelerar las cosas, incluso cuando cuesta CPU
Si tu pool está limitado por E/S, la compresión suele ganar dos veces:
- Escribe menos bytes, así que tus discos hacen menos trabajo.
- Lee menos bytes, lo que puede convertir picos de latencia en algo que dejas de notar.
Pero la compresión no es gratis. Algoritmos como lz4 están diseñados para velocidad; zstd puede intercambiar CPU por mejores ratios.
Elige según tu cuello de botella. Si ya estás limitado por CPU (alta utilización, cola de ejecución, cambios de contexto frecuentes),
habilitar compresión pesada es cómo conviertes un problema leve en una cola de tickets.
La sobrecarga del cifrado suele estar “bien”, hasta que no lo está
Con aceleración por hardware, AES-GCM puede ser muy rápido. Pero el cifrado aún añade:
- Trabajo de CPU por cada bloque escrito y leído.
- Algo de manejo extra de metadatos.
- Potencial presión de caché y ancho de banda de memoria bajo alto rendimiento.
El modo de fallo no siempre es obvio. Puedes tener bastante “CPU promedio” pero aun así carecer de margen por núcleo.
Los hilos de almacenamiento pueden volverse sensibles a latencia; si se ejecutan en núcleos ya ocupados con trabajo de la app, obtienes jitter.
El orden te da una palanca: reduce bytes antes de pagar el coste del cifrado
Porque ZFS comprime antes de cifrar, la compresión reduce la cantidad de datos que deben ser cifrados y escritos.
Esto importa cuando:
- Tienes un dataset que se comprime bien (logs de texto, JSON, imágenes de VM con ceros, muchas páginas de BD).
- Estás limitado por throughput en almacenamiento o replicación por red.
- Replicas datos cifrados (send/receive), donde bytes en la red te cuestan tiempo.
Si los datos ya están comprimidos (media, muchos backups, blobs cifrados), la compresión no reducirá bytes. Aun así pagas
el coste de intentar comprimir, aunque pequeño para lz4 y no trivial para niveles más pesados de zstd.
El nivel de compresión es una decisión de política, no una vibra
La tentación es elegir un algoritmo que suene cool (“zstd-19, porque número más grande”) y llamarlo optimización.
Eso no es ingeniería; es cosplay.
Aquí la postura práctica:
- Por defecto, usa
compression=lz4casi en todas partes. Es la elección “segura” y a menudo gana tanto en espacio como en velocidad. - Usa
compression=zstd(nivel moderado) para datasets donde hayas medido beneficios reales y tengas presupuesto de CPU. - Desactiva la compresión para datasets que sean demostrablemente incomprimibles y extremadamente sensibles a latencia (raro, pero real).
La gestión de claves de cifrado puede convertirse en tu problema de rendimiento
No directamente—la criptografía es rápida—sino porque errores operativos provocan demoras y cortes. Si las claves no se cargan al arranque, tus servicios
no montan, tus apps no arrancan y terminas depurando “rendimiento de almacenamiento” que en realidad es “almacenamiento no disponible.”
Chiste #2: El sistema de archivos más rápido es el que monta; el segundo más rápido es el que no despierta a tu on-call a las 3 a.m.
Diseño de datasets: recordsize, volblocksize y ajuste a la carga de trabajo
El cifrado y la compresión no son interruptores independientes. Interactúan con el dimensionamiento de bloques y los patrones de acceso. La mayoría de los incidentes de “ZFS es lento”
son en realidad “ZFS está haciendo exactamente lo que pediste, y lo que pediste era extraño.”
recordsize: el multiplicador oculto
recordsize afecta a datasets de archivos (no a zvols) y controla el tamaño máximo de bloque que ZFS usa para datos de archivo.
Registros más grandes:
- Mejoran el throughput secuencial (menos operaciones de E/S).
- Aumentan la efectividad de la compresión (más datos por bloque, más patrones).
- Pueden perjudicar la latencia de lectura aleatoria para lecturas pequeñas (amplificación de lectura).
El cifrado y la compresión operan por registro. Si eliges un recordsize que no encaja con tu carga, amplificas
el trabajo de CPU y la E/S en los lugares equivocados.
volblocksize: para zvols, tienes una sola oportunidad (mayormente)
Para zvols, volblocksize es el tamaño de bloque expuesto al consumidor (VM, iSCSI, etc.). Se establece al crear y
es difícil de cambiar sin recrear el volumen.
Si ejecutas bases de datos o imágenes de VM en zvols, acierta con volblocksize. Si el huésped escribe bloques de 8K y tu volblocksize es 128K,
vas a ofrecer una clase magistral de amplificación de escrituras.
vdevs especiales y metadatos: la trampilla de rendimiento
El cifrado y la compresión tratan sobre bloques de datos, pero el comportamiento de metadatos puede dominar la latencia. Si tu carga es intensiva en metadatos
(millones de archivos pequeños, contenedores, artefactos de compilación), tu dataset “de datos” puede verse bien mientras los metadatos están thrashing.
Los vdevs especiales pueden ayudar, pero deben diseñarse cuidadosamente y protegerse como ciudadanos de primera clase.
Tareas prácticas: comandos, salidas y la decisión que tomas
La teoría es barata. Aquí tienes tareas prácticas que puedes ejecutar en un sistema ZFS para entender si el cifrado y la compresión están ayudando,
dañando o solo luciendo ocupados. Cada tarea incluye: comando, qué significa la salida y la decisión que tomas.
Tarea 1: Confirmar propiedades de cifrado y compresión en un dataset
cr0x@server:~$ zfs get -o name,property,value,source encryption,keystatus,keylocation,keyformat,compression,compressratio pool/app
NAME PROPERTY VALUE SOURCE
pool/app encryption aes-256-gcm local
pool/app keystatus available -
pool/app keylocation prompt local
pool/app keyformat passphrase local
pool/app compression zstd local
pool/app compressratio 1.72x -
Qué significa: el cifrado está activado, la clave está cargada (keystatus=available), la compresión es zstd y la ratio real es 1.72x.
Decisión: Si compressratio está cerca de 1.00x y la carga es sensible a latencia, considera compression=lz4 o desactivarla.
Si keystatus no está available, arregla la carga de claves antes de perseguir “rendimiento.”
Tarea 2: Comprobar si estás comprimiendo datos incomprimibles
cr0x@server:~$ zfs get -o name,property,value compressratio,compression pool/media
NAME PROPERTY VALUE SOURCE
pool/media compressratio 1.01x -
pool/media compression zstd local
Qué significa: zstd está haciendo básicamente nada. Probablemente archivos multimedia o objetos ya comprimidos.
Decisión: Cambia a compression=lz4 o compression=off si la CPU está caliente y este dataset no se beneficia.
Tarea 3: Medir si el cifrado está presente donde crees que está
cr0x@server:~$ zfs get -o name,property,value encryption -r pool
NAME PROPERTY VALUE SOURCE
pool encryption off default
pool/app encryption aes-256-gcm local
pool/app/db encryption aes-256-gcm inherited from pool/app
pool/backups encryption off local
Qué significa: No todo está cifrado. La herencia funciona para pool/app/db; backups no están cifrados.
Decisión: Decide la política: ¿los backups necesitan cifrado? Si sí, habilítalo a nivel de dataset (o usa send en crudo).
Tarea 4: Comprobar características de CPU que abaratan el cifrado (o no)
cr0x@server:~$ grep -m1 -oE 'aes|sha_ni|pclmulqdq' /proc/cpuinfo | sort -u
aes
pclmulqdq
Qué significa: AES y las instrucciones de multiplicación sin acarreo existen; AES-GCM puede acelerarse por hardware.
Decisión: Si faltan en hardware antiguo, espera un coste de CPU de cifrado notablemente mayor y planifica capacidad en consecuencia.
Tarea 5: Inspeccionar carga de I/O por dataset y pistas de latencia
cr0x@server:~$ zpool iostat -v pool 1 3
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
pool 2.10T 5.14T 120 980 18.3M 210M
mirror-0 1.05T 2.57T 60 490 9.2M 105M
nvme0n1 - - 30 250 4.6M 52.0M
nvme1n1 - - 30 240 4.6M 53.0M
mirror-1 1.05T 2.57T 60 490 9.1M 105M
nvme2n1 - - 30 245 4.5M 52.5M
nvme3n1 - - 30 245 4.6M 52.5M
-------------------------- ----- ----- ----- ----- ----- -----
Qué significa: Escrituras intensas. Esto te indica que la pool está realizando trabajo real; no quién es el culpable, pero dónde mirar a continuación.
Decisión: Si el ancho de banda es alto pero la latencia es mala, investiga escrituras sync, SLOG y saturación de CPU en lugar de suposiciones de “el cifrado es lento.”
Tarea 6: Comprobar salud del ARC y si la caché ayuda a cargas comprimidas/cifradas
cr0x@server:~$ arcstat 1 3
time read miss miss% dmis dm% pmis pm% mmis mm% size c
12:10:01 920 180 19 45 25 120 67 15 8 24.1G 31.8G
12:10:02 910 175 19 44 25 116 66 15 9 24.1G 31.8G
12:10:03 950 190 20 50 26 125 66 15 8 24.1G 31.8G
Qué significa: ~80% tasa de aciertos; ARC es útil. Si miss% es muy alto, estás yendo a disco y la latencia vendrá detrás.
Decisión: Si los misses dominan y el conjunto de trabajo es más grande que ARC, ajusta memoria, considera special vdev/L2ARC (con cuidado),
o rediseña el layout de datasets. No culpes al cifrado por faltas de caché.
Tarea 7: Verificar recordsize y decidir si coincide con patrones de acceso
cr0x@server:~$ zfs get -o name,property,value recordsize pool/app
NAME PROPERTY VALUE SOURCE
pool/app recordsize 128K local
Qué significa: 128K es un valor común por defecto. Genial para secuencial, no siempre para lecturas aleatorias pequeñas.
Decisión: Para cargas con muchos archivos pequeños o con lecturas aleatorias, considera recordsize más pequeño (p. ej., 16K o 32K) en un dataset creado para ese propósito.
Tarea 8: Para zvols, validar volblocksize (y no arrepentirte después)
cr0x@server:~$ zfs get -o name,property,value volblocksize pool/vm-01
NAME PROPERTY VALUE SOURCE
pool/vm-01 volblocksize 16K local
Qué significa: 16K a menudo es razonable para cargas VM; alinea con I/O del huésped cuando sea posible.
Decisión: Si volblocksize es enorme y la carga realiza escrituras aleatorias pequeñas, planifica una migración/recreación. No hay sysctl heroico que arregle un dimensionado de bloque incorrecto.
Tarea 9: Comprobar comportamiento sync y si estás pagando por durabilidad que no necesitas
cr0x@server:~$ zfs get -o name,property,value sync pool/app/db
NAME PROPERTY VALUE SOURCE
pool/app/db sync standard default
Qué significa: ZFS respeta las solicitudes sync de la aplicación. Las bases de datos pueden forzar escrituras sync; la latencia lo mostrará.
Decisión: Mantén sync=standard para corrección a menos que realmente entiendas el riesgo. Si necesitas baja latencia en sync, considera un SLOG en NVMe con protección contra pérdida de energía.
Tarea 10: Confirmar estado de claves de cifrado tras un arranque (fiabilidad operativa)
cr0x@server:~$ zfs get -o name,property,value keystatus -r pool/app
NAME PROPERTY VALUE
pool/app keystatus available
pool/app/db keystatus available
Qué significa: Las claves están cargadas ahora. Esto no garantiza que se cargarán automáticamente en el próximo arranque.
Decisión: Elige una estrategia de carga de claves (prompt vs archivo vs agente externo) que coincida con tu automatización de arranque y modelo de amenazas.
Tarea 11: Benchmarks del efecto de compresión sin engañarte
cr0x@server:~$ zfs create -o encryption=aes-256-gcm -o keyformat=passphrase -o keylocation=prompt -o compression=lz4 pool/bench-lz4
Enter passphrase:
Re-enter passphrase:
cr0x@server:~$ dd if=/dev/zero of=/pool/bench-lz4/zeros bs=1M count=2048 status=progress
2147483648 bytes (2.1 GB, 2.0 GiB) copied, 2.31 s, 930 MB/s
cr0x@server:~$ zfs get -o name,property,value compressratio used,logicalused pool/bench-lz4
NAME PROPERTY VALUE SOURCE
pool/bench-lz4 compressratio 200.00x -
pool/bench-lz4 used 12.5M -
pool/bench-lz4 logicalused 2.00G -
Qué significa: Los ceros se comprimen extremadamente bien; ves el “mejor caso”. También nota: el cifrado no impidió la compresión porque la compresión ocurrió primero.
Decisión: Usa también datos realistas (páginas de BD, logs, imágenes de VM). Hacer benchmarks solo con ceros es cómo creas una mentira bonita.
Tarea 12: Validar modo send/receive para replicación cifrada
cr0x@server:~$ zfs send -nvpw pool/app@daily | head
send from @daily estimated size is 58.2G
send from @daily to pool/app@daily incremental size 2.14G
Qué significa: -w indica un send en crudo (se preserva el stream cifrado). El receptor no necesita descifrar para almacenarlo.
Decisión: Usa sends en crudo para destinos de backup no confiables. Si el receptor necesita acceder a los datos, usa sends normales y gestiona claves en consecuencia.
Tarea 13: Comprobar ahorro de espacio por dataset y si estás “ganando”
cr0x@server:~$ zfs list -o name,used,logicalused,compressratio,encryption -r pool/app | head -n 6
NAME USED LOGICALUSED RATIO ENCRYPTION
pool/app 620G 1.02T 1.69x aes-256-gcm
pool/app/db 410G 710G 1.73x aes-256-gcm
pool/app/log 42G 120G 2.85x aes-256-gcm
pool/app/tmp 168G 170G 1.01x aes-256-gcm
Qué significa: Los logs se comprimen muy bien; tmp no. El cifrado es consistente.
Decisión: Considera compression=off (o lz4) para tmp si la CPU está limitada, y mantiene compresión más fuerte donde compense.
Tarea 14: Inspeccionar salud de la pool y estado de scrub (porque los problemas de rendimiento aman pools enfermas)
cr0x@server:~$ zpool status -v pool
pool: pool
state: ONLINE
scan: scrub repaired 0B in 03:12:44 with 0 errors on Sun Dec 15 03:30:12 2025
config:
NAME STATE READ WRITE CKSUM
pool ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
nvme2n1 ONLINE 0 0 0
nvme3n1 ONLINE 0 0 0
errors: No known data errors
Qué significa: Pool saludable, scrub reciente limpio. Buena línea base.
Decisión: Si ves errores o resilvering, deja de “tunar cifrado/compresión” y atiende primero la salud del hardware/pool.
Tarea 15: Identificar si la carga es IOPS aleatorias o ancho de banda secuencial
cr0x@server:~$ iostat -x 1 3
avg-cpu: %user %nice %system %iowait %steal %idle
35.2 0.0 9.8 1.2 0.0 53.8
Device r/s w/s rkB/s wkB/s await svctm %util
nvme0n1 30.0 250.0 4700.0 52000.0 1.5 0.4 11.2
nvme1n1 30.0 240.0 4600.0 53000.0 1.6 0.4 11.0
Qué significa: Bajo iowait y baja utilización de dispositivo sugiere que el almacenamiento no está saturado. La CPU está haciendo trabajo real.
Decisión: Si estás lento pero los discos no están ocupados, sospecha de CPU (nivel de compresión, sobrecarga de cifrado, checksumming) o del comportamiento de la aplicación (escrituras sync).
Guion de diagnóstico rápido: encuentra el cuello de botella en minutos
Cuando el rendimiento cae tras habilitar cifrado o cambiar compresión, no hagas el baile de “ajusta tres perillas y a ver.”
Haz esto en orden. Para cuando encuentres la restricción, detente.
Primero: ¿La pool está sana y no ocupada en trabajo de recuperación?
- Ejecuta
zpool status. Busca resilvering, scrubs, errores de checksum. - Si hay un resilver o scrub en curso, acepta rendimiento degradado o reprograma. La sintonía no arreglará la física.
Segundo: ¿Estás limitado por E/S o por CPU?
- Ejecuta
zpool iostat -v 1yiostat -x 1. - Si los dispositivos están en alto
%utilyawaitsube: limitado por E/S. - Si los dispositivos están tranquilos pero la CPU está al máximo: limitado por CPU (a menudo compresión/cifrado/checksum, o sobrecarga de la app).
Tercero: ¿La latencia de escrituras sync es la villana?
- Revisa la propiedad
syncdel dataset. - Comprueba si la carga es una base de datos o VM que hace patrones fsync-intensos.
- Si las escrituras sync dominan y no tienes un SLOG rápido, el rendimiento será “aceptable” hasta que no lo sea.
Cuarto: ¿Tus datos se comprimen? ¿O solo estás quemando CPU?
- Revisa
compressratioylogicalusedvsused. - Si la ratio está ~1.00x en datasets calientes y la CPU está ajustada, elige lz4 o desactiva la compresión allí.
Quinto: ¿El dimensionado de bloques es incorrecto para la carga?
- Revisa
recordsizepara datasets de archivos. - Revisa
volblocksizepara zvols. - El desajuste causa amplificación, que parece “sobrecarga de cifrado” porque todo se vuelve más lento a la vez.
Tres micro-historias corporativas desde las trincheras
1) Incidente causado por una suposición equivocada: “El cifrado rompió la compresión”
Una compañía SaaS mediana desplegó cifrado nativo de ZFS para satisfacer un cuestionario de cliente. El ingeniero que hizo el cambio
activó cifrado en nuevos datasets y dejó la compresión tal cual (zstd). Una semana después, finanzas notó que el crecimiento de almacenamiento se ralentizaba.
Todos se relajaron. Luego llegaron quejas de latencia: llamadas API agotando tiempo, jobs en background retrasándose y una narrativa de “ZFS está lento ahora”
tomó el canal de incidentes semanal.
La suposición equivocada fue sutil: el equipo creía que el cifrado impediría la compresión y por tanto aumentaría la E/S. En su cabeza,
el almacenamiento se volvería más ocupado, así que se concentraron en la pool: layout de vdev, profundidad de cola, “tal vez necesitamos más NVMe.” Mientras tanto, las gráficas de pool
se veían aburridas—baja utilización, sin saturación evidente.
La solución vino de alguien que hizo una pregunta poco a la moda: “¿La CPU está haciendo algo diferente?” Revisaron
compressratio y vieron que la compresión seguía siendo efectiva. También notaron que los nodos de aplicación se habían quedado sin CPU porque un despliegue separado
aumentó la carga de TLS en los mismos hosts que ejecutaban servicios de almacenamiento. El cambio de cifrado fue la straw, no el truck.
Movieron los servicios de almacenamiento a hosts con más margen por núcleo y ajustaron compresión de zstd a lz4 en el dataset aleatorio más ocupado.
La latencia se estabilizó. El informe de incidente fue directo: el cifrado no mató la compresión; la mala planificación de capacidad mató la planificación de capacidad.
2) Optimización que salió mal: “zstd-19 en todas partes”
Un equipo de TI empresarial migró desde un array legado a ZFS y adoró los ahorros por compresión. Alguien leyó que zstd tiene grandes ratios
y decidió estandarizar un nivel alto en todos los datasets, incluidos almacenamiento de VM y una caché de build muy ocupada.
Los resultados inmediatos parecían buenos en el dashboard: la ratio mejoró y las gráficas de crecimiento de almacenamiento hicieron que todos parecieran inteligentes.
Luego el helpdesk empezó a recibir tickets de “VM está lenta” difíciles de reproducir. La granja de builds empezó a incumplir SLAs por pequeñas cantidades—suficiente para molestar equipos sin desencadenar un gran incidente.
El contragolpe fue clásico: mejoraron eficiencia de espacio a costa de latencia por I/O. Niveles altos de compresión aumentan el tiempo de CPU
por bloque. En cargas secuenciales puedes ocultarlo con throughput. En I/O aleatorio no puedes. Cada I/O ahora llevaba un pequeño impuesto de CPU,
y la suma de pequeños impuestos es cómo se crea jitter sistémico.
Revirtieron datasets de VM a lz4, mantuvieron zstd (moderado) para archivos de logs, y aprendieron la dura regla: la compresión es una característica de la carga,
no una religión global.
3) La práctica aburrida pero correcta que salvó el día: carga de claves y disciplina en replicación
Una empresa con múltiples sitios usaba datasets cifrados y los replicaba cada noche. Su práctica “aburrida” fue doble:
(1) las claves se gestionaban con una jerarquía consistente, y (2) la replicación se probaba trimestralmente con un drill de restauración. Sin heroísmos, solo repetición.
Un nodo de almacenamiento falló duro—a nivel de hardware, sin historia romántica. Promovieron la réplica, importaron la pool y levantaron servicios.
La restauración no fue rápida, pero sí predecible. Lo más importante: no se convirtió en un fiasco de gestión de claves.
El detalle salvador: usaron sends en crudo para copias offsite y aseguraron que el sitio de recuperación tuviera las claves necesarias (y el proceso
para cargarlas) documentado y ensayado. El receptor no necesitó descifrar el stream en crudo para almacenarlo, lo que redujo las “piezas móviles”
en medio de un evento estresante.
El postmortem no tuvo fuegos artificiales. Fue casi decepcionante. Así luce el éxito en producción: recuperación sin eventos y sin improvisación cripto nocturna.
Errores comunes: síntomas → causa raíz → solución
Estos son patrones recurrentes. Si ves el síntoma, no lo debatas en Slack. Ve directo a la causa raíz y arregla.
1) Síntoma: ratio de compresión cerca de 1.00x, CPU elevada
Causa raíz: Los datos ya están comprimidos o cifrados antes de que ZFS los vea (archivos multimedia, backups cifrados, cifrado a nivel de app).
Solución: Usa compression=lz4 o compression=off en ese dataset. Mantén la compresión donde realmente compense.
2) Síntoma: rendimiento cayó tras habilitar cifrado, pero los discos no están ocupados
Causa raíz: Limitación por CPU: cifrado + compresión + overhead de checksum ahora compiten con cargas de aplicación.
Solución: Reduce nivel de compresión (zstd → lz4), añade margen de CPU, aísla servicios de almacenamiento o escala horizontalmente. Prueba con iostat y estadísticas ARC.
3) Síntoma: picos de latencia en escrituras de base de datos, especialmente en peak
Causa raíz: escrituras sync (fsync) forzando comportamiento ZIL; no hay SLOG rápido con protección contra pérdida de energía, o el SLOG está mal dimensionado/funcionando mal.
Solución: Mantén sync=standard; añade un SLOG adecuado; valida con pruebas de carga. No pongas sync=disabled como “arreglo de rendimiento” a menos que disfrutes explicando pérdida de datos.
4) Síntoma: almacenamiento de VM se siente “aleatoriamente lento”, I/O pequeño es terrible
Causa raíz: volblocksize incorrecto causando amplificación de escrituras; a veces combinado con niveles altos de compresión.
Solución: Recrea zvol con volblocksize correcto (a menudo 8K/16K dependiendo de la carga) y migra datos; usa lz4 para zvols de VM salvo que hayas medido otra cosa.
5) Síntoma: el sistema arranca, pero los datasets no montan; servicios fallan “misteriosamente”
Causa raíz: Datasets cifrados con claves no cargadas al arranque; keylocation=prompt en sistemas sin cabeza; falta de automatización.
Solución: Implementa un mecanismo de carga de claves consistente con tu modelo de amenazas (archivo con permisos restringidos, agente externo, prompt manual con runbooks) y prueba la recuperación tras reboot.
6) Síntoma: replicación lenta, CPU en sender o receiver se dispara
Causa raíz: Los sends no crudos requieren descifrado/recifrado o recompresión; además la compresión intensa en datasets con alto ritmo de cambio puede añadir coste de CPU durante el send.
Solución: Usa sends en crudo para backups cifrados cuando el receptor no necesite texto claro. Considera ajustar el nivel de compresión en datasets con tasas de cambio agresivas.
Listas de verificación / plan paso a paso
Checklist A: Configurar un dataset cifrado + comprimido (valores por defecto seguros para producción)
- Crea un dataset dedicado por clase de carga (db, logs, media, vm, backups).
- Habilita cifrado al crear el dataset (diseña la herencia de claves intencionalmente).
- Empieza con
compression=lz4a menos que tengas una razón medida para zstd. - Configura
recordsizepara ajustar la carga (grande para secuencial; más pequeño para lecturas aleatorias). - Para zvols, elige cuidadosamente
volblocksize(y documenta la elección). - Decide la política
syncy si necesitas un SLOG. - Prueba de reinicio: ¿el sistema puede importar la pool y cargar claves de forma predecible?
Checklist B: Cambiar compresión en un dataset existente sin drama
- Mide la línea base: latencia, CPU,
compressratioe iostat de la pool bajo carga representativa. - Cambia la propiedad de compresión (se aplica a nuevas escrituras; los bloques antiguos permanecen).
- Observa bajo carga real; no confíes solo en microbenchmarks.
- Si necesitas recomprimir datos existentes, planea una reescritura (send/receive a un nuevo dataset o copy/rsync).
- Reevalúa luego de una semana de carga típica; las pruebas cortas omiten la entropía del mundo real.
Checklist C: Higiene operativa de cifrado (la parte que evita “no monta”)
- Estandariza keyformat y keylocation entre entornos cuando sea posible.
- Documenta pasos de carga de claves y quién tiene acceso.
- Prueba recuperación: importa pool, carga claves, monta datasets, arranca servicios.
- Valida modo de replicación (raw vs no-raw) que coincida con objetivos de seguridad.
- Audita herencia: asegúrate de que datasets hijos sensibles no hayan quedado sin cifrar por accidente.
Preguntas frecuentes
1) ¿ZFS cifra antes de comprimir?
Para el cifrado nativo de ZFS, ZFS comprime primero y luego cifra. Por eso la compresión sigue funcionando en datasets cifrados.
2) ¿Por qué la compresión es inefectiva en algunos datasets cifrados?
Usualmente porque los datos ya estaban cifrados o comprimidos antes de que ZFS los viera (cifrado a nivel de app, formatos multimedia,
backups comprimidos). ZFS no puede comprimir aleatoriedad.
3) ¿Debo usar zstd o lz4 con datasets cifrados?
Por defecto usa lz4 para datasets calientes y sensibles a la latencia. Usa zstd cuando hayas medido ahorros significativos de espacio y tengas presupuesto de CPU.
El cifrado no cambia esa regla; solo añade otro consumidor de CPU.
4) Si cambio la compresión, ¿ZFS recomprime los datos existentes?
No. La propiedad afecta bloques recién escritos. Para recomprimir datos existentes necesitas reescribirlos (copiarlos o send/receive a un nuevo dataset).
5) ¿El cifrado perjudica la caché ARC?
El cifrado cambia lo que ZFS debe hacer en lecturas/escrituras, pero la efectividad del ARC depende principalmente de patrones de acceso y tamaño del conjunto de trabajo.
Si fallas mucho en ARC, lo notarás independientemente del cifrado.
6) ¿Es raw send la elección correcta para backups cifrados?
Si el destino del backup no necesita acceder al texto claro, raw send es excelente: preserva el cifrado y evita exponer claves en el receptor.
Si necesitas restoraciones que monten y lean datos en el receptor, planifica la gestión de claves en consecuencia.
7) ¿Puedo habilitar cifrado en un dataset existente no cifrado?
No in-place en el sentido que la gente espera. En la práctica, creas un nuevo dataset cifrado y migras datos (send/receive o copia),
luego haces el cutover.
8) ¿Cuál es la perilla de rendimiento más grande además del algoritmo de compresión?
Dimensionado de bloques: recordsize para datasets de archivos y volblocksize para zvols. Un dimensionado incorrecto crea amplificación que ningún algoritmo te salvará.
9) ¿Debo poner sync=disabled para hacer rápidos los datasets cifrados?
No, no como medida general. Cambia durabilidad por velocidad y convierte ciertos fallos en pérdida de datos. Si la latencia de sync es el problema,
arréglalo con un SLOG adecuado o ajustando la aplicación.
10) ¿Cómo sé si la sobrecarga de cifrado es mi cuello de botella?
Si los discos no están saturados, ARC no es el problema y la CPU se dispara durante operaciones intensivas de I/O, el cifrado (junto con compresión/checksums)
puede estar contribuyendo. Confírmalo con métricas de CPU del sistema y comparando comportamiento con lz4 vs compresión más pesada.
Conclusión: próximos pasos prácticos
El “orden que marca el rendimiento” es simple: reduce bytes mientras aún son compresibles, luego cifra. El cifrado nativo de ZFS
ya hace esto. Tu trabajo no es pelear contra eso; tu trabajo es asegurarte de que el resto del sistema—margen de CPU, dimensionado de bloques, política sync
y operaciones de claves—no sabotee la ganancia.
Próximos pasos que puedes ejecutar esta semana
- Haz inventario de datasets: cifrado on/off, algoritmo de compresión, compressratio, recordsize/volblocksize.
- Identifica datasets calientes con compressratio ~1.00x y decide si la compresión debería ser lz4 o off.
- Ejecuta el guion de diagnóstico rápido durante la carga pico una vez, registra resultados y guárdalos como baseline.
- Elige una clase de carga (VMs o bases de datos) y valida el dimensionado de bloques; planea migraciones para los peores casos.
- Prueba un reinicio + carga de claves + arranque de servicios en una ventana controlada. Si no es aburrido, no está hecho.