ZFS refreservation: Garantizando espacio sin romper aplicaciones

¿Te fue útil?

En producción, “disco lleno” rara vez es un evento aislado. Es una reacción en cadena: un archivo de registro deja de rotar, una base de datos entra en pánico, una cola se acumula y de repente el canal de incidentes se llena de gente repitiendo “pero df dice que hay espacio.” ZFS te da herramientas excepcionalmente precisas para evitar ese desorden—si entiendes la diferencia entre espacio que existe y el espacio que realmente puede escribir tu dataset.

Esta es una guía profunda y práctica sobre refreservation de ZFS: qué garantiza realmente, qué no garantiza, cómo interactúa con cuotas y snapshots, y cómo usarla para mantener aplicaciones críticas vivas mientras todo lo demás pelea por los bytes restantes. El objetivo no es la corrección académica. El objetivo es no volver a ver una pool perfectamente “saludable” tumbar un servicio de nivel 0 porque los últimos GiB fueron devorados por algo aburrido.

Qué es refreservation (y por qué existe)

refreservation es una propiedad de dataset de ZFS que reserva espacio basado en los datos referenciados para ese dataset. En términos sencillos: es ZFS diciendo, “No importa qué más pase en esta pool, este dataset tendrá al menos N bytes disponibles para escribir, siempre que la pool en sí no haya cruzado ya el punto de imposibilidad física.”

La parte “ref” importa. ZFS es copy-on-write. El espacio “usado” de un dataset no es solo lo que está en su estado actual. Los snapshots pueden mantener bloques antiguos vivos. Los clones pueden compartir bloques. Los borrados no siempre liberan espacio cuando crees que lo hacen. Así es como llegas al clásico debate de ZFS:

  • Aplicación: “Borré 500GB. ¿Por qué no puedo escribir 10GB?”
  • ZFS: “Porque esos 500GB siguen referenciados por snapshots, clones u otros datasets. Buen intento.”

refreservation está diseñado para proteger la capacidad de un dataset de seguir escribiendo aun cuando su propio historial (snapshots) o su relación con otros datasets (clones) haga la contabilidad de espacio poco obvia.

Una manera operativa de describirlo: refreservation es cómo evitas que “datasets importantes” se queden sin espacio debido a “datasets interesantes.” Importantes: bases de datos, colas con journaling, almacenes de metadatos, volúmenes de arranque de VM. Interesantes: cualquier cosa en la que la gente pueda volcar datos, especialmente logs, buckets de subida, artefactos de compilación o áreas de “scratch” que son temporales desde 2019.

Broma #1: Refreservation es como poner tu almuerzo en la nevera de la oficina con tu nombre—salvo que esto realmente funciona.

Datos interesantes y contexto histórico

La ingeniería de almacenamiento está llena de “ideas nuevas” que en realidad son ideas antiguas con mejor herramienta. Algunos puntos de contexto que ayudan a que refreservation tenga sentido:

  1. ZFS se diseñó para integridad de extremo a extremo, no solo para gestión de capacidad. Controles de espacio como cuotas y reservas existen porque “correcto pero lleno” aún rompe aplicaciones.
  2. Los sistemas de archivos copy-on-write complican los borrados. Los sistemas tradicionales suelen liberar bloques al borrar; ZFS solo libera bloques cuando nada los referencia. Los snapshots son lo más común que referencia bloques.
  3. La “paradoja df” existe desde antes de ZFS. Incluso en sistemas antiguos, bloques reservados, sobrecarga del sistema de archivos y asignación retardada causaban momentos en los que “df muestra libre”. ZFS solo hace las razones más potentes—y más confusas.
  4. La provisión delgada (thin provisioning) se volvió común en virtualización y trajo una nueva clase de cortes: los invitados creen que tienen espacio; el backend lo contradice a las 3 a.m. Las reservas de ZFS son una forma honesta de gestionar trade-offs thin vs thick.
  5. Los snapshots pasaron de “función de backup” a “predeterminado operacional.” En el momento en que los equipos comenzaron a snapshotear con frecuencia (cada hora, cada 15 minutos, a veces cada 5), la presión de espacio se volvió una preocupación diaria.
  6. “Mantener 20% libre” no es superstición. Muchos sistemas de almacenamiento (incluido ZFS) degradan rendimiento y flexibilidad de asignación al acercarse al lleno. Refreservation no arregla la física.
  7. La herencia de propiedades de ZFS es una característica y una trampa. Reservas y cuotas pueden heredarse inesperadamente; refreservation se suele poner a nivel de dataset precisamente porque “talla única” falla.
  8. Refquota/refreservation surgieron del dolor real de administradores. Las propiedades “ref” existen porque “used” puede incluir espacio que no es realmente tuyo para liberar (snapshots/clones).

