Instantáneas ZFS: el superpoder que también puede llenar tu pool

¿Te fue útil?

Las instantáneas ZFS son lo más parecido a viajar en el tiempo que tienen los ingenieros de almacenamiento. Te permiten revertir un dataset, recuperar un archivo que alguien “no borró” y enviar datos consistentes a otra máquina sin detener servicios. Puedes tomarlas cada minuto y dormir mejor—hasta que despiertas y el pool está al 98% y el cluster de repente trata a fsync() como una sugerencia.

Este artículo es para quienes gestionan sistemas de producción, no demos de laboratorio. Cubriremos cuánto cuestan realmente las instantáneas, cómo la contabilidad de espacio te engaña (sin scandal), y cómo ejecutar retención sin convertir accidentalmente tu programa de snapshots en un ataque de denegación de servicio a cámara lenta. En el camino: comandos que puedes ejecutar hoy, tres historias corporativas con las que te reconocerás y un plan de diagnóstico rápido para cuando el pool se llena más rápido que la batería de tu pager.

Qué es realmente (y qué no) una instantánea ZFS

Una instantánea ZFS es una referencia de solo lectura al estado de un dataset en un momento dado. ZFS usa copy-on-write: cuando los datos cambian, ZFS escribe nuevos bloques y luego actualiza los metadatos para apuntar a ellos. Los bloques viejos permanecen hasta que nada los referencia. Una instantánea es simplemente “algo más que todavía referencia los bloques viejos”.

Esto explica por qué las instantáneas se crean rápido: ZFS no está copiando tu dataset; está fijando referencias. Y también explica por qué las instantáneas pueden “usar” mucho espacio más tarde: no porque crezcan por sí mismas, sino porque impiden que los bloques viejos se liberen cuando el dataset en vivo cambia.

El modelo mental que evita outages

Piénsalo como una lista de reproducción, no como una carpeta. Los bloques son las canciones. Cuando “editas” la lista, ZFS no edita canciones en el lugar; escribe nuevas canciones y apunta la lista a ellas. Una instantánea es una versión guardada de la lista que sigue apuntando a las canciones viejas. Si sigues editando, sigues acumulando canciones viejas a las que las instantáneas todavía hacen referencia.

Si esa metáfora suena demasiado amable para producción: las instantáneas son “raíces del recolector de basura”. Mantienen vivos los bloques. Si creas muchas raíces y la tasa de cambios es alta, llenarás la memoria. Aquí, la memoria es tu pool.

Las instantáneas no son respaldos (la mayoría de las veces)

Las instantáneas te protegen contra problemas lógicos: eliminaciones accidentales, despliegues malos, ransomware que detectas rápido, o ese script que “solo elimina archivos antiguos” pero tiene un off-by-one en la ruta. Los respaldos te protegen contra problemas físicos y existenciales: pérdida del pool, error del operador que destruye instantáneas, incendio, robo y “migramos el dataset equivocado y no nos dimos cuenta en un mes”.

Puedes convertir instantáneas en respaldos replicándolas en otro lugar (p. ej., zfs send/receive) con retención independiente. Hasta que lo hagas, las instantáneas son una red de seguridad unida a la misma trapecio.

Broma #1: Una instantánea es como “deshacer”, salvo que nunca olvida y te factura en terabytes.

Hechos y contexto: por qué las instantáneas importaron tanto

Algo de contexto histórico y técnico ayuda a explicar por qué el snapshotting de ZFS se siente mágico—y por qué puede sorprender a equipos que vienen de sistemas de archivos tradicionales y LVM.

  1. ZFS salió con instantáneas como característica de primera clase cuando muchos sistemas de archivos trataban las instantáneas como un añadido (gestor de volúmenes, característica de array o herramientas propietarias).
  2. Copy-on-write es el habilitador: ZFS puede instantanear barato porque nunca sobreescribe bloques en vivo en su lugar; escribe bloques nuevos y cambia punteros.
  3. La contabilidad de espacio evolucionó con el tiempo: implementaciones tempranas y herramientas antiguas a menudo confundían “referenciado”, “usado” y tamaños “lógicos”, lo que llevó a dashboards inconsistentes en entornos mixtos.
  4. Los entornos Solaris normalizaron horarios agresivos de instantáneas mucho antes de que los contenedores pusieran de moda la “infraestructura inmutable”; patrones diarios/horarios/minutales eran comunes en flujos de trabajo de NAS empresariales.
  5. Las instantáneas son por dataset, no por pool. Esto importa cuando la gente asume que “una política de retención para todo el pool” se comportará igual en todas partes.
  6. Los clones hicieron las instantáneas más peligrosas (en el buen sentido): un clone depende de su snapshot. Las eliminaciones se bloquean y tu trabajo de “podar snaps antiguos” de repente se vuelve mentiroso.
  7. Imágenes de VM y bases de datos cambiaron las reglas: cargas de trabajo con escrituras aleatorias churnean bloques rápido, haciendo que las instantáneas acumulen bloques referenciados mucho más rápido que una carga mayormente append-only.
  8. “Pool full” se volvió una clase de incidente operativa porque el rendimiento y el comportamiento de asignación de ZFS empeoran drásticamente a alta utilización; no es solo “no hay más espacio”, es “todo se vuelve lento y luego empiezan los errores”.
  9. Las instantáneas baratas complicaron la política de retención: una vez que los equipos saben que puedes mantener 30 días “gratis”, alguien pedirá 365 días “por cumplimiento”.

