A la gente de ZFS le encantan las reglas prácticas. Dan seguridad, como etiquetar un panel eléctrico o fingir que “arreglarás la disposición de datasets más tarde”. La más famosa es la “regla del 80% de ZFS”: no dejes que un pool pase del 80% de uso, o el rendimiento caerá en picado y llegarán los problemas. En producción se repite como si fuera física.
La verdad es mejor—y más útil. La línea del 80% no es ni superstición ni ley universal. Es un límite burdo para un puñado de mecanismos reales: asignación de metaslabs, fragmentación, comportamiento copy-on-write, crecimiento de metadata y la matemática brutal de “necesito espacio libre contiguo-ish para escribir de forma eficiente”. La verdadera zona peligrosa no es un número único; es cuando tu espacio libre restante deja de ser espacio libre utilizable para tu carga de trabajo.
Qué significa realmente la “regla del 80%”
La “regla del 80%” es una abreviatura de: la asignación en ZFS se vuelve más difícil a medida que el pool se llena, y una vez que se vuelve lo bastante difícil, todo lo que te importa (latencia, rendimiento de escritura, tiempos de resilver, borrado de snapshots) puede degradarse de forma no lineal.
Ésa es la clave: no lineal. ZFS no se frena de forma gradual y educada como un ascensor con demasiadas personas. Es más parecido a intentar aparcar en una ciudad cuando solo quedan los huecos raros, pequeños y medio bloqueados. Aún puedes aparcar, pero tu tiempo medio para “encontrar un sitio” aumenta mucho.
Dos chistes, como prometí, porque la gente de almacenamiento sobrevive con humor y cafeína:
Broma #1: La regla del 80% es como una dieta: todos están de acuerdo, y luego llega el viernes.
Broma #2: Si quieres aprender lo que significa realmente “copy-on-write”, llena un pool al 95% y observa cómo tu aplicación reescribe su currículum.
¿Entonces el 80% es correcto?
A veces. Para muchas cargas mixtas, “mantenerlo por debajo de ~80%” es conservador y te mantiene fuera de problemas. Pero no es un umbral mágico. Algunos pools funcionan felices al 85–90% porque la carga es mayormente lecturas secuenciales y escrituras secuenciales grandes, la fragmentación está controlada y hay margen en otros lugares (vdev especial rápido para metadata, RAM adecuada, recordsize sensato). Otros pools se vuelven miserables al 70–75% porque ejecutan escrituras aleatorias con bloques pequeños, retención intensiva de snapshots y muchos metaslabs pequeños por vdevs estrechos.
El objetivo no es adorar al 80%. El objetivo es entender qué hace que tu pool esté “efectivamente lleno” antes de que el número “used” llegue al 100%.
Qué cambia realmente a medida que el espacio libre disminuye
A alto nivel, ZFS necesita encontrar bloques libres para satisfacer asignaciones. A medida que el pool se llena, los bloques libres restantes están más fragmentados y distribuidos de forma desigual entre metaslabs. Las decisiones de asignación se vuelven más costosas y menos óptimas, lo que puede traducirse en:
- Mayor amplificación de escritura (más I/O por unidad de escritura lógica).
- Escrituras más dispersas (peor para HDD, aún no ideal para SSD).
- Tiempos de sincronización de transaction group (TXG) más largos (visible como picos de latencia).
- Borrados más lentos (eliminar snapshots puede sentirse como empujar un piano cuesta arriba).
- Tiempos de resilver y scrub más largos, especialmente cuando el pool está caliente y fragmentado.
Breve historia y hechos que explican la tradición
Las reglas prácticas de almacenamiento no aparecen por arte de magia; surgen después de que suficientes personas se quemen en el mismo sitio. Aquí hay hechos concretos y puntos de contexto que hacen que la regla del 80% tenga sentido—sin tratarla como escritura sagrada:
- ZFS fue diseñado para copy-on-write desde el primer día. Eso significa que las sobrescrituras se convierten en “asignar nuevo, luego actualizar punteros”, lo que necesita espacio libre incluso para modificar datos existentes.
- El asignador de metaslabs favorece regiones de baja fragmentación. A medida que el pool se llena, los metaslabs “buenos” se agotan y el asignador trata cada vez más con restos.
- Las primeras implementaciones de ZFS usaban mucho HDD. Los HDD castigan las escrituras aleatorias y los seeks; el “acantilado” era evidente. Los SSD suavizan el dolor pero no eliminan la sobrecarga de asignación, ni eliminan la agitación de metadata.
- RAIDZ cambia las matemáticas. RAIDZ tiene paridad y comportamiento de stripe variable. Las escrituras pequeñas aleatorias pueden convertirse en ciclos read-modify-write, y la fragmentación del espacio libre empeora la situación.
- Los snapshots son baratos hasta que no lo son. Tomar snapshots es rápido; retenerlos y borrarlos a escala puede convertir el “espacio libre” en una responsabilidad complicada.
- 128K se volvió un recordsize cultural por defecto. Ese valor es genial para muchas cargas secuenciales, pero interactúa mal con escrituras aleatorias pequeñas y churn de snapshots si no ajustas por dataset.
- Los errores de ashift son para siempre (para ese vdev). Suposiciones de alineación de sectores pueden desperdiciar espacio y capacidad I/O, reduciendo tu margen práctico de espacio libre.
- Los special vdev cambiaron la economía de la metadata. Poner metadata (y opcionalmente bloques pequeños) en medios rápidos puede mantener los pools utilizables con mayor uso—si se dimensiona correctamente. Si no, puede convertirse en el nuevo cuello de botella.
- “df” y “zfs list” cuentan verdades diferentes. Los sistemas de archivos tradicionales permiten fingir; ZFS expone más realidad: snapshots, reservas y referenced vs used importan.
La verdadera zona peligrosa: cuando el espacio libre deja de ser usable
Si quieres una frase operativa para reemplazar “nunca exceder el 80%”, usa ésta:
La zona peligrosa comienza cuando el espacio libre restante del pool no puede satisfacer tu patrón de asignación de forma eficiente, especialmente bajo picos de escritura y retención de snapshots.
“Used” no es lo mismo que “estrés”
Dos pools pueden estar al 85% usados y comportarse de forma completamente diferente. El estrés depende de:
- Fragmentación del espacio libre: ¿Tienes bloques libres en extensiones grandes, o un montón de confeti?
- Tamaño y localidad de las escrituras: ¿Escribes bloques grandes secuenciales o actualizaciones aleatorias de 4K?
- Geometría de vdev: Los mirrors se comportan diferente que RAIDZ; más vdevs significa más “carriles” de asignación.
- Churn de snapshots: Snapshots frecuentes + sobrescrituras significa que tus liberaciones se retrasan y tu conjunto vivo crece en “copias sombra”.
- Carga de metadata: Millones de archivos pequeños, atributos extendidos, ACLs y tablas de deduplicación crean I/O de metadata que no aparece como “grandes escrituras”.
Una definición práctica de “efectivamente lleno”
En producción, llamo a un pool “efectivamente lleno” cuando cualquiera de estas es cierta:
- La latencia de escritura de la aplicación se vuelve impredecible (p99 y p999 se disparan), aunque los discos no estén saturados en tráfico bruto.
- El tiempo de sincronización de TXG crece y se mantiene alto bajo carga de escritura sostenida.
- Los borrados de snapshots se estancan o tardan horas más de lo habitual.
- Las estimaciones de resilver se vuelven cómicas, especialmente durante horario laboral.
- Empiezas a “arreglar” el rendimiento reiniciando, lo cual es señal de que has agotado ideas y entraste en negación.
Por qué el acantilado se siente repentino
El acantilado es un bucle de realimentación:
- El pool se llena y se fragmenta.
- Las asignaciones se vuelven más dispersas; las escrituras tardan más.
- Las escrituras más largas mantienen los TXG abiertos más tiempo; se acumula más dato “sucio”.
- Más datos sucios significan más trabajo de sincronización; la latencia de sync sube.
- Las aplicaciones ven latencia y reintentan o encolan; la carga aumenta.
No es que ZFS “entre en pánico al 81%”. Es que tu carga cruza el punto donde las decisiones del asignador dejan de ser baratas.
Patrones de carga que chocan primero
VM y bases de datos con escrituras aleatorias en RAIDZ
Este es el clásico. Muchas actualizaciones de 8K–16K, escrituras sync y churn por sobrescritura. Si es RAIDZ, las escrituras pequeñas pueden disparar read-modify-write. Añade snapshots y has construido una máquina que fabrica fragmentación.
Compartidos de archivos con muchos snapshots, renombrados frecuentes y archivos pequeños
Churn de metadata y liberaciones retrasadas. Los usuarios no notan las primeras 50.000 snapshots porque las lecturas aún parecen fluidas. Luego los borrados, renombrados y operaciones de directorio empiezan a retrasarse, y todos culpan “a la red”.
Backups y almacenamiento tipo objeto con flujos secuenciales grandes
Estos pueden tolerar mayor utilización si la carga es mayormente append y no reescribes en el lugar. Pero cuidado: la expiración por retención (borrados masivos) puede ser su propia tormenta.
Contenedores y pipelines de CI
Muchos archivos pequeños, vidas cortas, capas overlayfs, caches de build y eventos de “borrar todo”. ZFS puede funcionar muy bien aquí, pero los pools casi llenos convierten el constante crear/borrar en dolor para el asignador.
Contabilidad de espacio: por qué “df” miente y a ZFS no le importa
ZFS enfada a la gente porque se niega a mantener la ilusión simple. Puedes tener 2 TB “libres” en una vista y quedarte sin espacio en otra. Normalmente nadie miente; estás haciendo preguntas diferentes.
Términos clave que sí importan
- USED: Espacio consumido por el dataset y sus descendientes, incluyendo snapshots (dependiendo de dónde mires).
- REFER: Espacio referenciado exclusivamente por este dataset (sin contar snapshots).
- AVAIL: Espacio disponible considerando cuotas/reservas y el espacio libre del pool.
- RECORDED vs actual: Compresión y copias cambian lo que significa “lógico” vs “físico”.
Por qué los snapshots hacen que el espacio libre parezca embrujado
Con snapshots, los borrados no liberan bloques necesariamente. Las sobrescrituras asignan nuevos bloques; los bloques antiguos siguen referenciados por snapshots. Así que tu reflejo de “borrar el archivo grande” no te compra tanto espacio como en ext4. El pool puede parecer que tiene espacio libre, pero el asignador aún se ve forzado a lugares incómodos porque el espacio libre que tiene está fragmentado o distribuido de forma desigual.
Tres mini-historias del mundo corporativo (desde el frente)
1) Incidente causado por una suposición errónea: “80% es seguro, entonces 79% es seguro”
Una empresa mediana operaba un clúster NFS respaldado por ZFS que servía directorios personales y algunos build farms. El equipo de almacenamiento tenía un dashboard con una agradable banda verde/amarilla/roja: verde por debajo del 80%, amarillo por encima del 80%, rojo por encima del 90%. Parecía profesional y a todos les gustó porque reducía las discusiones a un color.
Luego el pool alcanzó 79% usado. Seguía en verde. Esa semana, el churn de artefactos del build farm se disparó por el lanzamiento de un producto, y el compartido de directorios personales tenía una política trimestral de snapshots por cumplimiento. Nada exótico: muchos archivos pequeños creados y sobrescritos, más snapshots tomados cada hora.
El martes, la mesa de ayuda empezó a ver fallos “aleatorios” en builds. El miércoles, los clientes NFS comenzaron a quedarse colgados en operaciones de metadata: llamadas stat(), listados de directorios, renombrados de archivos. El equipo de red recibió la primera llamada porque “NFS está lento”, y hicieron lo que hacen los equipos de red: demostraron que la red era inocente.
El jueves, el equipo de almacenamiento encontró la verdad: el pool no estaba “seguro” al 79%. Estaba efectivamente lleno para esa carga. Los metaslabs se habían fragmentado lo suficiente como para que las búsquedas del asignador y las escrituras dispersas martillaran la latencia. La línea del 80% no era el acantilado; era una advertencia popular. Sus dashboards estaban en verde mientras los usuarios ardían en problemas.
La solución no fue magia. Liberaron espacio expirando snapshots antiguos, movieron artefactos de build a un dataset con recordsize y compresión ajustados y—lo más importante—cambiaron las alertas para rastrear no solo el porcentaje usado sino también la latencia de escritura, el comportamiento de sincronización de TXG y el crecimiento del espacio de snapshots. La nueva banda “verde” se basó en comportamiento, no solo en un número.
2) Optimización que se volvió en su contra: “Subiremos el recordsize y comprimiremos todo”
Otra empresa usaba ZFS para virtualización. Tenían SSDs, mucha RAM y confianza—siempre un ingrediente peligroso. Alguien notó que el recordsize por defecto era 128K y decidió “más grande es mejor”, subiéndolo a 1M en el dataset de VM. También activaron compresión agresiva en todas partes porque quedaba genial en el informe trimestral de almacenamiento.
Al principio, todo fue bien. Las copias de seguridad se hicieron más pequeñas. El número “used” del pool parecía más saludable. Luego, conforme la utilización subió, la latencia de escrituras aleatorias empezó a dispararse. Las cargas de VM que hacían pequeñas actualizaciones ahora tocaban registros enormes, amplificando escrituras y trabajo de metadata. La compresión añadió sobrecarga de CPU justo cuando el sistema necesitaba tomar decisiones de asignación rápidas y mantener el ritmo de los sync.
Lo peor: su monitorización mayormente seguía throughput y porcentaje usado. El throughput parecía aceptable. El porcentaje usado estaba por debajo del 80%. Mientras tanto, los hipervisores estaban expirando en operaciones de almacenamiento durante las horas pico. La experiencia para el negocio era “la plataforma es inestable”, que es el tipo más caro de bug de rendimiento.
Revirtieron: los discos de VM se movieron a datasets con recordsize más sensato (y, para zvols, volblocksize apropiado), la compresión se mantuvo pero ajustada al margen de CPU, y separaron cargas por dataset en lugar de una única configuración para todo. La lección no fue “la compresión es mala” o “recordsize grande es malo”. La lección fue: optimizaciones que mejoran los informes de capacidad pueden perjudicar el comportamiento de asignación cerca de pools llenos.
3) Práctica aburrida pero correcta que salvó el día: reservas, margen y limpieza ensayada
Una firma de servicios financieros usaba ZFS para una canalización de análisis de logs y servicios de archivos internos. Nada glamuroso: muchas escrituras por append, compactaciones periódicas y snapshots para rollback rápido. El responsable de almacenamiento era alérgico a las recuperaciones heroicas, así que diseñó un plan soso: mantener 20–25% de margen, aplicar cuotas y crear un dataset “romper vidrio” con espacio reservado para emergencias.
No fue popular. A los equipos no les gustan las cuotas como a los gatos no les gustan los baños. Pero aceptaron tras algunas reuniones y explicaciones calmadas sobre copy-on-write y retención de snapshots. También crearon un runbook de limpieza: qué snapshots expirar primero, qué datasets podían purgarse y qué debía preservarse. Lo probaron trimestralmente como un simulacro de incendios.
Un año, un bucle de logging desbocado empezó a generar datos masivos. En un entorno menos disciplinado, el pool habría llegado al 95% y se habría convertido en un carnaval de latencias. Aquí, las alertas saltaron temprano (tendencia de espacio + latencia), las cuotas contuvieron el radio de la explosión y el espacio reservado “romper vidrio” aseguró que los servicios críticos aún pudieran escribir mientras el equipo limpiaba. Ejecutaron el runbook sin improvisar: expirar snapshots no críticos, pausar la canalización ofensiva, scrubrear para comprobar salud y luego reanudar.
No pasó nada heroico. Ese es el punto. La práctica aburrida no dio una gran historia para la reunión general, pero evitó una gran historia en redes sociales.
Tareas prácticas: comandos, salidas y cómo leerlas
Debajo están las tareas prácticas que realmente uso cuando un pool está “misteriosamente lento” o se acerca a la zona peligrosa. Los comandos se muestran como si se ejecutaran en un host Linux típico con OpenZFS. Las interpretaciones están incluidas—porque la salida cruda sin significado es solo decorativa.
Tarea 1: Comprobar capacidad y salud del pool (la base)
cr0x@server:~$ zpool list
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 54.5T 44.1T 10.4T - - 38% 80% 1.00x ONLINE -
Interpretación: CAP al 80% no es automáticamente malo, pero es el momento de empezar a prestar atención. FRAG es un indicador, no un veredicto. Un FRAG de 38% puede estar bien o ser doloroso dependiendo de la carga.
Tarea 2: Obtener el layout detallado de vdev y detectar un cuello de botella obvio
cr0x@server:~$ zpool status -v tank
pool: tank
state: ONLINE
scan: scrub repaired 0B in 07:12:33 with 0 errors on Sun Dec 22 02:10:14 2025
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sda ONLINE 0 0 0
sdb ONLINE 0 0 0
sdc ONLINE 0 0 0
sdd ONLINE 0 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
errors: No known data errors
Interpretación: La salud es buena. Esto no significa que el rendimiento sea bueno. Si un único disco tuviera errores READ/WRITE altos o se desconectara intermitentemente, lo verías aquí—los pools casi llenos amplifican el dolor de hardware marginal.
Tarea 3: Identificar qué consume espacio (datasets principales)
cr0x@server:~$ zfs list -o name,used,refer,avail,compressratio,mountpoint -S used | head -n 12
NAME USED REFER AVAIL COMPRESSRATIO MOUNTPOINT
tank 44.1T 128K 10.4T 1.35x /tank
tank/vm 18.7T 18.2T 10.4T 1.12x /tank/vm
tank/home 12.4T 9.1T 10.4T 1.61x /tank/home
tank/backup 9.8T 9.7T 10.4T 1.05x /tank/backup
tank/containers 2.1T 1.9T 10.4T 1.48x /tank/containers
Interpretación: USED incluye snapshots dependiendo de la jerarquía del dataset; REFER es dato en vivo. Una gran diferencia entre USED y REFER suele significar que los snapshots retienen muchos bloques antiguos.
Tarea 4: Cuantificar el impacto de los snapshots
cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -S used | head -n 10
NAME USED REFER CREATION
tank/home@hourly-2025-12-24-2300 420G 9.0T Wed Dec 24 23:00 2025
tank/home@hourly-2025-12-24-2200 390G 8.9T Wed Dec 24 22:00 2025
tank/vm@daily-2025-12-24 210G 18.1T Wed Dec 24 01:00 2025
tank/home@hourly-2025-12-24-2100 180G 8.8T Wed Dec 24 21:00 2025
Interpretación: USED del snapshot es el espacio exclusivo retenido por ese snapshot. Si unos pocos snapshots son enormes, probablemente tienes mucho churn por sobrescritura (VMs, bases de datos, caches de CI) en ese dataset.
Tarea 5: Detectar reservas y cuotas que hacen extraña la “AVAIL”
cr0x@server:~$ zfs get -o name,property,value,source quota,refquota,reservation,refreservation tank/home tank/vm
NAME PROPERTY VALUE SOURCE
tank/home quota none default
tank/home refquota none default
tank/home reservation none default
tank/home refreservation none default
tank/vm quota 20T local
tank/vm refquota none default
tank/vm reservation 2T local
tank/vm refreservation none default
Interpretación: Las reservas reservan espacio incluso cuando el pool está justo. Genial para proteger cargas críticas, confuso si olvidaste que las pusiste.
Tarea 6: Comprobar fragmentación del pool y clases de asignación
cr0x@server:~$ zdb -L -bbbs tank | head -n 30
Traversing all blocks to verify metadata...
Metaslabs:
tank: 256 metaslabs, 38% fragmented, 80% capacity
...
Summary:
blocks = 123456789
alloc = 44.1T
free = 10.4T
Interpretación: La fragmentación aquí es a nivel de pool y gruesa, pero se correlaciona con el dolor del asignador. FRAG en ascenso más latencia de escritura en ascenso es tu sirena de “zona peligrosa”.
Tarea 7: Inspeccionar propiedades del dataset que influyen en comportamiento cerca de lleno
cr0x@server:~$ zfs get -o name,property,value,source recordsize,compression,atime,sync,logbias,primarycache,secondarycache tank/vm
NAME PROPERTY VALUE SOURCE
tank/vm recordsize 128K default
tank/vm compression lz4 local
tank/vm atime off local
tank/vm sync standard default
tank/vm logbias latency local
tank/vm primarycache all default
tank/vm secondarycache all default
Interpretación: Para datasets de VM, recordsize y comportamiento de sync importan. Los pools cerca del lleno castigan las escrituras aleatorias sync; logbias y un SLOG correctamente desplegado pueden ayudar, pero no arreglan la fragmentación.
Tarea 8: Comprobar volblocksize de zvol (trampa común en VM)
cr0x@server:~$ zfs get -o name,property,value,source volblocksize tank/vm/zvol0
NAME PROPERTY VALUE SOURCE
tank/vm/zvol0 volblocksize 8K local
Interpretación: Un volblocksize razonable puede reducir la amplificación de escritura. Un desajuste (como 128K para una carga de 8K, o 4K para secuenciales grandes) puede hacer que el “casi lleno” se sienta peor antes.
Tarea 9: Monitorizar latencia en tiempo real e IOPS por vdev
cr0x@server:~$ zpool iostat -v tank 1 5
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 44.1T 10.4T 820 1600 110M 95.2M
raidz2-0 44.1T 10.4T 820 1600 110M 95.2M
sda - - 120 250 17.0M 15.8M
sdb - - 118 260 16.5M 16.2M
sdc - - 130 245 17.2M 15.4M
sdd - - 112 270 16.1M 16.8M
sde - - 160 300 22.0M 18.5M
sdf - - 180 275 21.2M 17.0M
Interpretación: Busca un disco fuera de rango haciendo menos trabajo (o mostrando errores en otra parte). También nota: el ancho de banda puede parecer bien mientras la latencia no lo está. Usa iostat y métricas de la aplicación, no solo throughput.
Tarea 10: Comprobar salud del ARC y si estás cacheando lo que importa
cr0x@server:~$ arcstat 1 3
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
12:00:01 890 120 13 10 1 40 4 70 8 96G 112G
12:00:02 910 140 15 15 2 50 5 75 8 96G 112G
12:00:03 870 110 12 8 1 38 4 64 7 96G 112G
Interpretación: Los misses de ARC no son automáticamente malos, pero si los misses de metadata suben durante cargas intensas en directorios, los pools cerca del lleno sufren más porque cada operación de metadata dispara más I/O disperso.
Tarea 11: Ver si las escrituras sync dominan (y si un SLOG ayuda)
cr0x@server:~$ cat /proc/spl/kstat/zfs/zil
8 1 0x01 107 8880 1234567890 987654321
name type data
zil_commit_count 4 152340
zil_commit_writer_count 4 152338
zil_itx_count 4 9832451
zil_itx_indirect_count 4 0
Interpretación: Alta actividad de commits sugiere cargas con muchas escrituras sync. Si estás cerca del lleno y con sync intensivo, lo vas a notar. Un SLOG puede reducir la latencia de escrituras sync, pero no curará la fragmentación del asignador ni la amplificación por snapshots.
Tarea 12: Confirmar ashift (implicaciones de capacidad y alineación IO)
cr0x@server:~$ zdb -C tank | grep -E "ashift|vdev_tree" -n | head
109: vdev_tree:
174: ashift: 12
231: ashift: 12
Interpretación: ashift=12 (4K) es común. Si construiste accidentalmente con un ashift demasiado pequeño para unidades 4K-nativas, puedes tener ineficiencias de rendimiento y espacio que reducen tu margen real.
Tarea 13: Medir el dolor de borrado (destrucción de snapshot) de forma segura
cr0x@server:~$ time zfs destroy -nvp tank/home@hourly-2025-12-24-2100
would destroy tank/home@hourly-2025-12-24-2100
would reclaim 180G
Interpretación: El dry-run muestra el espacio recuperable. Si los destroys tardan una eternidad en la práctica, eso suele ser señal de que estás profundo en fragmentación y/o churn de metadata. Planifica borrados en horas de baja actividad y evita destruir masivamente durante picos de escritura.
Tarea 14: Detectar candidatos de bloques pequeños para special vdev (metadata/bloques pequeños)
cr0x@server:~$ zfs get -o name,property,value,source special_small_blocks tank/home tank/containers
NAME PROPERTY VALUE SOURCE
tank/home special_small_blocks 0 default
tank/containers special_small_blocks 0 default
Interpretación: Si tienes un special vdev y habilitas bloques pequeños para que aterricen allí, puedes reducir I/O aleatorio en vdevs HDD. Pero esto es una elección de diseño, no un parche: si subdimensionas el special vdev creas un nuevo modo de fallo “pool lleno” cuando éste se llena.
Guion de diagnóstico rápido (qué comprobar primero, segundo, tercero)
Cuando alguien dice “ZFS está lento” y el pool se está llenando, necesitas una secuencia repetible que encuentre el cuello de botella antes de que se multipliquen las invitaciones a reuniones.
Primero: confirmar si esto es presión de capacidad o otra cosa
- CAP y FRAG del pool: ¿CAP > ~80%? ¿FRAG aumenta con el tiempo?
- Latencia de escritura en la app: ¿Ves p99 picos que se correlacionan con carga de escritura o operaciones de snapshot?
- Errores/dispositivos degradados: ¿Algún disco con errores, dispositivos lentos o un resilver en progreso?
cr0x@server:~$ zpool list -o name,size,alloc,free,frag,cap,health
NAME SIZE ALLOC FREE FRAG CAP HEALTH
tank 54.5T 44.1T 10.4T 38% 80% ONLINE
Segundo: determinar si estás limitado por IOPS, ancho de banda, sync o CPU
- IOPS y ancho de banda por vdev:
zpool iostat -v 1durante la ventana del problema. - Latencia de disco: Usa herramientas del SO para ver await/service times; un pool casi lleno puede parecer “I/O aleatorio por todas partes”.
- Presión de sync: NFS, bases de datos e hipervisores pueden forzar escrituras sync. Confírmalo con actividad ZIL y políticas de
syncde datasets. - CPU: Compresión y checksum suelen valer la pena, hasta que la máquina se queda sin CPU durante la sincronización de TXG.
cr0x@server:~$ iostat -x 1 3
avg-cpu: %user %nice %system %iowait %steal %idle
12.30 0.00 6.10 22.40 0.00 59.20
Device r/s w/s rkB/s wkB/s await svctm %util
sda 21.0 240.0 1800 16400 28.1 2.8 73.4
sdb 18.0 255.0 1600 17100 31.5 2.9 79.2
Interpretación: Await alto y %util implican que los discos son el limitador. La fragmentación cercana al lleno tiende a empujar I/O aleatorio, elevando await.
Tercero: identificar el dataset o comportamiento que causa presión
- ¿Qué datasets están creciendo más rápido?
zfs list -o used,refery listas de snapshots. - ¿Qué snapshots son enormes? Ordena snapshots por USED.
- ¿Una sola carga está haciendo churn por sobrescritura? VMs, caches de CI, bases de datos.
cr0x@server:~$ zfs list -t snapshot -o name,used -S used | head
NAME USED
tank/home@hourly-2025-12-24-2300 420G
tank/home@hourly-2025-12-24-2200 390G
tank/vm@daily-2025-12-24 210G
Errores comunes, síntomas específicos y soluciones
Error 1: Tratar el 80% como una línea rígida en lugar de vigilar el comportamiento
Síntoma: El pool está “solo” al 75–80% usado, pero los picos de latencia de escritura y los borrados se estancan.
Solución: Añade alertas sobre latencia de escritura, tiempo de sincronización TXG (vía métricas del sistema) y tasa de crecimiento de snapshots. Mantén margen según la carga observada. Si tu pool se vuelve infeliz al 75%, tu regla es 75%.
Error 2: Mantener una política de snapshots que crece sin plan de borrado
Síntoma: “Borramos 2 TB pero solo recuperamos 50 GB.” Snapshot USED es grande; los borrados no liberan espacio rápido.
Solución: Audita retención de snapshots por dataset, limita la retención y borra los más antiguos primero fuera de horas pico. Considera separar cargas con mucho churn en su propio dataset con cadencia de snapshots a medida.
Error 3: Mezclar cargas incompatibles en un mismo dataset
Síntoma: Afinar para una carga rompe a otra; las decisiones sobre recordsize/compresión parecen compromisos.
Solución: Separa cargas en datasets y ajústalos (recordsize/volblocksize, compresión, atime, logbias).
Error 4: Sobreoptimizar para informes de capacidad
Síntoma: Excelentes ratios de compresión, latencia terrible bajo carga de escritura.
Solución: Mantén la compresión sensata (lz4 es la ganancia habitual “gratis”), pero mide el margen de CPU. No subas recordsize para cargas de escritura aleatoria.
Error 5: Asumir que un SLOG arregla el rendimiento “cerca de lleno”
Síntoma: Añadiste un SLOG rápido; la latencia de escrituras aleatorias sigue siendo horrible; los borrados de snapshots siguen lentos.
Solución: SLOG ayuda la latencia de escrituras sync; no arregla fragmentación, presión de metadata ni costes de búsqueda del asignador. Concéntrate en margen y diseño de datasets.
Error 6: Usar RAIDZ para cargas de VM con muchas IOPS sin suficiente ancho/cantidad de vdevs
Síntoma: Rendimiento aceptable al 50% usado; doloroso al 75%; scrubs/resilvers devastan la latencia.
Solución: Los mirrors (más vdevs) suelen ofrecer mejor IOPS en cargas pequeñas y aleatorias. Si te quedas en RAIDZ, planifica más vdevs, considera special vdev para metadata y mantén más espacio libre.
Error 7: Ignorar la dinámica de rebuild/resilver
Síntoma: Reemplazar un disco tarda una eternidad; el rendimiento durante el resilver es catastrófico.
Solución: Mantén margen, scrubea regularmente y programa trabajos pesados alrededor del mantenimiento. Los pools casi llenos hacen los resilvers más lentos porque la asignación y los patrones de espacio libre son peores.
Listas de verificación / plan paso a paso
Paso a paso: decidir tu verdadero objetivo de headroom
- Mide tu “normal”: Registra latencia de escritura p95/p99, comportamiento de sincronización TXG (indirectamente vía picos de latencia) y tiempo base de scrub al 50–60% de utilización.
- Mide a mayor utilización: Al pasar 70%, 75%, 80%, compara esas métricas semanalmente.
- Encuentra la rodilla: El punto donde la varianza de latencia y las tareas operativas (borrado de snapshots, scrub) se degradan más rápido que crece la capacidad.
- Establece política: Tu “regla” es donde tu carga permanece aburrida. Para algunos pools es 80%. Para otros es 70%. Para pools de backup append-only, puede ser más alto con gestión cuidadosa.
Paso a paso: recuperación de espacio de emergencia sin caos
- Detén la hemorragia: Identifica al mayor escritor y ponlo en pausa si es posible (cache de CI, bucle de logging, job de backup descontrolado).
- Borra con intención: Prioriza borrar snapshots que recuperen más espacio primero (pero no borres masivamente a lo loco en hora pico).
- Protege datasets críticos: Asegúrate de que tengan reservas o cuotas apropiadas para que un equipo no deje a todos sin espacio.
- Verifica después de recuperar: Confirma el espacio libre del pool y que la latencia se estabilice; programa un scrub si tuviste problemas de hardware.
Paso a paso: hacer que el “casi lleno” dejen de dar miedo a largo plazo
- Separa cargas en datasets y ajústalas (recordsize/volblocksize, compresión, atime, logbias).
- Revisa diseño de vdev (mirrors vs RAIDZ, número de vdevs, dimensionado del special vdev si se usa).
- Implementa alertas basadas en tendencia (tasa de crecimiento de espacio + latencia), no solo umbrales.
- Practica la limpieza (aplicar retención de snapshots, simulacro de recuperación de emergencia).
Preguntas frecuentes (FAQ)
1) ¿Es real la regla del 80% en ZFS?
Es real como advertencia, no como umbral universal. Muchos pools se vuelven notablemente más difíciles de asignar de forma eficiente al pasar ~80%, pero la “rodilla” real depende de la carga, diseño de vdev y fragmentación.
2) ¿Por qué el rendimiento se degrada tanto cerca del lleno?
Porque ZFS debe asignar nuevos bloques para escrituras (copy-on-write), y a medida que el espacio libre se reduce se vuelve más fragmentado y desigual. El asignador trabaja más y hace ubicaciones menos óptimas, aumentando I/O y latencia.
3) ¿Los pools SSD ignoran la regla del 80%?
Los SSD enmascaran algunos síntomas (penalización por seek) pero no eliminan la sobrecarga de asignación, el churn de metadata ni el impacto de sobrescrituras con muchos snapshots. Además, los SSD tienen sus propios acantilados de rendimiento cuando su espacio interno libre (overprovisioning) se achica.
4) ¿Es FRAG de ZFS un indicador fiable?
Es útil pero no suficiente. Un valor FRAG moderado puede estar bien para cargas secuenciales y ser doloroso para cargas aleatorias. Usa FRAG junto a métricas de latencia y comprensión de la carga.
5) ¿Añadir más RAM arregla el rendimiento cerca del lleno?
Más ARC ayuda lecturas y caching de metadata, y puede reducir algo de I/O. Pero no hará que el espacio fragmentado sea contiguo, ni evitará el dolor del asignador bajo escrituras intensas. Considera la RAM un multiplicador, no una cura.
6) ¿Un SLOG me permite usar el pool más lleno?
Un SLOG puede mejorar la latencia de escrituras sync para cargas como NFS o bases de datos con fsync. No arregla la ineficiencia de asignación general ni la amplificación por snapshots. Puede ayudarte a sobrevivir, no a romper las leyes de la geometría.
7) ¿Cuál es la forma más segura de recuperar espacio rápido?
Detén o limit a quien más escribe, y luego recupera espacio donde realmente se pueda recuperar—a menudo borrando snapshots con alto USED. Usa zfs destroy -nvp para estimar lo que recuperarás y evita operaciones destructivas masivas en plena carga pico.
8) ¿Puedo desfragmentar un pool ZFS?
No en el sentido tradicional de “ejecutar defrag”. Puedes reducir la fragmentación reescribiendo datos con el tiempo (send/receive a un nuevo pool, o replicación a vdevs frescos) y manteniendo margen para que las decisiones del asignador sigan siendo buenas.
9) ¿Por qué borrar archivos no liberó espacio?
Porque los snapshots pueden seguir referenciando los bloques antiguos. Borrar el archivo en vivo elimina una referencia, pero los snapshots preservan otra. El espacio se libera cuando se elimina la última referencia—lo que suele implicar expirar snapshots.
10) ¿Qué objetivo de utilización debo elegir?
Elige la utilización máxima que mantenga tu sistema aburrido bajo carga máxima. Para muchos pools de propósito general eso es 70–80%. Para cargas churny de VM/DB, bajar suele ser más seguro. Para backups append-only, puedes apurar más con monitorización y control de retención cuidadosos.
Conclusión
La regla del 80% de ZFS no es ni mito ni evangelio. Es una cicatriz antigua convertida en eslogan. La verdad ingenieril es que ZFS necesita espacio libre usable para mantener eficientes las asignaciones copy-on-write, y “usable” depende de fragmentación, disponibilidad de metaslabs, patrones de escritura de la carga y churn de snapshots.
Si operas almacenamiento en producción, la jugada ganadora no es discutir sobre el 80%. Es definir la zona peligrosa de tu pool usando comportamiento: varianza de latencia, dinámica de recuperación de snapshots, impacto de scrub/resilver y tendencias de crecimiento. Mantén suficiente margen para facilitar la asignación, aplica políticas aburridas (cuotas, reservas, retención) y pasarás menos tiempo negociando con un sistema de archivos que se quedó sin buenas opciones.