Un modelo mental: espacio referenciado vs disponible

Si operas ZFS el tiempo suficiente, acabas con dos libretas mentales:

  • Propiedad lógica: lo que un dataset aparenta contener ahora mismo.
  • Realidad física: qué bloques siguen referenciados en la pool.

ZFS expone esta división mediante propiedades de espacio de dataset. La salida exacta varía por plataforma (OpenZFS en Linux vs derivados de illumos), pero las ideas son estables:

  • used: espacio total consumido por el dataset y sus descendientes, incluyendo snapshots (según el contexto) y sobrecarga.
  • referenced: espacio referenciado por el estado actual del dataset (excluyendo snapshots).
  • usedbydataset, usedbysnapshots, usedbychildren: el mejor desglose para “¿a dónde fue?”.
  • available: lo que ZFS cree que puede escribirse en el dataset, después de cuotas/reservas y restricciones de la pool.

refreservation está ligado a referenced. Piénsalo como: “Quiero garantizar que este dataset pueda aumentar sus bytes referenciados al menos N, sin importar el equipaje de snapshots en otros lados.” La mecánica es sutil, pero operativamente el efecto es claro: separa espacio de la pool que otros datasets no pueden reclamar.

Reservation vs refreservation vs cuotas

ZFS ofrece varias palancas que suenan similares. No son intercambiables. Aquí el mapeo práctico:

reservation

reservation reserva espacio para un dataset y sus descendientes (según cómo estructures las cosas). Es una garantía de “este subárbol obtiene al menos N bytes”. Es útil cuando tratas un dataset como un contenedor para muchos hijos y quieres una porción mínima de la pool protegida.

refreservation

refreservation trata sobre el espacio referenciado del dataset (no snapshots). Es la herramienta más precisa cuando te importa la capacidad del dataset para seguir escribiendo su estado vivo actual incluso cuando existen snapshots y los borrados no devuelven espacio de inmediato.

quota

quota limita cuánto espacio puede consumir un dataset (y típicamente sus descendientes). Es un techo: “no puedes crecer más allá de esto”. Bueno para control multi-tenant. Malo si lo configuras y lo olvidas.

refquota

refquota limita el espacio referenciado (datos vivos actuales), no los snapshots. Esto suele ser lo que quieres cuando no quieres que los snapshots sean la razón por la que un dataset rechaza escrituras—aunque aún estás limitado por el espacio total de la pool.

Una regla rápida para decidir

  • Si quieres limitar los datos vivos de una app: usa refquota.
  • Si quieres limitar todo incluyendo la proliferación de snapshots: usa quota.
  • Si quieres garantizar una porción mínima para las escrituras vivas de un dataset: usa refreservation.
  • Si quieres garantizar una porción mínima para todo un subárbol: usa reservation.

Broma #2: Si las cuotas son una dieta, las refreservations son preparar las comidas—menos emocionantes, más efectivas, y todos las resienten hasta que llega la crisis.

Cómo ZFS aplica refreservation (qué se garantiza realmente)

Las reservas de ZFS no son espacio extra mágico; son zonas de exclusión. Cuando configuras una refreservation, ZFS reduce lo que otros datasets ven como disponible porque ese espacio está reservado.

Tres verdades operativas importantes:

  1. Refreservation solo ayuda si la pool tiene espacio para honrarla. Si la pool está realmente llena (o efectivamente llena debido al espacio de seguridad y las necesidades de metadata), ZFS no puede asignar bloques que no tiene. Refreservation es una política, no una ley de la termodinámica.
  2. Refreservation no reserva “espacio para snapshots.” Se trata del crecimiento referenciado/vivo del dataset. Los snapshots aún pueden consumir la pool y crear problemas, simplemente no robando la porción garantizada de las escrituras vivas de ese dataset.
  3. Refreservation puede hacer que otros datasets fallen antes—y ese es el punto. Es un mecanismo de priorización. Tu dataset de archivo de logs debería fallar antes que tu dataset de base de datos.