La verdad incómoda: cómo las instantáneas “usan” espacio

La asunción equivocada más común es: “Las instantáneas son baratas, por lo tanto son pequeñas.” Crearlas es barato. El espacio no lo es necesariamente.

Tres tipos de “tamaño” que verás

ZFS reporta múltiples métricas y responden preguntas distintas:

  • logicalused: cuánto dato está almacenado lógicamente (ignora compresión, copias, etc.).
  • used: cuánto espacio se usa en disco desde la perspectiva de este dataset (incluye cosas como instantáneas dependiendo de flags/propiedades mostradas).
  • referenced: el espacio que se liberaría si el dataset fuera destruido (la vista “única” en vivo, excluyendo el espacio retenido solo por instantáneas).
  • usedbysnapshots / usedbydataset / usedbychildren: un desglose que ayuda a zanjar discusiones en reuniones.

Las instantáneas “usan” el espacio de bloques que ya no son referenciados por el dataset en vivo pero que todavía son referenciados por una o más instantáneas. Eso significa que el uso por instantáneas es proporcional a la tasa de cambio, no al tamaño total del dataset. Un dataset de 10 TB con poco churn puede tener años de instantáneas con sobrecarga modesta; un datastore de VM de 500 GB con alto churn puede comerse un pool en un fin de semana.

Por qué borrar archivos no libera espacio (a veces)

Borras un directorio de 200 GB. Los usuarios aplauden. La monitorización no cambia. Esas son las instantáneas haciendo su trabajo: todavía referencian los bloques, así que el pool no puede liberarlos. Esto también explica por qué los “scripts de limpieza” pueden ser engañosos en sistemas con muchas instantáneas: reducen el espacio referenciado en vivo, pero no la asignación del pool, hasta que se eliminen las instantáneas antiguas.

“Pero solo instantaneamos /var/log, ¿qué tan malo puede ser?”

Los patrones append-only son amigables con instantáneas. Pero muchos sistemas no son append-only:

  • Imágenes de VM: metadata del sistema de archivos invitado churnea, pequeñas escrituras aleatorias, rotación de logs dentro del invitado.
  • Bases de datos: checkpoints y compactaciones pueden reescribir regiones grandes.
  • Caches de build y workspaces de CI: patrones de borrar-y-recrear churnean todo.
  • Capas de contenedores: rebuilds frecuentes; muchos cambios en ficheros pequeños.

El precipicio de “pool lleno” es real

Muchos equipos tratan 95% de utilización como “aún queda 5%”. En ZFS, ese último 5% suele ser donde el rendimiento muere, especialmente en pools con fragmentación, recordsize pequeño o escrituras aleatorias intensas. Las asignaciones de metadata se vuelven más difíciles, el espacio libre se dispersa y cargas que funcionaban bien al 70% empiezan a hacer timeouts al 92%.

Broma #2: ZFS al 98% es como una maleta en el aeropuerto: aún se cierra, pero todos sudan y alguien está a punto de romper la cremallera.

Eliminar instantáneas no siempre libera espacio de inmediato

Destruir instantáneas suele liberar espacio rápido, pero no siempre de la manera que los humanos esperan:

  • Frees pendientes pueden diferir la reclamación real; podrías ver un retraso en el “liberando”.
  • Holds pueden bloquear la eliminación por completo.
  • Clones pueden mantener bloques referenciados incluso después de intentos de eliminación (o prevenir la eliminación).
  • Dispositivos especiales / metadata pueden complicar dónde aparece la presión (p. ej., un vdev especial llenándose mientras el vdev principal parece estar bien).

Tareas prácticas (comandos + interpretación)

