Eliminar un snapshot ZFS debería ser aburrido: zfs destroy pool/fs@snap, hecho. Pero en sistemas reales suele ser una escena de serie policial: la instantánea está “borrada” y, sin embargo, el espacio no vuelve, o el destroy falla porque algo—en algún lugar—aún la “necesita”.
Esta es una guía de campo para esos momentos. No es un folleto. Cubriremos las razones técnicas por las que las instantáneas se niegan a desaparecer (holds, clones, datasets ocupados, destrucción diferida, replicación, contabilidad de espacio) y las soluciones operativas que funcionan cuando tu pager ya está encendido.
Qué es realmente un snapshot ZFS (y por qué eliminarlo no es “gratuito”)
Un snapshot ZFS no es una copia de tus ficheros. Es una vista congelada de un dataset en un límite de grupo de transacciones: un conjunto de punteros a bloques que dice “estos bloques definen el sistema de ficheros en ese momento”. Cuando modificas datos en vivo, ZFS escribe nuevos bloques en otro lugar (copy-on-write). Los bloques antiguos siguen referenciados por el snapshot. Si borras el snapshot, esos bloques antiguos pueden quedar sin referencias y ser elegibles para liberarse—si nada más sigue apuntando a ellos.
Por eso la eliminación de snapshots tiene dos modos de fallo diferentes:
- La operación destroy queda bloqueada (holds, clones, “dataset is busy”). Aún no puedes eliminar la metadata del snapshot.
- La operación destroy tiene éxito pero el espacio no vuelve (porque los bloques siguen referenciados por otros snapshots, clones, o por una mala interpretación de la contabilidad de espacio).
También significa que la eliminación puede ser costosa. ZFS puede necesitar recorrer metadata para determinar qué bloques se vuelven libres. Árboles grandes de snapshots con años de cambios pueden hacer que los destroys tarden minutos—o horas—dependiendo de la carga del pool, la latencia del almacenamiento y las banderas de función.
Una verdad operativa: cuando la gente dice “los snapshots son baratos”, quiere decir “crear snapshots es barato”. El recibo aparece al eliminarlos.
Datos interesantes y contexto histórico (los sentirás en producción)
- Los snapshots ZFS vienen de Sun Microsystems y se diseñaron como una primitiva para cloning, rollback y replicación—mucho antes de que “copias inmutables” fuera lenguaje de marketing.
- Copy-on-write es la razón por la que los snapshots existen sin pausar escrituras: puedes tomar un snapshot de un dataset de base de datos en vivo sin congelar I/O, porque las nuevas escrituras van a bloques nuevos.
- Los nombres de snapshots forman parte del namespace del dataset:
pool/fs@snapno es un tipo de objeto separado como ocurría con snapshots LVM; está profundamente ligado a la contabilidad del dataset. - Los clones son snapshots escribibles: un clone es un dataset que inicialmente comparte todos los bloques con un snapshot; esa dependencia es lo que hace que algunos snapshots sean “no eliminables”.
- Los “holds” se introdujeron para evitar borrados accidentales durante flujos como replicación, verificación de backups y aprovisionamiento basado en snapshots.
- La destrucción diferida existe porque borrar puede ser lento: ZFS puede marcar un snapshot para limpieza posterior para que el comando responda rápido mientras la liberación ocurre de forma asíncrona.
- El espacio no es un único número en ZFS: “used”, “refer”, “logicalused”, “written”, “usedbysnapshots” y “usedbychildren” responden a preguntas distintas. La gente elige mal bajo presión.
- La compresión cambia la intuición: un snapshot puede “retener” bloques que parecen enormes lógicamente pero pequeños físicamente—o viceversa con cambios en recordsize y reescrituras.
Y un pequeño chiste, porque nos lo ganamos: los snapshots ZFS son como las sillas de oficina—fáciles de añadir, curiosamente difíciles de quitar, y sólo notas el coste cuando el pasillo está bloqueado.
Guía de diagnóstico rápido (revisa esto primero, segundo, tercero)
Esta es la secuencia que uso cuando alguien dice, “Borramos snapshots pero el espacio no volvió”, o “Destroy falla y no sabemos por qué”. El objetivo es encontrar el cuello de botella rápido, no admirar la complejidad filosófica del pool.
1) ¿El snapshot realmente desapareció, o está en destrucción diferida?
Primero comprueba si estás ante una situación de destrucción diferida. ZFS puede aceptar el destroy pero liberar bloques más tarde.
2) ¿Hay holds?
Los holds son el culpable n.º 1 de “no se elimina” en entornos disciplinados (el software de backup/replicación los adora). También son el culpable n.º 1 de “nadie recuerda haberlos puesto”.
3) ¿Hay dependencia por clones?
Si se creó algún clone a partir de un snapshot, no puedes destruir ese snapshot hasta que el clone sea promovido o destruido. En muchas empresas, un desarrollador “temporalmente” clonó datos de producción para pruebas y convirtió la limpieza de snapshots en una negociación de rehenes.
4) Si el snapshot está destruido, ¿por qué no vuelve el espacio?
Comprueba usedbysnapshots, y verifica si otros snapshots aún referencian los mismos bloques sobrescritos. También asegura que estés mirando el dataset correcto y no confundas uso a nivel de pool y a nivel de dataset.
5) ¿El pool está degradado o bajo carga extrema?
Un pool degradado, alta fragmentación o IOPS saturados puede hacer que los destroys vayan lentos. La eliminación de snapshots consume mucha metadata; compite con tus cargas reales.
6) ¿Borraste snapshots en el lado incorrecto de la replicación?
Las topologías de replicación pueden mantener snapshots vivos: el emisor los retiene para satisfacer cadenas incrementales, el receptor los conserva porque los anclaste, y ambos se echan la culpa mutuamente.
Por qué las instantáneas se niegan a morir: causas reales
Causa A: Holds (holds de usuario, de herramientas, “es por tu bien”)
Un hold es una etiqueta adjunta a un snapshot que impide su destrucción. Lo verás cuando zfs destroy falle con un mensaje sobre holds, o cuando una herramienta de borrado “omite snapshots protegidos”. Los holds son excelentes—hasta que quedan huérfanos por un job que se estrelló, un sistema de backup parcialmente migrado, o un script que etiqueta snapshots pero nunca los desetiqueta.
En el terreno, los holds aparecen como:
- Canales de replicación que mantienen snapshots hasta que la recepción termina.
- Jobs de verificación de backup que mantienen snapshots hasta que terminan las sumas de comprobación.
- Holds de “seguridad” añadidos por admins durante un incidente y olvidados.
Causa B: Dependencias por clones (el bloqueador más silencioso)
Si un snapshot tiene un clone, ese snapshot forma parte de la ascendencia del clone. ZFS se negará a destruirlo porque rompería las referencias de bloques del clone. Puedes identificarlo verificando la propiedad clones del snapshot. La solución es destruir el clone, o promover el clone para que se convierta en el nuevo origen y la dependencia cambie.
Este es el caso más común de “no entendemos por qué falla” en equipos mixtos, porque la persona que borra snapshots a menudo no sabe que alguien creó un clone hace meses.
Causa C: Errores de «dataset busy» (montado, en uso o casos especiales)
La mayor parte del tiempo puedes destruir snapshots de datasets montados sin problema. Pero “dataset is busy” puede ocurrir cuando intentas destruir un filesystem o volumen con referencias activas, o cuando intentas destruir snapshots durante ciertas operaciones (como una recepción en curso en algunos flujos, dependiendo de la plataforma y flags).
Además, ten cuidado con zfs destroy -r o -R: podrías estar destruyendo datasets (no sólo snapshots) y topar con uso de puntos de montaje, exports NFS, jails/zones o runtimes de contenedores que anclaron los puntos de montaje.
Causa D: Destrucción diferida (se “borró”, pero el pool no respiró)
La destrucción diferida permite a ZFS eliminar rápidamente el snapshot del namespace mientras pospone el trabajo real de liberar bloques. No es magia; es una decisión de planificación. Si el pool está bajo carga, la limpieza puede retrasarse. Los operadores ven “el snapshot ya no existe” y asumen que el espacio debería volver al instante. Puede que no.
La destrucción diferida suele activarse con zfs destroy -d, pero también puede aparecer como comportamiento cuando el sistema no quiere bloquear demasiado el comando (la implementación depende de la plataforma y flags).
Causa E: Conceptos erróneos sobre la contabilidad de espacio (liberaste espacio—simplemente no donde miras)
ZFS informa espacio en múltiples niveles:
- a nivel de pool espacio libre: lo que el pool puede asignar.
- a nivel de dataset “used”: incluye hijos y snapshots según propiedades y perspectiva.
- usedbysnapshots: bloques retenidos únicamente por snapshots para ese dataset.
- referenced: lo que el dataset apunta en ese momento (excluyendo snapshots).
Una realidad común: borras un montón de snapshots y zfs list sigue mostrando que “used” casi no cambia porque el dataset en vivo (u otros snapshots) todavía referencia la mayoría de los bloques. Esto es especialmente común cuando la carga es de append (logs) en lugar de sobrescritura.
Causa F: Cadenas de replicación y dependencias incrementales
zfs send incremental necesita un snapshot común entre origen y destino. Si borras “el snapshot equivocado” en cualquiera de los lados, rompes la cadena y fuerzas un envío completo la próxima vez. Para evitarlo, muchas herramientas de replicación retienen snapshots. Si anulas la retención manualmente, puedes ganar unos gigabytes y perder un fin de semana volviendo a sembrar.
Causa G: Estás borrando demasiado, demasiado rápido (operacionalmente correcto pero físicamente doloroso)
Destruir miles de snapshots a la vez puede crear una ráfaga desagradable de trabajo sobre metadata. En pools ocupados—especialmente con discos HDD—esto puede parecer un incidente de rendimiento. ZFS no está siendo quisquilloso; está haciendo la contabilidad que pediste. La solución es limitar, agrupar o diferir.
Segundo chiste (y último): Las políticas de retención de snapshots son como las dietas—fáciles de empezar, difíciles de mantener, y todo el mundo miente sobre cuántas llevan.
Tareas prácticas: comandos, salidas y qué significan
A continuación se presentan tareas concretas que he ejecutado en situaciones reales. Los comandos son herramientas estándar de ZFS; las salidas son representativas. Tu plataforma (OpenZFS en Linux, FreeBSD, illumos) puede diferir ligeramente, pero el flujo se mantiene.
Tarea 1: Confirma que el snapshot existe (y que lo estás escribiendo bien)
cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -s creation pool/app
NAME USED REFER CREATION
pool/app@auto-2025-12-24 12G 1.20T Wed Dec 24 02:00 2025
pool/app@auto-2025-12-25 14G 1.21T Thu Dec 25 02:00 2025
Interpretación: Tienes dos snapshots. USED es cuánto espacio consume exclusivamente ese snapshot comparado con el head del dataset y otros snapshots.
Tarea 2: Intenta un destroy normal y lee el error literalmente
cr0x@server:~$ sudo zfs destroy pool/app@auto-2025-12-24
cannot destroy snapshot pool/app@auto-2025-12-24: snapshot has holds
Interpretación: Esto no es un misterio. Tiene holds. No empieces a adivinar “busy”. Ve a comprobar los holds.
Tarea 3: Lista los holds en un snapshot
cr0x@server:~$ sudo zfs holds pool/app@auto-2025-12-24
NAME TAG TIMESTAMP
pool/app@auto-2025-12-24 repl-inflight Thu Dec 25 02:05 2025
pool/app@auto-2025-12-24 backup-verify Thu Dec 25 02:10 2025
Interpretación: Dos sistemas diferentes creen que aún necesitan este snapshot. Es una buena noticia: tienes nombres para rastrear.
Tarea 4: Liberar un hold (con seguridad y con intención)
cr0x@server:~$ sudo zfs release backup-verify pool/app@auto-2025-12-24
cr0x@server:~$ sudo zfs holds pool/app@auto-2025-12-24
NAME TAG TIMESTAMP
pool/app@auto-2025-12-24 repl-inflight Thu Dec 25 02:05 2025
Interpretación: Eliminaste una etiqueta. Si un hold pertenece a un job de replicación o backup, liberarlo prematuramente puede romper garantías. Coordina o confirma que el job está muerto/atorado.
Tarea 5: Forzar el destroy (no recomendado, pero conoce lo que hace)
cr0x@server:~$ sudo zfs destroy -f pool/app@auto-2025-12-24
cannot destroy snapshot pool/app@auto-2025-12-24: snapshot has holds
Interpretación: -f no es “ignorar holds”. Los holds existen precisamente para prevenir esto. Debes release los holds o eliminar las condiciones dependientes.
Tarea 6: Comprobar si un snapshot tiene clones
cr0x@server:~$ zfs get -H -o value clones pool/app@auto-2025-12-24
pool/dev/app-clone
Interpretación: Este snapshot es el origen de un dataset clone. No puedes destruir el snapshot hasta que gestiones el clone.
Tarea 7: Inspeccionar el clone y su origen
cr0x@server:~$ zfs get -o name,property,value origin pool/dev/app-clone
NAME PROPERTY VALUE
pool/dev/app-clone origin pool/app@auto-2025-12-24
Interpretación: Linaje claro. Si este clone aún se necesita, considera promoverlo. Si es prescindible, destrúyelo.
Tarea 8: Promover un clone para romper la dependencia (cuando necesitas el clone, no el snapshot origen)
cr0x@server:~$ sudo zfs promote pool/dev/app-clone
cr0x@server:~$ zfs get -o name,property,value origin pool/dev/app-clone
NAME PROPERTY VALUE
pool/dev/app-clone origin -
Interpretación: Después de la promoción, el clone se convierte en un dataset independiente (su origin queda vacío). El antiguo origen puede ahora mostrar un origin apuntando de vuelta, dependiendo del linaje. Vuelve a comprobar la lista de clones en el snapshot que quieres eliminar.
Tarea 9: Destruir un snapshot ahora que holds/clones están resueltos
cr0x@server:~$ sudo zfs release repl-inflight pool/app@auto-2025-12-24
cr0x@server:~$ sudo zfs destroy pool/app@auto-2025-12-24
Interpretación: Si esto tiene éxito y el snapshot desaparece de zfs list -t snapshot, eliminaste la entrada del namespace. La recuperación de espacio puede aún llevar tiempo.
Tarea 10: Verificar si el espacio está realmente retenido por snapshots
cr0x@server:~$ zfs get -o name,property,value -s local,default used,usedbysnapshots,usedbydataset,referenced pool/app
NAME PROPERTY VALUE
pool/app used 3.10T
pool/app usedbysnapshots 420G
pool/app usedbydataset 2.68T
pool/app referenced 2.68T
Interpretación: Si usedbysnapshots es grande, eliminar snapshots puede ayudar. Si es pequeño, la eliminación de snapshots no te rescatará; el propio dataset es el que ocupa espacio.
Tarea 11: Identificar qué snapshots consumen más espacio
cr0x@server:~$ zfs list -t snapshot -o name,used,refer -s used pool/app | tail -n 5
pool/app@auto-2025-10-01 85G 1.05T
pool/app@auto-2025-11-01 92G 1.10T
pool/app@auto-2025-11-15 97G 1.12T
pool/app@auto-2025-12-01 110G 1.18T
pool/app@auto-2025-12-15 140G 1.20T
Interpretación: Estos son buenos candidatos para poda si la política lo permite. Normalmente los picos en USED correlacionan con grandes reescrituras, compactaciones, churn de imágenes VM o mantenimiento de bases de datos.
Tarea 12: Eliminar snapshots por patrón en lotes (con cuidado)
cr0x@server:~$ zfs list -H -t snapshot -o name -s creation pool/app | grep '@auto-2025-10' | head
pool/app@auto-2025-10-01
pool/app@auto-2025-10-02
pool/app@auto-2025-10-03
pool/app@auto-2025-10-04
pool/app@auto-2025-10-05
cr0x@server:~$ zfs list -H -t snapshot -o name -s creation pool/app | grep '@auto-2025-10' | xargs -n 1 sudo zfs destroy
Interpretación: Esto borra snapshots uno por uno (menos ráfaga que un único destroy recursivo sobre muchos datasets). Si algún snapshot falla por holds/clones, verás cuál y por qué. En entornos grandes, añade throttling entre destroys.
Tarea 13: Usar destrucción diferida cuando necesites que el comando responda rápido
cr0x@server:~$ sudo zfs destroy -d pool/app@auto-2025-12-15
cr0x@server:~$ zfs list -t snapshot pool/app | grep auto-2025-12-15
# (no output)
Interpretación: El snapshot se elimina rápidamente del namespace, pero el pool puede seguir liberando bloques en segundo plano. Observa el I/O del pool y el espacio a lo largo del tiempo.
Tarea 14: Comprueba la salud del pool y señales obvias antes de culpar a la lógica de eliminación de ZFS
cr0x@server:~$ zpool status -x
all pools are healthy
cr0x@server:~$ zpool status pool
pool: pool
state: ONLINE
scan: scrub repaired 0B in 03:21:10 with 0 errors on Sun Dec 22 03:00:11 2025
config:
NAME STATE READ WRITE CKSUM
pool 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
errors: No known data errors
Interpretación: Si el pool está degradado o haciendo resilver, las eliminaciones de snapshots pueden demorarse, y quizá quieras posponer la limpieza masiva hasta después de la recuperación.
Tarea 15: Confirma que no estás atrapado por expectativas de replicación
cr0x@server:~$ zfs list -t snapshot -o name,creation pool/app | tail -n 3
pool/app@repl-2025-12-24-0200 Wed Dec 24 02:00 2025
pool/app@repl-2025-12-25-0200 Thu Dec 25 02:00 2025
pool/app@repl-2025-12-25-1400 Thu Dec 25 14:00 2025
cr0x@server:~$ zfs holds pool/app@repl-2025-12-24-0200
NAME TAG TIMESTAMP
pool/app@repl-2025-12-24-0200 zfs-send-chain Thu Dec 25 14:05 2025
Interpretación: Una herramienta de replicación está manteniendo intencionadamente este snapshot. Si lo eliminas, el siguiente incremental puede fallar o degradarse a una transferencia completa.
Tarea 16: Ver el conteo de snapshots y detectar “explosiones”
cr0x@server:~$ zfs list -H -t snapshot -o name pool/app | wc -l
1827
Interpretación: Un dataset con miles de snapshots no es automáticamente incorrecto, pero cambia el modelo de coste para eliminación y rollback. Planifica la limpieza como planificarías una reconstrucción de índices: prográmala, limítala y monitorízala.
Tres microhistorias del mundo corporativo
1) Incidente causado por una suposición errónea: “Eliminar snapshots liberará terabytes al instante”
En un gran clúster de VM de empresa, el equipo de almacenamiento recibió una alerta alarmante: el pool primario había caído por debajo del umbral de espacio libre. Un ingeniero hizo lo que muchos hemos hecho: eliminó “snapshots antiguos” en el dataset más ocupado, esperando una caída rápida en el uso. El borrado terminó, pero el espacio libre del pool apenas cambió. En la siguiente hora, la latencia de escritura subió y algunas VMs empezaron a hacer timeouts.
La suposición equivocada no era que los snapshots cuestan espacio; era que esos snapshots eran la causa. El dataset tenía una carga con mucho churn: las imágenes VM se compactaban y reescribían diariamente, pero también se tomaban nuevos snapshots cada hora. Borrar un puñado de snapshots antiguos no ayudó porque los bloques sobrescritos seguían referenciados por snapshots más recientes.
El equipo duplicó la apuesta: más borrados, más rápido. Así provocaron el efecto de segundo orden: la destrucción masiva de snapshots creó presión sobre metadata. No “rompió ZFS”, pero compitió con el I/O de las VMs y empeoró una situación marginal. Ahora tenían tanto poco espacio libre como rendimiento degradado.
La solución fue mezcla de humildad y aritmética. Midieron usedbysnapshots, identificaron los rangos de snapshots más problemáticos por USED, y borraron en lotes controlados. También ajustaron la programación de snapshots para ese dataset: menos snapshots horarios, más diarios, y un periodo de retención más corto para las imágenes de alto churn. El pool se estabilizó y el rendimiento se recuperó—lentamente, como cualquier sistema que ha sido forzado a hacer mucha contabilidad de golpe.
2) Optimización que salió mal: “Convirtamos todo en clones para velocidad de desarrollo”
Una compañía con un equipo de plataforma fuerte quería acelerar entornos de desarrollo. La propuesta fue elegante: tomar un snapshot nocturno de datasets tipo producción y luego crear clones por equipo en segundos. Funcionó. Los desarrolladores estaban felices. El equipo de plataforma recibió elogios por “aprovechar las primitivas de almacenamiento”.
Meses después, el pool de almacenamiento tocó techo. La eliminación de snapshots empezó a fallar por dependencias de clones. Peor aún, esos clones ya no eran “temporales”. Los equipos habían instalado paquetes, eliminado datos de prueba y construido flujos sobre sus clones. Destruirlos dejó de ser una tarea de limpieza y se convirtió en un proceso político.
El fracaso fue sutil: la optimización trasladó complejidad de ciclo de vida a la capa de almacenamiento. Los snapshots se volvieron no eliminables no porque ZFS sea terco, sino porque la organización hizo de los snapshots parte de un contrato implícito. Cada clone anclaba un snapshot; cada snapshot anclado retenía historial; e historial retenía espacio.
El plan de recuperación no fue una línea heroica. Introdujeron una política: los clones de dev deben promoverse dentro de una ventana temporal (o reconstruirse desde un snapshot más nuevo). También implementaron etiquetado e informes: edad del clone, edad del snapshot origen y excepciones de retención. La victoria fue tanto cultural como técnica: el coste de “clones instantáneos” se hizo visible y el equipo de plataforma dejó de tratar la limpieza de snapshots como algo secundario.
3) Práctica aburrida pero correcta que salvó el día: “Holds con etiquetas de propietario y un contrato de limpieza”
Otro entorno tenía dos sistemas de replicación durante una migración—antiguo y nuevo—corriendo en paralelo por un tiempo. Este es el tipo de situación donde los snapshots se acumulan silenciosamente, porque nadie quiere borrar algo que pueda ser necesario para envíos incrementales.
La práctica del equipo fue poco glamorosa: cada etiqueta de hold incluía el nombre del sistema propietario y un identificador de ejecución, y los holds tenían límites temporales por política. Un job diario informaba de snapshots con holds más antiguos que un umbral, desglosado por tag. Cuando una canalización moría, dejaba evidencia en lugar de misterio.
Durante la migración, uno de los jobs de replicación empezó a fallar intermitentemente. Los snapshots se acumulaban, pero no se convirtieron en “inmortales”. El informe mostró una única etiqueta de hold volviéndose obsoleta. El ingeniero on-call no tuvo que adivinar qué sistema la poseía; la etiqueta lo decía.
Pausaron la canalización defectuosa, confirmaron un snapshot base seguro, liberaron holds obsoletos y reanudaron con una cadena actualizada. Sin drama, sin borrados especulativos. El pool nunca llegó a la zona de peligro y la migración se completó sin el habitual incidente de “¿por qué no funciona la retención?”. La práctica era aburrida. También funcionó—y en producción eso es el mayor elogio.
Errores comunes (síntomas específicos y correcciones)
Error 1: Confundir “snapshot destruido” con “espacio reclamado al instante”
Síntoma: El snapshot ya no aparece en zfs list -t snapshot, pero el espacio libre del pool no aumenta.
Corrección: Comprueba usedbysnapshots y si aún existen otros snapshots que referencian bloques. Considera la demora por destrucción diferida y la carga del pool. Mide en el tiempo, no en segundos.
Error 2: Eliminar snapshots ignorando dependencias de clones
Síntoma: cannot destroy snapshot ...: snapshot has dependent clones o la propiedad clones del snapshot no está vacía.
Corrección: Identifica clones con zfs get clones. Destruye clones innecesarios o zfs promote el clone si debe vivir.
Error 3: Liberar holds sin entender quién los puso
Síntoma: Jobs de replicación o backup empiezan a fallar después de la “limpieza”. Los envíos incrementales se quejan de snapshots faltantes.
Corrección: Antes de liberar holds, identifica el proceso/herramienta propietaria y confirma que es seguro. Si debes romper la cadena, planifica una re-seed completa y el coste de tiempo/ancho de banda.
Error 4: Usar destroys recursivos demasiado a la ligera
Síntoma: Ejecutas zfs destroy -r pool/fs@snap y apuntas inesperadamente a un subtree enorme; los borrados tardan una eternidad o fallan en lugares sorprendentes.
Corrección: Lista primero lo que se verá afectado. Prefiere borrados por lotes con nombres de snapshot explícitos cuando el radio de impacto importa.
Error 5: Medir el dataset equivocado o la propiedad incorrecta
Síntoma: Borras snapshots en pool/app pero el pool sigue lleno; luego descubres que el espacio está en pool/app/logs u otro dataset.
Corrección: Usa vistas tipo zfs list -o space (o consultas de propiedad explícitas) a través del árbol de datasets. Verifica qué dataset realmente contribuye a la presión del pool.
Error 6: Eliminar primero los snapshots con gran USED sin considerar incrementales
Síntoma: Tras eliminar un snapshot grande, tu siguiente replicación pasa a ser un envío completo o falla.
Corrección: Entiende qué snapshots son puntos de anclaje para cadenas incrementales. Coordina borrados con el calendario de replicación y el estado del destino.
Error 7: Ejecutar destrucciones masivas de snapshots durante picos de I/O
Síntoma: Picos de latencia, iowait sube, usuarios reportan lentitud, pero nada está “caído”.
Corrección: Limita la velocidad de borrado, hazlo en lotes, ejecútalo en ventanas de baja actividad o usa destrucción diferida. La eliminación de snapshots es heavy en metadata; trátala como trabajo de mantenimiento.
Listas de verificación / plan paso a paso
Checklist A: “Destroy falla” paso a paso
- Confirma el nombre exacto del snapshot con
zfs list -t snapshot. - Intenta el destroy una vez y captura el texto del error.
- Si menciona holds: ejecuta
zfs holds, identifica etiquetas y decide si liberarlas. - Si menciona clones: ejecuta
zfs get clones, inspecciona y destruye o promueve clones. - Si menciona “busy”: confirma si estás destruyendo sólo snapshots o también datasets (
-r/-R); comprueba montajes, exports, contenedores y recepciones en curso. - Vuelve a ejecutar destroy para un solo snapshot para verificar que has despejado el bloqueador antes de escalar.
Checklist B: “Snapshots eliminados pero el espacio no volvió” paso a paso
- Verifica que el conteo de snapshots realmente disminuyó:
zfs list -t snapshot | wc -l(o por dataset). - Comprueba el desglose de espacio del dataset:
zfs get used,usedbysnapshots,usedbydataset,referenced. - Lista los snapshots restantes y ordénalos por
USEDpara ver quién sigue reteniendo bloques. - Considera que el head del dataset puede seguir referenciando los bloques: eliminar snapshots no ayudará si los datos en vivo son el grueso.
- Si usas destrucción diferida, da tiempo y monitoriza la tendencia del espacio libre del pool.
- Comprueba si otro dataset es la verdadera fuente de uso del pool.
Checklist C: Plan seguro para limpieza masiva (cuando necesitas borrar cientos/miles)
- Elige una ventana de eliminación (off-peak). Anúnciala como cualquier otro mantenimiento.
- Dry-run de la selección: lista los nombres de snapshots que piensas eliminar, revisa patrones (anclas de replicación, cierres de mes).
- Comprueba holds y dependencias de clones antes de empezar.
- Elimina en lotes; monitoriza latencia y actividad del pool entre lotes.
- Registra lo que borraste y lo que falló (y por qué). “Ejecutamos un comando” no es pista de auditoría.
- Después de la limpieza, verifica que replicación/backups todavía tengan sus snapshots base requeridos.
FAQ
1) ¿Por qué zfs destroy dice “snapshot has holds”?
Porque uno o más tags de hold están establecidos en el snapshot. Los holds son protecciones explícitas. Usa zfs holds pool/fs@snap para listarlos, luego zfs release TAG pool/fs@snap para quitar una etiqueta específica cuando sea seguro.
2) ¿Por qué no puedo destruir un snapshot que tiene clones dependientes?
Un clone es un dataset que usa ese snapshot como origen. Destruir el snapshot rompería el grafo de referencias del clone. O bien destruye el clone, o zfs promote el clone para invertir la dependencia.
3) Destruí snapshots y df aún muestra el filesystem lleno. ¿ZFS miente?
Normalmente no miente; estás comparando sistemas de contabilidad distintos. df muestra lo que el filesystem montado cree que está disponible, influenciado por reservas, cuotas, refreservations y presión de asignación a nivel de pool. Usa zfs get used,available,usedbysnapshots y a nivel de pool zpool list para ver qué está ocurriendo realmente.
4) ¿Los snapshots ralentizan mi carga de trabajo?
No por existir por sí solos. El coste viene del churn: si sobrescribes muchos datos mientras mantienes muchos snapshots, el pool retendrá más bloques antiguos, aumentando la presión de espacio y potencialmente la fragmentación. Eliminar grandes cantidades de snapshots también puede crear una ráfaga de trabajo de metadata.
5) ¿Cuál es la diferencia entre USED en un snapshot y usedbysnapshots en un dataset?
USED en un snapshot es lo que ese snapshot contribuye de forma única comparado con otros. usedbysnapshots en un dataset es el espacio total consumido por snapshots asociados a ese dataset. Responden preguntas distintas: “¿qué snapshot es caro?” versus “¿cuánto me cuestan los snapshots en este lugar?”
6) ¿La destrucción diferida es segura?
Sí, en el sentido de que es un mecanismo soportado: el snapshot se elimina y la liberación de bloques ocurre más tarde. El intercambio es visibilidad operativa—la gente espera recuperación de espacio instantánea. Úsala cuando necesites reactividad y puedas tolerar reclamación retrasada.
7) ¿Por qué a veces destruir snapshots tarda una eternidad?
ZFS puede necesitar recorrer metadata para liberar bloques, y eso compite con I/O normal. Pools con muchos snapshots, alto churn, discos lentos o cargas concurrentes pesadas lo notarás más. Borra en lotes y prográmalo en periodos más tranquilos.
8) ¿Puedo eliminar snapshots en el origen sin tocar el destino (o viceversa)?
Puedes, pero los incrementales de replicación dependen de snapshots comunes. Eliminar un snapshot “ancla” en cualquiera de los lados puede forzar una re-seed completa o romper la automatización. Si no estás seguro, inspecciona qué snapshots se usan para replicación y si están retenidos/anclados.
9) ¿Cómo evito que los snapshots se vuelvan “inmortales” otra vez?
Usa convenciones de nombres explícitas, etiqueta los holds con propiedad, monitoriza snapshots con holds más antiguos de lo esperado y evita clones de larga vida salvo que tengas una política de ciclo de vida (ventana de promoción, TTL o limpieza automática).
Conclusión
Los snapshots ZFS no “se niegan a morir” por maldad. Persisten porque ZFS hace exactamente lo que le pediste: preservar consistencia, respetar dependencias y prevenir borrados inseguros. Cuando un snapshot no se elimina, casi siempre es por una de tres cosas—holds, clones o una mala interpretación de la contabilidad de espacio—y la solución es identificar cuál es antes de empezar a ejecutar comandos a lo loco.
Cuando tratas la eliminación de snapshots como mantenimiento (acotada, monitorizada y coordinada con las realidades de replicación/backup), vuelve a ser aburrida. Y el almacenamiento aburrido es el tipo que sólo notas cuando presumes del uptime en lugar de explicarlo.