Además, ZFS es honesto pero no siempre intuitivo: el valor de available en un dataset ya refleja estas restricciones de política. Si tu refreservation es grande, zfs list para otros datasets mostrará menos disponible, incluso si la pool tiene espacio bruto libre.

Tres mini-historias del mundo corporativo

Mini-historia #1: El outage causado por una suposición incorrecta (“Los snapshots son backups, ¿no?”)

Una empresa mediana ejecutaba una API orientada al cliente respaldada por PostgreSQL sobre ZFS. El layout de almacenamiento parecía limpio: una pool, un dataset para la base de datos, un dataset para WAL y un dataset para logs. Tomaban snapshots frecuentes porque parecía lo responsable. Y lo era—hasta la noche en la que no lo fue.

Un desarrollador ejecutó un backfill que creó una tabla temporal grande y luego la eliminó. El equipo vio el uso del filesystem de la base de datos dispararse y luego caer. Todos respiraron aliviados. Pero la pool no lo hizo. Porque los snapshots retenían los bloques, el espacio “liberado” no estaba realmente libre. La pool fue acercándose al lleno en las siguientes horas conforme continuaban las escrituras normales.

A aproximadamente 95% de utilización de pool (efectiva), el rendimiento se degradó. La latencia subió. Autovacuum empezó a thrashear. Luego el dataset de WAL alcanzó ENOSPC. PostgreSQL hizo lo que hacen las bases de datos cuando no pueden escribir WAL: dejó de ser una base de datos.

La suposición equivocada fue sutil: “Si la base de datos borra datos, la pool recupera espacio.” En ZFS con snapshots, eso no está garantizado. No tenían refreservation en WAL, ni refquota para controlar el crecimiento temporal, y su política de retención de snapshots era “para siempre hasta que nos acordemos de limpiarla.” La solución no fue heroica: añadieron una refreservation para WAL dimensionada para cubrir ráfagas de escritura máximas, limitaron el dataset de la base de datos con refquota y establecieron tiempos de vida de snapshots con cumplimiento.

El postmortem tenía una línea que he visto en muchas formas: “Tratamos los snapshots como backups.” Los snapshots son una máquina del tiempo conectada a tu capa de asignación. Son increíblemente útiles—solo que no son gratis.

Mini-historia #2: La optimización que salió mal (“Todo thin!”)

Otra organización consolidó múltiples servicios en una sola pool ZFS para simplificar operaciones. Movieron discos de VM y volúmenes de contenedores a datasets y apostaron por la provisión delgada. Parecía eficiente: alta utilización, poco desperdicio, todos contentos. Finanzas lo adoró.

Luego alguien “optimizó” eliminando un conjunto de reservas de datasets. La lógica sonaba sólida en una reunión: “Las reservas desperdician espacio. Podemos recuperar capacidad y aumentar la densidad.” Quitaron reservas de algunos datasets de infraestructura, incluyendo el que contenía volúmenes de arranque críticos de VM.

Dos semanas después, una pipeline de builds se descontroló. Llenó un dataset de artefactos con blobs de varios gigabytes. Como nada estaba reservado, el dataset de artefactos consumió con gusto el resto del espacio. Cuando un hipervisor intentó escribir en un disco de VM (una pequeña actualización de metadata, nada dramático), la escritura falló. De pronto, VMs que tenían mucho espacio aparente dentro del invitado no podían confirmar escrituras a nivel de almacenamiento. El resultado fue un torrente de remounts en modo solo-lectura y mucho “¿cómo es posible?”

La lección no fue “la provisión delgada es mala.” La lección fue: provisión delgada sin reglas de prioridad es apostar. Reservations/refreservations son esas reglas. El equipo reintrodujo garantías para volúmenes de arranque y bases de datos, y pusieron el dataset de artefactos detrás de una cuota más una pool separada de “desbordamiento”. La densidad bajó un poco. El sueño mejoró mucho.

Mini-historia #3: La práctica aburrida pero correcta que salvó el día (“Protege el journal”)

Un equipo de pagos ejecutaba una cola de mensajes cuya durabilidad dependía de un write-ahead log. La cola no era glamorosa, pero era el sistema de registro para el trabajo en vuelo. Alguien del equipo ya había sufrido incidentes por falta de espacio, así que hizo algo profundamente poco sexy: creó un dataset dedicado para el journal y estableció una refreservation basada en la tasa de ingestión en el peor caso y el tiempo de respuesta ante incidentes.