Estas son tareas operativas reales que puedes ejecutar durante un día tranquilo para entender la huella de tus instantáneas—o durante un día ruidoso para detener la hemorragia. Los comandos asumen un prompt estilo Linux y las herramientas de OpenZFS.

Tarea 1: Obtener la verdad sobre la capacidad y salud del pool

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

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

errors: No known data errors

Interpretación: Si el pool no está sano, limpiar instantáneas es el movimiento equivocado como primer paso. Un vdev degradado, resilvering o errores de checksum pueden cambiar los síntomas de rendimiento y la tolerancia al riesgo. Los resultados del scrub te dicen si estás lidiando con “presión de espacio” o “presión de integridad de datos”.

cr0x@server:~$ zpool list -o name,size,alloc,free,capacity,health,fragmentation
NAME  SIZE  ALLOC   FREE  CAPACITY  HEALTH  FRAG
tank  20T   17.8T   2.2T      89%  ONLINE    43%

Interpretación: La capacidad y la fragmentación importan juntas. 89% y 43% de fragmentación en un pool con escrituras aleatorias es distinto a 89% y 5% de fragmentación en un pool append-only.

Tarea 2: Listar datasets con desglose consciente de instantáneas

cr0x@server:~$ zfs list -o name,used,avail,refer,usedbysnapshots,usedbydataset,usedbychildren -r tank
NAME              USED  AVAIL  REFER  USEDSNAP  USEDDS  USEDCHILD
tank              17.8T  2.2T   256K   0B       256K    17.8T
tank/home         1.2T   2.2T   980G   220G     980G    0B
tank/vm           12.9T  2.2T   3.1T   9.8T     3.1T    0B
tank/db           3.4T   2.2T   1.9T   1.5T     1.9T    0B

Interpretación: Este es tu titular. tank/vm tiene 9.8T “usado por instantáneas”. Eso no significa que las instantáneas sean copias de 9.8T; significa que esa cantidad de datos antiguos está fijada por instantáneas. La huella en vivo referenciada es solo 3.1T.

Tarea 3: Contar instantáneas por dataset (detector de deriva de retención)

cr0x@server:~$ zfs list -H -t snapshot -o name | awk -F@ '{print $1}' | sort | uniq -c | sort -nr | head
  4320 tank/vm
   720 tank/db
   120 tank/home

Interpretación: 4320 instantáneas suele significar “cada 10 minutos por 30 días” o “cada minuto por 3 días”, dependiendo del esquema de nombres. De cualquier modo: son muchas metadatos y mucha historia fijada si el churn es alto.

Tarea 4: Encontrar las instantáneas más pesadas (por used)

cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -s used | tail -n 10
tank/vm@auto-2025-12-24-2300   48G   3.1T  Wed Dec 24 23:00 2025
tank/vm@auto-2025-12-24-2200   47G   3.1T  Wed Dec 24 22:00 2025
tank/vm@auto-2025-12-24-2100   46G   3.1T  Wed Dec 24 21:00 2025
tank/db@auto-2025-12-24-2300   18G   1.9T  Wed Dec 24 23:00 2025
tank/vm@auto-2025-12-24-2000   44G   3.1T  Wed Dec 24 20:00 2025
tank/vm@auto-2025-12-24-1900   44G   3.1T  Wed Dec 24 19:00 2025
tank/vm@auto-2025-12-24-1800   43G   3.1T  Wed Dec 24 18:00 2025
tank/vm@auto-2025-12-24-1700   42G   3.1T  Wed Dec 24 17:00 2025
tank/db@auto-2025-12-24-2200   16G   1.9T  Wed Dec 24 22:00 2025
tank/vm@auto-2025-12-24-1600   41G   3.1T  Wed Dec 24 16:00 2025

Interpretación: used de la instantánea es “espacio retenido exclusivamente por esta instantánea”. Números grandes suelen indicar churn fuerte entre instantáneas. Si ves docenas de deltas de 40–50G horarios, tu política de retención debe ser conservadora con el tiempo, no con el conteo.

Tarea 5: Ver rápidamente qué datasets son monstruos de churn

cr0x@server:~$ zfs list -o name,refer,usedbysnapshots,compression,recordsize,primarycache -r tank/vm
NAME      REFER  USEDSNAP  COMPRESS  RECSIZE  PRICACHE
tank/vm   3.1T   9.8T      lz4       128K     all

Interpretación: La compresión y el recordsize influyen en la dinámica de churn. Una elección inadecuada de recordsize para imágenes de VM (a menudo mejor en 16K–64K según el caso) puede aumentar la amplificación de escritura y los deltas de instantánea.