Meses después, durante una escalada con un cliente se activó una bandera de debug “inofensiva”. Los logs explotaron. No de forma linda—de forma de “terabytes en un día”. El dataset de logs devoró todo lo que pudo, incluidos snapshots, y la pool pasó de cómoda a ajustada en horas.

Pero la cola siguió funcionando. El dataset del journal aún tenía espacio para escribir porque su refreservation había separado una porción que el dataset de logs no podía robar. El incidente fue ruidoso—alertas, limpieza, corrección de política de retención—pero no fue catastrófico. No hubo mensajes perdidos, ni estado corrupto, ni restauración a medianoche desde backup.

Para eso sirve refreservation: no para hacer la pool más grande, sino para hacer que los fallos impacten en los objetivos correctos. Cuando las cosas van mal, quieres que el dataset menos importante sea el primero en gritar.

Tareas prácticas (comandos + interpretación)

Estas son tareas prácticas que puedes ejecutar en un sistema OpenZFS (comúnmente Linux con ZFS-on-Linux/OpenZFS). Los comandos suponen que tienes privilegios. Reemplaza nombres de pool/dataset para que coincidan con tu entorno.

Tarea 1: Obtener la salud y la realidad de capacidad de la pool

cr0x@server:~$ zpool status -v
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 0 days 00:12:41 with 0 errors on Sun Dec 22 02:10:11 2025
config:

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          sda       ONLINE       0     0     0
          sdb       ONLINE       0     0     0

errors: No known data errors

Interpretación: Antes de ajustar propiedades, confirma que no estés depurando alrededor de una pool degradada. Las reservas no te salvarán de discos fallando o de una pool que no puede asignar debido a errores.

Tarea 2: Ver el espacio libre a nivel de pool y pistas de fragmentación

cr0x@server:~$ zpool list -o name,size,alloc,free,cap,frag,health
NAME  SIZE  ALLOC  FREE  CAP  FRAG  HEALTH
tank  7.25T  6.10T  1.15T  84%   29%  ONLINE

Interpretación: Un CAP alto y FRAG en aumento son las condiciones donde “debería funcionar” se transforma en “¿por qué va lento y falla?” Si estás consistentemente por encima de ~85–90%, estás en la zona de peligro independientemente de las reservas.

Tarea 3: Inventariar datasets y su espacio disponible

cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint
NAME               USED  AVAIL  REFER  MOUNTPOINT
tank               6.10T  1.02T   192K  /tank
tank/db            2.40T   220G  2.10T  /tank/db
tank/db-wal         180G   120G   175G  /tank/db-wal
tank/logs          1.60T   140G  1.20T  /tank/logs
tank/artifacts     1.90T    90G  1.50T  /tank/artifacts

Interpretación: avail aquí es lo que importa para las aplicaciones. Ya está ajustado por reservas/cuotas. Si un dataset crítico tiene poco avail, no tienes un problema teórico—tienes un incidente a corto plazo.

Tarea 4: Mostrar propiedades relacionadas con reservas para todos los datasets

cr0x@server:~$ zfs get -r -o name,property,value,source reservation,refreservation,quota,refquota tank
NAME             PROPERTY        VALUE  SOURCE
tank             reservation     none   default
tank             refreservation  none   default
tank             quota           none   default
tank             refquota        none   default
tank/db          reservation     none   default
tank/db          refreservation  300G   local
tank/db          quota           none   default
tank/db          refquota        3T     local
tank/db-wal      reservation     none   default
tank/db-wal      refreservation  200G   local
tank/db-wal      quota           none   default
tank/db-wal      refquota        none   default
tank/logs        reservation     none   default
tank/logs        refreservation  none   default
tank/logs        quota           2T     local
tank/logs        refquota        none   default

Interpretación: Si no puedes responder “¿qué datasets tienen espacio garantizado?” con un comando, estás trabajando con intuiciones. Esta vista hace la política explícita.

Tarea 5: Fijar una refreservation para un dataset crítico

cr0x@server:~$ sudo zfs set refreservation=200G tank/db-wal
cr0x@server:~$ zfs get refreservation tank/db-wal
NAME         PROPERTY        VALUE  SOURCE
tank/db-wal  refreservation  200G   local

Interpretación: Esto reserva 200G de la pool para el crecimiento referenciado del dataset WAL. Si te excedes, puedes dejar sin espacio a otros datasets—así que dimensiona según tasas reales de escritura y tiempo de respuesta ante incidentes.

Tarea 6: Confirmar cómo refreservation afecta el espacio disponible de otros datasets

cr0x@server:~$ zfs list -o name,avail tank/logs tank/artifacts tank/db-wal
NAME           AVAIL
tank/logs      90G
tank/artifacts 40G
tank/db-wal    120G

Interpretación: Si acabas de establecer una refreservation, espera que el AVAIL de otros datasets se reduzca. Eso no es un bug; es la política cumpliendo su función.

Tarea 7: Ver dónde está atado el espacio (dataset vs snapshots)

cr0x@server:~$ zfs list -o name,used,usedbydataset,usedbysnapshots,usedbychildren,refer -t filesystem tank/db
NAME      USED  USEDBYDATASET  USEDBYSNAPSHOTS  USEDBYCHILDREN  REFER
tank/db  2.40T          2.10T            260G              40G  2.10T

Interpretación: Si USEDBYSNAPSHOTS es grande, los borrados no liberarán espacio. Si tu app “liberó” datos pero la pool no, este desglose es donde empezar.

Tarea 8: Listar snapshots e identificar grandes culpables

cr0x@server:~$ zfs list -o name,used,refer,creation -t snapshot tank/db | tail -n 5
tank/db@auto-2025-12-23-0000   12.4G  2.06T  Tue Dec 23 00:00 2025
tank/db@auto-2025-12-23-0100    9.8G  2.07T  Tue Dec 23 01:00 2025
tank/db@auto-2025-12-23-0200   15.1G  2.07T  Tue Dec 23 02:00 2025
tank/db@auto-2025-12-23-0300   11.2G  2.08T  Tue Dec 23 03:00 2025
tank/db@auto-2025-12-23-0400   10.6G  2.08T  Tue Dec 23 04:00 2025

Interpretación: El USED de un snapshot es el espacio único para ese snapshot (relativo a otros). Números grandes suelen correlacionar con workloads con mucho churn (bases de datos, CI artefactos) y pueden justificar reducir retención o mover cargas.

Tarea 9: Comprobar si un dataset está bloqueado por una cuota/refquota en lugar de por la pool llena

cr0x@server:~$ zfs get -o name,property,value quota,refquota tank/logs
NAME       PROPERTY  VALUE
tank/logs  quota     2T
tank/logs  refquota  none

Interpretación: Si una app ve ENOSPC pero la pool no está llena, las cuotas son una sospecha principal. Las cuotas son un “lleno local” aun cuando la pool tenga capacidad.

Tarea 10: Medir el headroom referenciado real vs el tamaño de refreservation

cr0x@server:~$ zfs get -o name,property,value referenced,refreservation tank/db-wal
NAME         PROPERTY        VALUE
tank/db-wal  referenced      175G
tank/db-wal  refreservation  200G

Interpretación: Con referenced en 175G y refreservation en 200G, estás garantizando esencialmente unos 25G adicionales de crecimiento referenciado (sujeto a la realidad de la pool). Si referenced ya está por encima de la refreservation, no se te “debe” espacio extra; la reserva está efectivamente consumida.

Tarea 11: Usar reservation en su lugar cuando quieras proteger un subárbol

cr0x@server:~$ sudo zfs set reservation=500G tank/db
cr0x@server:~$ zfs get reservation tank/db
NAME     PROPERTY     VALUE  SOURCE
tank/db  reservation  500G   local

Interpretación: Esto es apropiado cuando tank/db contiene múltiples hijos (tablespaces, backups, áreas temporales) y quieres proteger al grupo. Úsalo con cuidado: las reservas de subárbol pueden ser sorprendentemente “pegajosas” en su efecto sobre la disponibilidad de la pool.

Tarea 12: Eliminar una refreservation de forma segura (y verificar impacto)

cr0x@server:~$ sudo zfs set refreservation=none tank/db-wal
cr0x@server:~$ zfs get refreservation tank/db-wal
NAME         PROPERTY        VALUE  SOURCE
tank/db-wal  refreservation  none   default

Interpretación: Quitar garantías debe tratarse como quitar un disyuntor: puede estar bien, pero estás cambiando modos de fallo. Hazlo con una razón explícita y un plan de reversión.