Tarea 6: Confirmar si holds están bloqueando la eliminación

cr0x@server:~$ zfs holds tank/vm@auto-2025-12-01-0000
NAME                         TAG        TIMESTAMP
tank/vm@auto-2025-12-01-0000 backup     Wed Dec  1 00:00 2025

Interpretación: Un hold es una fijación explícita de “no borrar”. Si tu trabajo de poda dice que borró instantáneas pero siguen ahí, los holds son un sospechoso principal.

Tarea 7: Liberar un hold (con cuidado) para permitir la poda

cr0x@server:~$ sudo zfs release backup tank/vm@auto-2025-12-01-0000

Interpretación: Esto no borra nada. Quita el seguro. Si un trabajo de replicación usa holds para proteger snapshots “no replicados aún”, coordina antes de liberar. El flujo correcto: confirmar estado de replicación, luego liberar, luego destruir.

Tarea 8: Detectar clones que dependen de instantáneas

cr0x@server:~$ zfs get -H -o name,value origin -r tank | grep -v -- '-'
tank/vm/dev-clone-01    tank/vm@auto-2025-12-15-0000
tank/vm/dev-clone-02    tank/vm@auto-2025-12-20-0000

Interpretación: Si existe un clone, la instantánea origen no puede destruirse hasta que el clone sea promovido o destruido. Los equipos suelen olvidar clones de dev/test y luego se preguntan por qué la retención “dejó de funcionar”.

Tarea 9: Identificar exactamente qué impide la destrucción de una instantánea

cr0x@server:~$ sudo zfs destroy tank/vm@auto-2025-12-15-0000
cannot destroy 'tank/vm@auto-2025-12-15-0000': snapshot has dependent clones

Interpretación: ZFS te está diciendo la verdad. Tu política de retención ahora es un problema de grafo de dependencias. O quitas los clones, los promueves, o cambias la política para conservar los orígenes más tiempo.

Tarea 10: Borrar instantáneas en una ventana controlada

cr0x@server:~$ sudo zfs destroy tank/vm@auto-2025-12-01-0000

Interpretación: Destruir una instantánea a la vez es más lento pero más seguro cuando estás aprendiendo el entorno. Una vez confíes en tus reglas de nombres y dependencias, puedes borrar rangos o usar scripting—pero solo después de probar los resultados.

Tarea 11: Borrar un rango de instantáneas por patrón (quirúrgico, no casual)

cr0x@server:~$ zfs list -H -t snapshot -o name -s creation | grep '^tank/vm@auto-2025-11' | head -n 5
tank/vm@auto-2025-11-01-0000
tank/vm@auto-2025-11-01-0100
tank/vm@auto-2025-11-01-0200
tank/vm@auto-2025-11-01-0300
tank/vm@auto-2025-11-01-0400

cr0x@server:~$ zfs list -H -t snapshot -o name -s creation | grep '^tank/vm@auto-2025-11' | wc -l
720

cr0x@server:~$ zfs list -H -t snapshot -o name -s creation | grep '^tank/vm@auto-2025-11' | sudo xargs -n 50 zfs destroy

Interpretación: Primero mostrar, luego contar, luego destruir. El fragmentado -n 50 evita “argument list too long”. Si alguna instantánea en la lista tiene holds o clones, el comando fallará en esas; necesitas inspeccionar los fallos y no asumir que todo el lote tuvo éxito.

Tarea 12: Vigilar la reclamación de espacio tras los borrados (y no entrar en pánico)

cr0x@server:~$ zpool list -o name,alloc,free,capacity
NAME  ALLOC   FREE  CAPACITY
tank  17.8T   2.2T      89%

cr0x@server:~$ sudo zfs destroy tank/vm@auto-2025-11-01-0000

cr0x@server:~$ zpool list -o name,alloc,free,capacity
NAME  ALLOC   FREE  CAPACITY
tank  17.7T   2.3T      88%

Interpretación: La reclamación puede ser gradual. Si estás bajo presión, borra lo suficiente para recuperar un margen seguro (a menudo 15–20% libre según la carga), no “solo una instantánea”.

Tarea 13: Encontrar datasets con reservas inesperadas (espacio que no puede usarse)

cr0x@server:~$ zfs get -o name,property,value -r tank | egrep 'refreservation|reservation' | grep -v '0$'
tank/vm  refreservation  2T

Interpretación: Un refreservation puede hacer que un pool parezca “más lleno” porque es espacio garantizado. Esto no es un problema de instantáneas, pero a menudo aparece durante un incidente de instantáneas porque todos miran “¿dónde se fue mi espacio libre?”