Tarea 13: Comprobar las restricciones de “slop space” de la pool (por qué los últimos GiB no se comportan)

cr0x@server:~$ zfs get -o name,property,value special_small_blocks 2>/dev/null
cr0x@server:~$ zfs list -o name,avail tank

Interpretación: Muchos operadores se sorprenden por el límite práctico donde ZFS se vuelve conservador cerca del lleno para preservar la operabilidad de la pool. Si diseñas garantías, no planees usar “el 100% del tamaño de la pool.” Deja margen.

Tarea 14: Identificar si los borrados están bloqueados por snapshots/clones

cr0x@server:~$ zfs get -o name,property,value used,referenced,usedbysnapshots tank/artifacts
NAME            PROPERTY        VALUE
tank/artifacts  used            1.90T
tank/artifacts  referenced      1.50T
tank/artifacts  usedbysnapshots 380G

Interpretación: Si los datos “borrados” formaban parte del estado referenciado pero los snapshots los retienen, usedbysnapshots crece. Esa es a menudo la explicación de “rm -rf no lo arregló”.

Tarea 15: Crear un dataset “sacrificial” con cuota para absorber basura

cr0x@server:~$ sudo zfs create tank/scratch
cr0x@server:~$ sudo zfs set quota=200G tank/scratch
cr0x@server:~$ zfs get -o name,property,value quota tank/scratch
NAME          PROPERTY  VALUE
tank/scratch  quota     200G

Interpretación: Esta es la versión operacional de “pon lo sucio en una habitación con candado.” Puedes asignar trabajos temporales aquí para que choquen contra un límite antes de afectar datasets de producción.

Guion de diagnóstico rápido

Cuando algo falla con ENOSPC, escrituras lentas o “el espacio disponible no tiene sentido”, no te aventures al azar. Comprueba esto en orden.

1) Realidad de la pool: ¿la pool está realmente llena o no está sana?

cr0x@server:~$ zpool list -o name,size,alloc,free,cap,frag,health
cr0x@server:~$ zpool status -v

Qué buscas: CAP > ~90%, fragmentación muy alta o estado degradado. Si la pool está en llamas, los ajustes a nivel de dataset son secundarios.

2) Restricciones de dataset: quota/refquota/reservation/refreservation

cr0x@server:~$ zfs get -r -o name,property,value,source quota,refquota,reservation,refreservation tank

Qué buscas: Un dataset alcanzando una quota/refquota, o que otros datasets “pierden” disponibilidad porque existe una gran reservation/refreservation en otro lado.

3) Espacio retenido por snapshots y hijos

cr0x@server:~$ zfs list -o name,used,usedbydataset,usedbysnapshots,usedbychildren,refer -t filesystem tank
cr0x@server:~$ zfs list -t snapshot -o name,used,creation | tail

Qué buscas: Grandes usedbysnapshots en datasets con churn; un dataset hijo consumiendo la reserva del padre; snapshots amplificando crecimiento.

4) Si el síntoma es rendimiento: comprueba saturación I/O y latencia de la pool

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

Qué buscas: Alta utilización de disco, tiempos de espera largos y carga desigual entre dispositivos. Una pool cerca del lleno también puede amplificar la amplificación de escritura y el churn de metadata.

5) Confirma la vista de la app (filesystem vs ZFS)

cr0x@server:~$ df -hT /tank/db /tank/db-wal
cr0x@server:~$ zfs list -o name,avail,used,refer tank/db tank/db-wal

Qué buscas: Mismatch entre df y zfs list generalmente significa que la política de ZFS (quota/reservation) o la realidad de snapshots es el factor decisivo, no lo que el sistema operativo cree en términos genéricos.

Errores comunes (síntomas + soluciones)

Error 1: “Pusimos refreservation y ahora la pool ‘perdió’ espacio.”

Síntoma: Otros datasets muestran AVAIL dramáticamente reducido. Alguien afirma que “consumiste” cientos de gigabytes sin escribir datos.

Qué está pasando: Reservations/refreservations reducen la disponibilidad compartida; esa es la garantía que se está honrando.

Solución: Dimensiona correctamente garantías basadas en escrituras en el peor caso y tiempo de respuesta. Si necesitas proteger múltiples servicios, reparte garantías más pequeñas en lugar de una gran partición. Confirma con:

cr0x@server:~$ zfs get -r -o name,property,value refreservation,reservation tank

Error 2: Asumir que refreservation te protege de snapshots llenando la pool

Síntoma: Pusiste refreservation en un dataset crítico, pero las escrituras aún fallan cuando la pool está casi llena.

Qué está pasando: Si la pool no puede asignar bloques por llenado general (más la necesidad de ZFS de espacio de metadata y margen operacional), la garantía no puede conjurar espacio.

Solución: Impon política de retención de snapshots y margen de capacidad. Trata “pool > 90%” como un incidente, no como una métrica. Investiga uso de snapshots:

cr0x@server:~$ zfs list -o name,used,usedbysnapshots -t filesystem tank | sort -h -k3

Error 3: Usar reservation cuando querías refreservation (o al revés)

Síntoma: Reservas en un dataset padre, pero un hijo alcanza ENOSPC; o pusiste refreservation en un padre y no se comporta como “garantía de subárbol”.

Qué está pasando: reservation y refreservation se aplican de forma diferente en jerarquía y en términos contables.

Solución: Decide si proteges las escrituras vivas de un solo dataset (refreservation) o un subárbol entero (reservation). Verifica la herencia y dónde se aplica la reserva:

cr0x@server:~$ zfs get -r -o name,property,value,source reservation,refreservation tank/db

Error 4: Tratar cuotas como “buenos predeterminados” sin monitorizar

Síntoma: Un servicio falla escrituras aunque la pool tenga mucho espacio libre.

Qué está pasando: El dataset alcanzó quota o refquota. Desde la perspectiva de la app, se quedó sin disco.

Solución: Monitoriza used vs cuotas y alerta temprano. Confirma rápido:

cr0x@server:~$ zfs get -o name,property,value quota,refquota tank/service

Error 5: Hacer garantías más grandes que tu margen de “oh no”

Síntoma: Datasets menos críticos alcanzan ENOSPC constantemente; los equipos empiezan a eludir controles; entras en un ciclo de whack-a-mole.

Qué está pasando: Sobreasignaste espacio garantizado respecto al tamaño de la pool y patrones reales de uso. Las garantías se vuelven contención permanente.

Solución: Suma reservations y refreservations y compara con objetivos realistas de espacio libre de la pool. Quieres que las garantías protejan cargas clave, no estrangulen todo lo demás.

cr0x@server:~$ zfs get -r -H -o value refreservation,reservation tank | awk '
{ if ($1 != "none") sum += $1 }
END { print sum }'

Interpretación: Este enfoque bruto necesita manejo de unidades en scripts reales, pero el punto operativo es claro: las garantías totales deben caber en tu plan de capacidad con margen.

Listas de verificación / plan paso a paso

Checklist A: Introducir refreservation para un servicio crítico (sin sorpresas)

  1. Mide la ráfaga de escritura. Observa el volumen de escritura peor en 1–6 horas del servicio, más sobrecarga y tiempo de respuesta ante incidentes.
  2. Confirma el margen de la pool. Si la pool vive por encima de 85–90%, arregla capacidad primero. Garantías en una pool crónicamente llena son solo mover sillas.
  3. Crea un dataset dedicado. No compartas un dataset entre “escrituras críticas” y “todo lo demás”.
  4. Configura refreservation en el dataset. Empieza modesto y ajusta según comportamiento observado.
  5. Opcionalmente limita a los vecinos ruidosos. Añade quota o refquota a datasets de logs/artefactos para que fallen antes que el nivel-0.
  6. Valida los cambios en disponibilidad. Confirma que el avail de otros datasets no bajó por debajo de umbrales operativos seguros.
  7. Simula el modo de fallo. Llena un dataset no crítico hasta que alcance la cuota y confirma que el dataset crítico sigue escribiendo.

Checklist B: Respuesta a incidente de capacidad cuando una pool tiende a llenarse

  1. Identifica los principales consumidores (zfs list y desglose usedbysnapshots).
  2. Revisa retención de snapshots y elimina los snapshots correctos (no al azar) cuando sea seguro.
  3. Confirma que ningún dataset desbocado esté sin restricciones (sin cuota) mientras datasets críticos carecen de garantías.
  4. Reduce el churn: detén el job que está generando la tormenta de escritura.
  5. Solo entonces considera cambios de propiedad de emergencia (reducciones temporales de cuota, reservas temporales) con pasos de reversión explícitos.