Tarea 14: Medir la tasa de creación de instantáneas y salud de send/receive (entornos con replicación)

cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation | tail -n 5
tank/vm@auto-2025-12-24-2000  Wed Dec 24 20:00 2025
tank/vm@auto-2025-12-24-2100  Wed Dec 24 21:00 2025
tank/vm@auto-2025-12-24-2200  Wed Dec 24 22:00 2025
tank/vm@auto-2025-12-24-2300  Wed Dec 24 23:00 2025
tank/vm@auto-2025-12-25-0000  Thu Dec 25 00:00 2025

Interpretación: Si las instantáneas llegan pero la replicación no puede seguir el ritmo, acumularás holds “mantener hasta replicado” (manuales o gestionados por herramientas) y la retención quedará estancada. Operativamente, la “explosión de instantáneas” suele ser un problema de lag de replicación disfrazado de almacenamiento.

Guion rápido de diagnóstico: cuellos de botella y uso descontrolado

Esta es la secuencia para cuando suena el pager. El objetivo es identificar si lidias con (a) agotamiento real de espacio, (b) fallo de retención de instantáneas, (c) reservas/presión en vdev especial, o (d) colapso de rendimiento por estar casi lleno y fragmentado.

Primero: confirmar el radio de impacto

  1. Capacidad y salud del pool: comprueba zpool list y zpool status.
  2. ¿Es un dataset o varios? comprueba zfs list -o name,usedbysnapshots,refer -r POOL.
  3. ¿Alguna presión en vdev especial? si usas un dispositivo especial, míralo en zpool status y compara los síntomas del pool con cargas ricas en metadata.

Segundo: decidir si son “bloques fijados por instantáneas” o “otra cosa”

  1. Huella de instantáneas: datasets con alto usedbysnapshots suelen ser los culpables.
  2. Deriva en el conteo de instantáneas: contar instantáneas por dataset; picos repentinos suelen significar que el trabajo de retención falló, el nombre cambió o el horario se duplicó.
  3. Reservas: comprueba refreservation/reservation; no borres instantáneas para compensar una reserva que alguien puso hace meses.

Tercero: identificar qué impide la limpieza

  1. Holds: ejecuta zfs holds en las instantáneas más viejas que esperas borrar.
  2. Clones: comprueba origin entre descendientes; los clones bloquean la destrucción.
  3. Lag de replicación: si las instantáneas se mantienen para replicación, verifica la canalización de replicación antes de liberar holds.

Cuarto: estabilizar, luego optimizar

  1. Estabilizar: libera espacio suficiente para evitar el precipicio de casi lleno. Si estás por encima de ~90%, apunta a bajar rápidamente por debajo de ese umbral de forma segura.
  2. Detener la hemorragia: pausa los horarios de instantáneas o reduce la frecuencia para datasets con alto churn mientras investigas.
  3. Luego afina: revisa recordsize, colocación de cargas, frecuencia/retención de instantáneas y la arquitectura de replicación.

Tres mini-historias del mundo corporativo

1) El incidente provocado por una suposición equivocada: “Las instantáneas son básicamente gratis”

Empezó como un proyecto sensato de modernización: mover un clúster de virtualización legacy a almacenamiento respaldado por ZFS para obtener checksumming, compresión y—la palabra favorita de todos—instantáneas. El equipo puso instantáneas horarias en el dataset de VM y mantuvo 30 días. Esa política había funcionado en un servidor de archivos durante años, así que parecía segura.

La suposición equivocada no era sobre la corrección de ZFS; era sobre el churn de la carga. Un datastore de VM no es un servidor de archivos. Los sistemas invitados hacen escrituras pequeñas constantes, actualizan metadata, rotan logs y reescriben partes de discos virtuales que “parecen inactivas” a nivel de aplicación. El dataset ZFS no era enorme, pero cambiaba por todas partes, todo el tiempo.

Dos semanas después, el pool llegó a finales de 80. Luego a finales de 90. La latencia subió primero—pequeñas escrituras síncronas quedando atascadas detrás de presión de asignación y fragmentación. Los tiempos de arranque de VMs se volvieron raros. VMs de bases de datos empezaron a lanzar timeouts. Las gráficas de almacenamiento parecían un monitor cardíaco después de un espresso.

La primera reacción del equipo fue buscar “el archivo grande” y borrarlo. Eso liberó casi nada, porque bloques viejos estaban fijados en cientos de instantáneas horarias. Solo después de ejecutar un desglose consciente de instantáneas el patrón fue obvio: usedbysnapshots estaba cargando el pool.

La solución no fue heroica. Fue limpieza controlada y un reajuste de políticas: menos instantáneas en datasets con alto churn, retenciones más cortas para instantáneas de alta frecuencia y replicación a otra máquina para puntos de recuperación a largo plazo. La lección: las instantáneas son baratas de crear, caras de mantener bajo churn—y tu carga decide la factura.

2) La optimización que rebotó: “Hagamos instantáneas cada minuto”

Otra organización tenía un problema real de negocio: los desarrolladores restauraban entornos de prueba con frecuencia, y el equipo de infra quería recuperaciones más rápidas sin restaurar desde backups. Alguien propuso instantáneas a nivel de minuto para un puñado de datasets. En papel era elegante: más instantáneas, reducir la granularidad de rollback, reducir tiempo de reconstrucción.

Por un tiempo funcionó. El equipo celebró la primera gran salvada: una migración de esquema rota en staging, revertida en segundos. Ese éxito creó un incentivo sutil: “Si instantáneas por minuto son buenas, ¿por qué no en todas partes?” Más datasets se unieron al horario. Nadie quería ser el equipo sin red de seguridad.

Entonces rebotó: overhead de metadata de instantáneas y complejidad operativa. Listar instantáneas se volvió lento en datasets con muchas instantáneas; scripts que asumían “unas pocas docenas” comenzaron a hacer timeout. El lag de replicación creció porque los streams incrementales tenían que atravesar más fronteras de instantáneas, y el lado receptor empezó a quedarse atrás en horas pico.

Y esto fue lo que más les sorprendió: la frecuencia de instantáneas no redujo el uso de espacio como esperaban. Con una carga de alto churn, instantáneas por minuto pueden de hecho aumentar la diversidad de bloques retenidos: más versiones intermedias quedan fijadas, menos bloques llegan a ser “completamente obsoletos” hasta que borres un slice mucho mayor de historia. Los deltas eran pequeños, pero eran tantos que el conjunto retenido se mantuvo grande.

La solución fue contraintuitiva: menos instantáneas, pero en niveles. Mantener instantáneas cada minuto por una ventana corta (horas), horarias por una ventana media (días), diarias por más tiempo (semanas). Y para datasets que necesitaban “recuperación oops”, movieron los flujos de trabajo más peligrosos (como refrescos de BD de prueba) a datasets separados para que el churn no envenenara todo lo demás.

3) La práctica aburrida pero correcta que salvó el día: “Retención con guardrails”

Esta casi decepciona porque no es dramática. Una compañía vinculada a finanzas corría ZFS en servidores que alojaban tanto homes de usuarios como datos de aplicaciones. Su política de instantáneas era conservadora y francamente poco sexy: instantáneas horarias mantenidas 48 horas, diarias 30 días, mensuales 12 meses. También tenían dos reglas aburridas: las instantáneas se nombran previsiblemente y la eliminación siempre va precedida por un informe de inventario.

Un viernes, un bug en un despliegue corrompió estado de aplicación de manera no inmediata. La app siguió funcionando, pero la calidad de datos se degradó. El lunes, el negocio lo notó. Este es exactamente el escenario donde “restaurar desde la última noche” no basta—necesitas múltiples puntos en el tiempo para delimitar cuándo empezó la corrupción.

El equipo de infra no debatió si existían instantáneas ni si el horario corrió. Ya tenían puntos diarios y horarios, y scripts que podían listar y comparar candidatas a instantáneas. Montaron una instantánea, validaron invariantes a nivel de aplicación y avanzaron paso a paso hasta encontrar el último estado bueno.

Recuperaron sin llenar el pool, sin inventar un proceso nuevo en medio del incidente y sin el clásico “tenemos instantáneas pero no sabemos qué contienen”. La parte poco glamorosa que importó: también tenían un guardrail duro de capacidad—alertas al 75/80/85% con un runbook explícito—así que el pool nunca se acercó al precipicio mientras hacían restauraciones forenses.

La gente ama comprar confiabilidad con funciones. Ellos salvaron el día con hábitos.

Errores comunes: síntomas y soluciones

Error 1: Confundir “referenced” con “used” y declarar victoria demasiado pronto

Síntoma: Borras directorios grandes, zfs list muestra refer menor, pero zpool list cambia poco.

Causa: Las instantáneas retienen bloques viejos. El dataset en vivo se redujo; la asignación del pool no.

Solución: Revisa usedbysnapshots y poda instantáneas según la política de retención. Valida que no haya holds/clones bloqueando la eliminación.