Paso a paso: Una política de “tiering” sensata con refreservation

Este es un patrón práctico que funciona bien en pools corporativas multi-servicio:

  1. Datasets Tier 0 (deben seguir escribiendo): configura refreservation; considera pool dedicada o vdevs especiales si aplica; alerta cuando avail baje por debajo del runway garantizado.
  2. Datasets Tier 1 (importantes pero degradables): cuotas/refquotas moderadas; reservas más pequeñas si hace falta.
  3. Datasets Tier 2 (mejor esfuerzo): las cuotas son obligatorias; snapshots retenidos corto; acepta ENOSPC como fallo controlado.

Preguntas frecuentes

1) ¿Refreservation garantiza espacio libre incluso si la pool está al 99%?

No. Garantiza disponibilidad a nivel de política dentro de la capacidad física de la pool para asignar. Pools casi llenas pueden fallar asignaciones por necesidades de metadata y márgenes operativos de ZFS.

2) ¿Cuál es la forma más sencilla de saber si ENOSPC se debe a cuota o a llenado de la pool?

Comprueba tanto la pool como el dataset:

cr0x@server:~$ zpool list -o name,cap,free
cr0x@server:~$ zfs get -o name,property,value quota,refquota tank/the-dataset

Si la pool tiene espacio libre pero el dataset tiene una quota/refquota cerca del límite, es una restricción del dataset.

3) ¿Por qué eliminar archivos no libera espacio en ZFS?

Porque los snapshots (y a veces los clones) pueden seguir referenciando los bloques. Borrar quita referencias del filesystem vivo, pero los bloques permanecen asignados hasta que nada los referencie.

4) ¿Debo usar refreservation para bases de datos?

A menudo sí para WAL/journals y otros volúmenes críticos para durabilidad, porque son lo primero que tumba el servicio cuando las escrituras fallan. Combínalo con disciplina de snapshots y monitorización de capacidad.

5) ¿Puede refreservation ayudar con “df muestra espacio pero las escrituras fallan”?

Puedes prevenir una clase de fallos—ser “ahogado” por otros datasets—pero no resuelve malas configuraciones de cuotas ni una pool efectivamente llena. Usa zfs list como la fuente de la verdad para la disponibilidad de datasets.

6) ¿Es refreservation lo mismo que preasignar un archivo?

No. Preasignar un archivo (como fallocate) asigna bloques a ese archivo. Refreservation es una garantía a nivel de dataset que reduce lo que otros datasets pueden usar. Es política, no un layout de asignación específico.

7) ¿Cómo interactúan los snapshots con refreservation?

Los snapshots consumen espacio de la pool a medida que el dataset vivo cambia. Refreservation no “reserva espacio para snapshots”, pero ayuda a asegurar que los datos vivos del dataset tengan una pista protegida para crecer.

8) ¿Cómo elijo el tamaño de una refreservation?

Bástate en: tasa máxima de escritura × (tiempo de detección + tiempo de mitigación) más un buffer para margen operativo. Si tu WAL puede crecer 30G en una hora durante una tormenta de replay, reservar 10G es optimismo, no ingeniería.

9) ¿Puedo poner refreservation en un zvol?

Sí, y puede ser especialmente relevante para discos de VM respaldados por zvol donde quieres garantizar espacio backend. Pero considera también volsize y si estás haciendo provisión delgada de hecho.

Conclusión

Refreservation de ZFS no es un código para hacer trampas de capacidad. Es una herramienta de diseño de modos de fallo. En una pool compartida, algo eventualmente intentará comerse todo el espacio disponible—logs, artefactos, una query descontrolada, una “exportación temporal”. Sin garantías, lo que falla primero es lo equivocado y el incidente se convierte en un problema de negocio.

Usa refreservation para mantener encendidos los datasets que deben seguir escribiendo. Combínalo con cuotas para contener a los datasets que no deberían arruinarte el día. Y recuerda la verdad operativa más útil de ZFS: cuando las cuentas de espacio se vuelven raras, casi siempre son snapshots, reservas o ambas—y ZFS te dirá cuál si le preguntas de la manera correcta.

← Anterior
pvedaemon.service falló en Proxmox: por qué las tareas no se ejecutan y cómo solucionarlo
Siguiente →
Controladores Arc: cómo se corrige en público una generación de GPU

Deja un comentario