Error 2: Podar instantáneas a ciegas con un patrón de nombre que no verificaste

Síntoma: El job de retención borra las instantáneas equivocadas (o ninguna), o borra las más nuevas y conserva las antiguas.

Causa: Cambió el formato de nombres, cambiaron zonas horarias, múltiples herramientas escriben prefijos distintos, o el orden lexicográfico no coincide con el orden temporal.

Solución: Ordena por creation no por nombre; prueba con un listado en seco antes de destruir. Prefiere zfs list -s creation como fuente de la verdad.

Error 3: Ignorar clones y luego preguntarse por qué falla la destrucción

Síntoma: cannot destroy ... snapshot has dependent clones

Causa: Alguien creó un clone para dev/test o trabajo forense y lo olvidó.

Solución: Encuentra clones con zfs get origin. Decide: destruir el clone, o promoverlo si debe vivir independientemente, y luego ajustar la retención.

Error 4: Holds usados por replicación, pero nadie monitoriza el lag de replicación

Síntoma: Crece el conteo de instantáneas; las eliminaciones fallan silenciosamente; la edad de la “instantánea más antigua” aumenta.

Causa: Las herramientas de replicación aplican holds hasta que una instantánea se transfiere con seguridad; la replicación se atrasa y el conjunto de holds crece.

Solución: Monitoriza la replicación de extremo a extremo. Durante la respuesta a incidentes, confirma la última instantánea replicada antes de liberar holds. Arregla la canalización en vez de pelear con los síntomas.

Error 5: Mantener el pool demasiado caliente

Síntoma: Picos de latencia, ralentización en asignación, a veces errores tipo ENOSPC mientras “df muestra espacio”.

Causa: Alta utilización y fragmentación del pool provocan colapso de rendimiento, especialmente en escrituras aleatorias.

Solución: Recuperar margen. Establecer SLOs operativos para capacidad (alertar temprano). Reevaluar retención de instantáneas y colocación de cargas.

Error 6: Tratar un vdev especial de metadata como una mejora mágica de rendimiento

Síntoma: El pool principal muestra espacio libre, pero el sistema aún falla escrituras o colapsa; el vdev especial está lleno.

Causa: El vdev especial se llenó (metadata / bloques pequeños). Las instantáneas y el churn de archivos pequeños pueden amplificar la presión de metadata.

Solución: Monitoriza la asignación del vdev especial. Mantén margen allí también. Considera ajustar special_small_blocks y las políticas de instantáneas, y planifica capacidad para el crecimiento de metadata.

Listas de verificación / plan paso a paso

Paso a paso: construir una política de retención de instantáneas que no devore tu pool

  1. Clasifica datasets por churn: imágenes de VM, bases de datos, caches de CI, homes de usuarios, logs. No apliques un mismo horario a todos.
  2. Define objetivos de recuperación: “Quiero rollback horario por dos días” es un requisito. “Guardar todo para siempre” es un deseo.
  3. Usa retención por niveles: ventana corta de alta frecuencia + ventana larga de baja frecuencia. Así obtienes granularidad sin fijación indefinida.
  4. Separa cargas riesgosas: coloca caches de CI y espacio scratch en datasets propios con podas agresivas.
  5. Haz nombres de instantáneas predecibles: prefijo consistente + timestamp tipo ISO. La predictibilidad evita bugs de eliminación.
  6. Decide cómo manejar holds/clones: documenta quién puede clonar, cuánto tiempo viven los clones y cómo se protegen los orígenes.
  7. Añade guardrails de capacidad: alertas al 75/80/85% y una política dura de “parar creación de instantáneas en X%” para datasets no críticos.
  8. Ensaya restaurar: montar una instantánea y restaurar un archivo debe ser rutinario, no un proyecto nocturno.

Paso a paso: recuperar espacio de forma segura durante un incidente de capacidad relacionado con instantáneas

  1. Congelar cambios: pausa los horarios de creación de instantáneas si están empeorando la situación (especialmente jobs minutely).
  2. Encontrar los mayores consumidores de instantáneas: zfs list -o name,usedbysnapshots -r POOL.
  3. Identificar bloqueadores: holds y clones sobre las instantáneas más antiguas que quieres eliminar.
  4. Borrar las instantáneas más antiguas primero: suelen fijar la historia más amplia. Evita borrar “puntos de recuperación recientes” a menos que sea necesario.
  5. Recomprobar capacidad del pool: no te quedes en “fue de 98% a 96%”. Recupéra un margen seguro.
  6. Arreglo post-incidente: ajusta niveles de retención, afina la frecuencia por clase de dataset y arregla el lag de replicación si aplica.

Paso a paso: auditoría rutinaria semanal (la práctica aburrida)

  1. Revisa zpool list y tendencias de fragmentación.
  2. Revisa los principales datasets por usedbysnapshots.
  3. Comprueba conteos de instantáneas por dataset; marca outliers.
  4. Busca instantáneas antiguas con holds inesperados.
  5. Escanea clones olvidados y decide si deben promoverse o eliminarse.

Preguntas frecuentes

1) ¿Las instantáneas ZFS copian todo el dataset?

No. Fijan referencias a los bloques existentes. El impacto en espacio viene de cambios posteriores: los bloques viejos no pueden liberarse mientras las instantáneas los referencien.

2) ¿Por qué zfs list muestra mucho uso de instantáneas en un dataset que “no ha cambiado mucho”?

Algo cambió más de lo que piensas. Imágenes de VM, bases de datos y cargas de archivos pequeños churnean bloques incluso cuando los datos a nivel de app parecen estables. Además verifica que leas usedbysnapshots y no lo confundas con refer.

3) Si borro un directorio grande, ¿cuándo recupero el espacio?

Lo recuperas cuando ninguna instantánea referencia esos bloques. Si existen instantáneas anteriores al borrado, los bloques permanecen fijados hasta que esas instantáneas se destruyan (o hasta que salgan de la retención).

4) ¿Por qué no puedo destruir una instantánea?

Razones comunes: tiene clones dependientes o tiene holds. Comprueba con zfs holds SNAP y encuentra clones usando zfs get origin -r.

5) ¿Borrar instantáneas dañará el rendimiento?

Borrar muchas instantáneas puede generar IO y trabajo de CPU, especialmente en sistemas ocupados, y puede competir con la carga. Pero la alternativa—operar casi lleno—suele ser peor. Haz borrados masivos en lotes controlados y observa la latencia.

6) ¿Más instantáneas con mayor frecuencia son siempre mejores?

No. Más instantáneas mejoran la granularidad de recuperación, pero pueden aumentar el overhead de metadata y mantener más versiones intermedias fijadas. La retención por niveles suele superar a “instantáneas cada minuto para siempre”.

7) ¿Cuánto espacio libre debo mantener en un pool ZFS?

No hay un número único, pero muchos equipos de producción tratan ~80–85% como techo blando para cargas mixtas, y menos para pools con muchas escrituras aleatorias. Lo que importa es dejar suficiente espacio libre relativamente contiguo para evitar problemas de asignación y espirales de fragmentación.

8) ¿Las instantáneas protegen contra ransomware?

Las instantáneas pueden proteger contra ransomware que encripta archivos—si el atacante no puede borrar las instantáneas. Si los atacantes obtienen acceso privilegiado, pueden destruir instantáneas también. Replica instantáneas a un sistema separado con credenciales restringidas y retención independiente si quieres resiliencia real.

9) ¿Por qué el “used” de instantáneas difiere entre servidores?

Las diferencias pueden venir de defaults de reporte de propiedades, feature flags, compresión, recordsize y churn de la carga. Compara siempre usando columnas explícitas (p. ej., usedbysnapshots) y comandos consistentes.

10) ¿Está bien instantanear bases de datos?

Sí, con cuidado. Para instantáneas consistentes a nivel de crash, puede que necesites coordinación de la aplicación (flush/checkpoint) según la BD y expectativas de recuperación. También espera mayor churn y planifica la retención en consecuencia.

Conclusión

Las instantáneas ZFS son un superpoder porque convierten el tiempo en una primitiva operacional: puedes crear puntos de restauración consistentes rápidamente, a menudo sin pausar cargas. La trampa es que el tiempo no es gratis. Cada instantánea es una promesa de recordar bloques antiguos, y los datasets con alto churn acumularán esas promesas como interés.

Ejecuta instantáneas como cualquier otra función de producción: mide la tasa de cambio, clasifica datasets, establece retención por niveles, monitoriza la capacidad con anticipación y trata holds/clones como dependencias de primera clase. Haz eso y las instantáneas seguirán siendo lo que se supone que deben ser: el “deshacer” más rápido que hayas usado—sin convertir tu pool en un vertedero.

← Anterior
Debian 13: AppArmor bloquea tu servicio — permite solo lo necesario sin desactivar la seguridad
Siguiente →
MySQL vs PostgreSQL: réplicas de lectura — cuándo ayudan y cuándo mienten

Deja un comentario