El infierno de instantáneas no llega con sirenas. Aparece como «¿por qué el pool está 94% lleno otra vez?» y «¿por qué eliminar instantáneas antiguas no libera nada?»
Luego la ventana de respaldo se alarga, la replicación se retrasa y una restauración de rutina se convierte en una excavación forense.
Las instantáneas ZFS son una de las mejores ideas que ha traído el almacenamiento. También son la forma más fácil de crear silenciosamente una máquina del tiempo que no puedes permitirte mantener.
La solución no es «tomar menos instantáneas» ni «comprar más discos». Es una política de retención que trate a las instantáneas como datos de producción: presupuestadas, observables y
rutinariamente recolectadas con recibos.
Qué es realmente el “infierno de instantáneas”
El infierno de instantáneas no es «demasiadas instantáneas». Es instantáneas sin gobernanza.
Puedes tener decenas de miles de instantáneas y estar bien si entiendes cómo se retiene el espacio, cómo funciona la replicación y los holds,
y si eliminas con intención en lugar de por corazonadas.
Así es como se manifiesta en producción:
- Pánico por capacidad: el uso del pool sube aunque «borramos datos antiguos».
- Incertidumbre en restauraciones: nadie sabe qué instantánea es segura, consistente o relevante.
- Arrastre en replicación: los envíos incrementales crecen porque las instantáneas están desalineadas o porque conservaste las equivocadas.
- Miedo operativo: «no borren nada, puede que se necesite». Felicitaciones, ahora administran un museo.
El problema central es que las instantáneas preservan bloques antiguos. Si modificas datos de forma agresiva (VMs, bases de datos, caches de CI),
las instantáneas mantienen esas versiones antiguas. Tus datos «eliminados» no se borran; se memorializan.
Broma #1: Las instantáneas son como recibos—útiles hasta que los guardas siete años y descubres que compraste 300 cables USB idénticos.
Hechos interesantes e historia útiles
- ZFS se construyó alrededor de copy-on-write (CoW), lo que significa que nunca sobrescribe bloques activos; las instantáneas son una consecuencia natural, no una función añadida.
- Crear instantáneas es casi gratuito (trabajo de metadatos), por eso es fácil abusar; el coste aparece después como bloques retenidos.
- Las instantáneas ZFS son consistentes a nivel de sistema de archivos; para consistencia de aplicación (bases de datos), aún necesitas coordinación (freeze, flush o herramientas de replicación).
- La contabilidad de espacio para instantáneas no es «tamaño de la instantánea»; es «bloques únicos referenciados solo por esa instantánea». Esto confunde a casi todo el mundo alguna vez.
- Los clones son instantáneas escribibles—y crean cadenas de dependencia donde no puedes borrar «lo viejo» porque un clone todavía lo usa.
- Los holds existen porque los humanos borran lo equivocado; ZFS hizo la eliminación de instantáneas reversible en espíritu (preventable), no en hecho (sigue siendo destructiva).
- El envío/recepción incremental depende de la genealogía de instantáneas; borrar instantáneas «intermedias» puede romper incrementales a menos que lo planifiques.
- Las herramientas de auto-instantáneas se popularizaron porque el snapshot manual falla silenciosamente: funciona hasta la semana que olvidas—justo antes de que la necesites.
Modelo mental: instantáneas, bloques y por qué la eliminación decepciona
Las instantáneas en ZFS son punteros a una vista consistente de un dataset en un momento dado. No «contienen archivos».
Contienen referencias a bloques que existían al momento de crear la instantánea.
Cuando los datos cambian después de una instantánea, ZFS escribe nuevos bloques (CoW). Los bloques antiguos permanecen porque la instantánea todavía apunta a ellos.
Así que el coste de la instantánea es proporcional a cuánto ha cambiado desde que se tomó, no al tamaño nominal del dataset.
Tres comportamientos que vuelven miserable a un operador
- El espacio libre vuelve tarde: eliminar un archivo no libera bloques si alguna instantánea todavía los referencia.
- «Usado» es contextual: el «used» de una instantánea es la propiedad de bloques únicos; puede crecer conforme el dataset churnea.
- Las dependencias son invisibles a menos que las revises: los clones y los holds impedirán eliminaciones y confundirán scripts de limpieza.
Qué debe resolver una política de retención
Una política de retención no es un calendario. Es un contrato entre riesgo y coste:
«Siempre podremos restaurar dentro de la ventana de tiempo X y la granularidad Y, y nunca excederemos Z% de uso del pool por instantáneas.»
Necesitas:
- Clases de instantáneas claras (hora/día/semana/mes).
- Un esquema de nombres que codifique la intención.
- Un algoritmo de poda que conserve puntos representativos en el tiempo.
- Guardarraíles: holds para instantáneas especiales y alertas cuando la retención viola presupuestos de capacidad.
- Runbooks para el «día en que el pool se llena»—porque pasará.
Una idea parafraseada, atribuida porque moldeó la cultura de ops:
deberías construir sistemas que asuman que los humanos cometerán errores, y luego restringir el radio de daño.
— James Hamilton (ingeniería de confiabilidad)
La política de retención que realmente funciona
La política abajo es aburrida. Por eso sobrevive al contacto con la producción.
Está diseñada alrededor de tres verdades: la mayoría de las restauraciones son recientes, cumplimiento quiere horizontes largos, y la capacidad es finita.
1) Elige un objetivo de recuperación y cúmpralo con instantáneas
Decide tu RPO (cuánto dato puedes perder) y RTO (qué tan rápido debes restaurar). Luego mapea eso a la frecuencia de instantáneas.
Si tu negocio dice «podemos tolerar 1 hora de pérdida», no tomes instantáneas solo diarias y esperes.
Por defecto práctico que encaja con muchos equipos:
- Horarias: conservar 48 (2 días)
- Diarias: conservar 35 (5 semanas)
- Semanales: conservar 12 (3 meses)
- Mensuales: conservar 18 (18 meses)
Suena a mucho. No lo es, si podas según el calendario y mantienes tus datasets de mayor churn separados (VMs, caches de build, WALs de DB).
2) Separa datasets por churn y por valor
La retención de instantáneas debe ser por clase de dataset, no «una regla para todo el pool».
Coloca lo de alto churn en su propio dataset para que no envenene la economía de retención del resto.
- Bases de datos: instantáneas consistentes coordinadas con la BD; retención corta localmente, más larga en réplicas/backups.
- Discos de VM: instantáneas frecuentes y cortas; poda agresiva; considera replicación para horizontes largos.
- Directorios home: retención más larga, menor churn, buen candidato para horizontes extensos.
- Scratch / CI: retención mínima o ninguna; las instantáneas aquí son cómo quemas dinero lentamente.
3) Presupuesta las instantáneas como porcentaje de la capacidad del pool
Elige un límite estricto, por ejemplo: «Las instantáneas no deben causar que el pool supere el 80% de uso en operación normal.»
Tu presupuesto es una restricción de política, no una sugerencia.
Cuando se supere el límite, la poda se vuelve más agresiva automáticamente (¿eliminar primero mensuales? ¿o primeras las horarias?).
Mi opinión: eliminar primero las capas de mayor frecuencia (horarias), porque cuestan más en datasets churny y aportan menos para recuperación a largo plazo.
4) Requiere holds para instantáneas especiales, pero nunca para las rutinarias
Los holds son para momentos excepcionales: puntos de control antes de una actualización, retenciones legales, «vamos a ejecutar una migración destructiva».
La retención rutinaria debe ser totalmente automática y totalmente eliminable.
Si permites que los holds se infiltren en el conjunto por defecto, tu política de retención se convierte en una ficción cortesana.
5) Alinea la retención con la replicación
Si haces replicación con ZFS send/receive, decide qué lado es la autoridad para la retención a largo plazo.
Patrón ganador común:
- Origen: retención corta, instantáneas frecuentes para restauración local rápida y incrementales pequeños.
- Destino: retención más larga, menos instantáneas retenidas, más «anclas» periódicas (semanales/mensuales) para cumplimiento.
Esto evita el clásico error de «retuvimos todo en todas partes». El disco es más barato que el tiempo—hasta que deja de serlo.
Nombres y metadatos: tu yo futuro lo agradecerá
Los nombres de instantáneas son parte de tu plano de control. No son decoración.
Si no codificas la intención, terminarás con nombres como auto-2025-thing y un humano adivinando cuáles importan.
Un esquema de nombres que escala
Usa: <dataset>@<clase>-<marca de tiempo utc> más sufijos opcionales para coordinación de la aplicación.
Ejemplos:
tank/vmstore@hourly-2026-02-04T00:00Ztank/home@daily-2026-02-04T00:00Ztank/db@hourly-2026-02-04T00:00Z-pgfreeze
Usa propiedades para etiquetar intención
Las propiedades de usuario ZFS pueden llevar metadatos de política. Por ejemplo:
com.example:retention=hourlycom.example:owner=paymentscom.example:tier=gold
Los nombres ayudan a los humanos. Las propiedades ayudan a las herramientas.
Tareas prácticas (comandos, salidas, decisiones)
Estos no son comandos «de juguete». Son los que ejecutas cuando alguien pregunta por qué el pool está lleno y tu calendario está a punto de ser cancelado por la física.
Cada tarea incluye: el comando, qué significa la salida y la decisión que tomas a partir de ello.
Tarea 1: Ver la presión de capacidad del pool y la fragmentación
cr0x@server:~$ zpool list -o name,size,alloc,free,cap,health,frag
NAME SIZE ALLOC FREE CAP HEALTH FRAG
tank 10.9T 9.2T 1.7T 84% ONLINE 38%
Significado: CAP en 84% ya está en la zona de peligro para rendimiento y comportamiento de asignación; FRAG indica cuán fragmentado está el espacio libre.
La fragmentación no es «mala» por sí misma, pero CAP alto + FRAG creciente es donde la latencia empieza a ponerse picante.
Decisión: Si CAP > 80%, deja de crear nuevas instantáneas de larga retención, prioriza la poda e investiga quién está reteniendo espacio (instantáneas, clones o datos reales).
Tarea 2: Identificar qué datasets consumen espacio realmente
cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint -S used
NAME USED AVAIL REFER MOUNTPOINT
tank/vmstore 4.3T 820G 1.1T /tank/vmstore
tank/home 2.7T 820G 2.2T /tank/home
tank/db 1.6T 820G 540G /tank/db
Significado: USED incluye instantáneas e hijos; REFER es lo que el sistema de archivos vivo referencia actualmente.
Grandes diferencias entre USED y REFER son tu impuesto por instantáneas (o hijos).
Decisión: Enfócate en datasets donde USED ≫ REFER. Son los principales sospechosos de bloat por instantáneas.
Tarea 3: Cuantificar la sobrecarga de instantáneas por dataset
cr0x@server:~$ zfs get -H -o name,property,value used,usedbysnapshots,usedbydataset tank/vmstore
tank/vmstore used 4.30T
tank/vmstore usedbysnapshots 3.10T
tank/vmstore usedbydataset 1.10T
Significado: 3.10T está fijado por instantáneas. Eso no es «conteo de instantáneas», es bloques retenidos.
Decisión: Este dataset necesita revisar retención inmediatamente. O reduces frecuencia/longitud de instantáneas o separas subrutas de alto churn en datasets distintos.
Tarea 4: Listar instantáneas con impacto de espacio, ordenadas
cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -S used tank/vmstore | head
NAME USED REFER CREATION
tank/vmstore@hourly-2026-02-02T10:00Z 120G 1.05T Sun Feb 2 10:00 2026
tank/vmstore@hourly-2026-02-02T11:00Z 118G 1.06T Sun Feb 2 11:00 2026
tank/vmstore@daily-2026-01-28T00:00Z 90G 1.02T Tue Jan 28 00:00 2026
Significado: La columna USED para instantáneas es «datos únicos retenidos por esta instantánea». Valores grandes son tu palanca de limpieza.
Decisión: Empieza podando las instantáneas horarias grandes primero—a menos que formen parte de una cadena de replicación que aún necesites.
Tarea 5: Comprobar si las instantáneas están bloqueadas por holds
cr0x@server:~$ zfs holds tank/vmstore@hourly-2026-02-02T10:00Z
NAME TAG TIMESTAMP
tank/vmstore@hourly-2026-02-02T10:00Z pre-upgrade Mon Feb 3 09:12 2026
Significado: Esta instantánea no puede destruirse hasta que el hold sea liberado.
Decisión: Confirma que el evento «pre-upgrade» esté completo y aprobado. Luego libera el hold; de lo contrario manténla y poda otras instantáneas.
Tarea 6: Liberar un hold (de forma segura) y eliminar una instantánea
cr0x@server:~$ zfs release pre-upgrade tank/vmstore@hourly-2026-02-02T10:00Z
cr0x@server:~$ zfs destroy tank/vmstore@hourly-2026-02-02T10:00Z
cr0x@server:~$ zfs list -t snapshot -o name,used -S used tank/vmstore | head -3
NAME USED
tank/vmstore@hourly-2026-02-02T11:00Z 118G
tank/vmstore@daily-2026-01-28T00:00Z 90G
Significado: La instantánea ha desaparecido; el orden cambió. El espacio puede no mostrarse inmediatamente como «libre» si otras instantáneas aún referencian esos bloques.
Decisión: Si el espacio libre no se mueve, sigue borrando en la cadena (o identifica clones/otras instantáneas que retengan los mismos bloques).
Tarea 7: Detectar clones que bloquean la eliminación de instantáneas
cr0x@server:~$ zfs get -H -o name,property,value origin -r tank/vmstore
tank/vmstore origin -
tank/vmstore/clone-win11 origin tank/vmstore@daily-2026-01-28T00:00Z
Significado: tank/vmstore/clone-win11 depende de esa instantánea diaria. Eliminar la instantánea fallará hasta que el clone se elimine o se promueva.
Decisión: O destruyes el clone (si es prescindible) o zfs promote el clone para romper la dependencia antes de podar.
Tarea 8: Promover un clone para desbloquear la retención
cr0x@server:~$ zfs promote tank/vmstore/clone-win11
cr0x@server:~$ zfs get -H -o name,property,value origin tank/vmstore/clone-win11
tank/vmstore/clone-win11 origin -
Significado: El clone ahora es independiente; su origin está limpio.
Decisión: Ahora puedes destruir instantáneas antiguas que previamente actuaban como origen—después de verificar la nueva genealogía de instantáneas del clone y el plan de replicación.
Tarea 9: Comprobar recuento y distribución de instantáneas por clase
cr0x@server:~$ zfs list -t snapshot -o name -r tank/home | awk -F@ '{print $2}' | cut -d- -f1 | sort | uniq -c
48 hourly
35 daily
12 weekly
18 monthly
Significado: Esto coincide con la política. Los conteos que aumentan indican una falla de automatización o una eliminación bloqueada (holds/clones).
Decisión: Si los conteos exceden la política, inspecciona holds y clones primero; luego verifica si tu trabajo de poda realmente corre y tiene permisos.
Tarea 10: Inspeccionar qué impide la replicación incremental
cr0x@server:~$ zfs list -t snapshot -o name,creation tank/db | tail -5
tank/db@hourly-2026-02-03T20:00Z Mon Feb 3 20:00 2026
tank/db@hourly-2026-02-03T21:00Z Mon Feb 3 21:00 2026
tank/db@hourly-2026-02-03T22:00Z Mon Feb 3 22:00 2026
tank/db@hourly-2026-02-03T23:00Z Mon Feb 3 23:00 2026
tank/db@hourly-2026-02-04T00:00Z Tue Feb 4 00:00 2026
Significado: Los incrementales de replicación requieren una instantánea común en ambos lados. Si el destino carece de las hourlies más antiguas porque las podaste allí,
tu origen no podrá hacer incremental desde ese punto.
Decisión: Define qué instantáneas son «anclas de replicación» (a menudo dailies o weeklies) y asegúrate de que ambos lados las conserven el tiempo suficiente.
Tarea 11: Estimar el tamaño a enviar antes de comprometerte
cr0x@server:~$ zfs send -nvP -I tank/db@hourly-2026-02-03T20:00Z tank/db@hourly-2026-02-04T00:00Z
send from @hourly-2026-02-03T20:00Z to tank/db@hourly-2026-02-04T00:00Z estimated size is 36.2G
total estimated size is 36.2G
Significado: Esto es lo que tu replicación empujaría. Si esto es inesperadamente grande, tu dataset churnea mucho o tu intervalo es demasiado largo.
Decisión: Si el tamaño estimado es demasiado grande para tu ventana, aumenta la frecuencia de instantáneas (deltas más pequeños), reduce el churn (separa WAL/temp),
o cambia a un horario de replicación más apropiado.
Tarea 12: Confirmar compresión y recordsize que afectan el churn de instantáneas
cr0x@server:~$ zfs get -o name,property,value compression,recordsize,atime tank/vmstore
NAME PROPERTY VALUE
tank/vmstore compression zstd
tank/vmstore recordsize 128K
tank/vmstore atime off
Significado: Recordsize afecta cuánto datos cambian cuando ocurren escrituras pequeñas; atime=on puede crear churn de metadatos innecesario (y por tanto crecimiento de instantáneas).
Decisión: Para imágenes de VM y bases de datos, considera recordsize y diseño del dataset de forma intencional. Desactiva atime salvo que tengas un caso de uso real.
Tarea 13: Encontrar «espacio que no se libera» por eliminaciones bajo instantáneas
cr0x@server:~$ zfs list -o name,used,refer,usedbysnapshots -r tank/vmstore
NAME USED REFER USEDBYSNAPSHOTS
tank/vmstore 4.3T 1.1T 3.1T
tank/vmstore/images 3.9T 820G 3.0T
tank/vmstore/iso 120G 115G 2G
Significado: El churn está concentrado bajo images. Ahí es donde ocurrieron eliminaciones/re-escrituras mientras existían instantáneas.
Decisión: Ajusta la retención específicamente para tank/vmstore/images o separa aún más (datasets por VM) para limitar el radio de daño.
Tarea 14: Simular una limpieza destructiva listando lo que se borraría
cr0x@server:~$ zfs list -t snapshot -o name,creation -S creation tank/home | awk 'NR==1 || /@hourly-/' | head -5
NAME CREATION
tank/home@hourly-2026-02-04T00:00Z Tue Feb 4 00:00 2026
tank/home@hourly-2026-02-03T23:00Z Mon Feb 3 23:00 2026
tank/home@hourly-2026-02-03T22:00Z Mon Feb 3 22:00 2026
tank/home@hourly-2026-02-03T21:00Z Mon Feb 3 21:00 2026
Significado: Has confirmado el patrón de nombres y las marcas de tiempo de creación. Los scripts de limpieza deben operar sobre estos patrones, no sobre «lo que parece viejo».
Decisión: Si las instantáneas no coinciden con los patrones, detente y arregla los nombres primero. La recolección de basura sin nombres consistentes es solo eliminación creativa.
Tarea 15: Observar la presión de I/O cuando las instantáneas son pesadas
cr0x@server:~$ zpool iostat -v tank 2 3
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 9.2T 1.7T 420 1150 62.1M 210M
raidz2-0 9.2T 1.7T 420 1150 62.1M 210M
sda - - 52 140 7.8M 26.5M
sdb - - 50 138 7.5M 25.9M
sdc - - 54 145 8.0M 27.1M
Significado: Altas operaciones de escritura junto con alto uso del pool a menudo coincide con cargas de trabajo pesadas en instantáneas (más churn de metadatos, más fragmentación).
Decisión: Si tu carga es sensible a latencia y CAP es alto, poda instantáneas y reduce el churn. Si no tienes margen, planifica expansión—no negocies con la entropía.
Guion de diagnóstico rápido
Cuando alguien dice «las instantáneas nos están matando», puede que tengan razón—o puede que estén culpando a la única característica visible.
Este guion encuentra el cuello de botella rápido, en el orden que normalmente da resultado.
Primero: ¿realmente estás limitado por capacidad?
-
Comprueba uso y salud del pool:
cr0x@server:~$ zpool list -o name,cap,health,frag NAME CAP HEALTH FRAG tank 84% ONLINE 38%Decisión: Si CAP > 80%, trátalo como un incidente. Tus opciones se reducen rápidamente por encima de esta línea.
-
Encuentra la contribución de instantáneas:
cr0x@server:~$ zfs get -H -o name,value usedbysnapshots -r tank | sort -h -k2 | tail -5 tank/vmstore 3.10T tank/home 420G tank/db 310GDecisión: Ataca al mayor contribuyente primero. Las heroicidades en otros sitios son performativas.
Segundo: ¿la eliminación está bloqueada por dependencias (holds/clones/replicación)?
-
Comprueba holds en instantáneas «deberían borrarse»:
cr0x@server:~$ zfs holds -r tank/vmstore | head NAME TAG TIMESTAMP tank/vmstore@daily-2026-01-28T00:00Z legal Thu Jan 30 14:10 2026Decisión: Los holds implican un proceso. Confirma la propiedad, luego libera o acepta el coste de capacidad.
-
Comprueba clones y orígenes:
cr0x@server:~$ zfs get -H -o name,value origin -r tank/vmstore | grep -v '^-' tank/vmstore/clone-win11 tank/vmstore@daily-2026-01-28T00:00ZDecisión: Si existen clones, promuévelos o destrúyelos antes de podar sus instantáneas origen.
Tercero: ¿la queja es rendimiento, no capacidad?
-
Comprueba síntomas de I/O y latencia:
cr0x@server:~$ zpool iostat -v tank 1 5 capacity operations bandwidth pool alloc free read write read write -------------------------- ----- ----- ----- ----- ----- ----- tank 9.2T 1.7T 380 1320 58.0M 225MDecisión: Si las escrituras son altas y CAP es alto, la poda ayuda. Si CAP está bien, revisa recordsize, sync settings y la forma de la carga.
-
Comprueba propiedades de dataset que crean churn (atime, recordsize):
cr0x@server:~$ zfs get -o name,property,value atime,recordsize -r tank/vmstore NAME PROPERTY VALUE tank/vmstore atime off tank/vmstore recordsize 128K tank/vmstore/images atime off tank/vmstore/images recordsize 128KDecisión: Ajusta por dataset. No «optimices» todo el pool porque una carga de trabajo es la más ruidosa.
Tres microhistorias corporativas desde las trincheras
Microhistoria 1: El incidente causado por una suposición errónea
Una empresa SaaS mediana usaba ZFS para almacenamiento de VM y directorios home. Tenían un trabajo nocturno que «eliminaba backups antiguos» en el sistema invitado.
El equipo de almacenamiento esperaba que el pool descendiera tras cada limpieza. Nunca lo hizo.
Cuando el pool cruzó a los altos 80s, la latencia se disparó. Llegaron tickets: «las VMs van lentas», «el backup tarda más», «los despliegues están atascados».
El ingeniero de guardia hizo lo obvio: borrar más archivos. El pool se llenó… más. Ahí es cuando el pánico adquiere sentido del humor.
La suposición errónea fue simple: «Eliminar archivos libera espacio». En ZFS con instantáneas, eso solo es cierto cuando ninguna instantánea referencia los bloques eliminados.
Su dataset de VM tenía instantáneas horarias por 30 días. Cada limpieza nocturna borraba grandes archivos de log y rotaba imágenes de VM. Las instantáneas retuvieron todos los bloques antiguos.
La solución no fue mística. Midieron usedbysnapshots, descubrieron que era la mayoría del dataset, y acortaron la retención horaria de 30 días a 2 días.
Mantuvieron dailies y weeklies más largos para recuperación puntual. También separaron imágenes de VM de alto churn en datasets por-VM para que un inquilino ruidoso no fijara espacio para todos.
Lo mejor: las restauraciones mejoraron. En lugar de recorrer un mes de hourlies, tenían una ventana reciente clara para rollback rápido y una ventana más larga para auditoría.
Menos instantáneas. Mejores resultados. El universo ocasionalmente recompensa la contabilidad básica.
Microhistoria 2: La optimización que salió mal
Un área de finanzas quiso «más seguridad» y decidió snapshotear cada cinco minutos. Lo hicieron en un dataset de base de datos ocupado sin coordinación de aplicación.
El trabajo de instantáneas era rápido. La replicación no. El pool se llenó más rápido que su ciclo de compras, que es el tier de almacenamiento más lento conocido por la ciencia.
Luego optimizaron: «Mantengamos los snapshots de cinco minutos solo 24 horas, y las diarias por un año.»
Razonable en papel. En la práctica, su script de poda eliminó instantáneas «intermedias» necesarias para las cadenas de envío incremental al site de DR,
forzando envíos completos frecuentes. El ancho de banda subió, la latencia de replicación creció y el dataset de DR empezó a carecer de los puntos de recuperación que todos pensaban que tenían.
La sorpresa fue que optimizaban la métrica equivocada. La frecuencia de instantáneas no era el problema; la alineación sí lo era.
El origen creaba instantáneas a :00, :05, :10. La retención del destino podaba según su tiempo local y carga, borrando anclas de forma impredecible.
La solución: definieron anclas de replicación explícitas (horarias y diarias) y las retuvieron en ambos lados. Las instantáneas de cinco minutos se mantuvieron solo localmente, de corta vida.
DR mantuvo hourlies por unos días y dailies por meses. La replicación volvió a ser incremental, predecible y aburrida—exactamente lo que quieres de DR.
Broma #2: Nada dice «alta disponibilidad» como descubrir que tu plan de DR depende del humor de un cron.
Microhistoria 3: La práctica aburrida pero correcta que salvó el día
Una compañía de salud tenía control de cambios estricto. Antes de cualquier actualización mayor, tomaban una instantánea manual y aplicaban un hold con el ID del ticket en la etiqueta.
Era procedimental, ligeramente molesto y universalmente burlado hasta que importó.
Durante un despliegue de firmware de almacenamiento, una configuración multipath errónea provocó errores de I/O intermitentes en un subconjunto de hosts.
El equipo de aplicación hizo rollback de código. Los errores continuaron. El problema no era software; era el ruteo de almacenamiento.
Necesitaban restaurar un conjunto de directorios de configuración y una pequeña base de datos que habían «limpiado» durante la resolución de problemas.
Gracias a que la instantánea pre-upgrade tenía un hold, sobrevivió al ciclo de poda regular. La restauración fue quirúrgica: clonar la instantánea, extraer los archivos necesarios,
y mantener la operación mientras arreglaban multipath.
No requirió genialidad. Requirió disciplina aburrida: instantánea + hold + propietario documentado. El hold impidió que una «limpieza útil» destruyera la vía de escape.
Luego retiraron el hold cuando el incidente cerró, y el sistema volvió a su política normal sin acumular incrustaciones permanentes.
Errores comunes: síntoma → causa raíz → solución
1) «Borramos datos antiguos pero el espacio no volvió»
SÍNTOMA: REFER del dataset disminuye, CAP del pool no.
CAUSA RAÍZ: Instantáneas siguen referenciando los bloques eliminados.
FIJO: Mide usedbysnapshots, luego poda instantáneas según la política. Si necesitas las instantáneas, separa datasets para aislar el churn.
2) «Destruir instantáneas falla con ‘dataset is busy’ u errores de dependencia»
SÍNTOMA: zfs destroy se niega, o el script omite instantáneas.
CAUSA RAÍZ: Existen holds o clones; la instantánea es un origen.
FIJO: Usa zfs holds y zfs get origin. Libera holds si estás autorizado; destruye o promueve clones.
3) «La replicación de repente se volvió enorme o lenta»
SÍNTOMA: Envios incrementales se inflan; la replicación se atrasa.
CAUSA RAÍZ: Instantáneas comunes faltantes por retención o poda desajustada en un lado.
FIJO: Establece anclas de replicación retenidas en ambos lados. Valida con zfs list -t snapshot en origen y destino.
4) «Tenemos miles de instantáneas y nadie sabe qué son»
SÍNTOMA: Nombres inconsistentes, propiedad poco clara.
CAUSA RAÍZ: No hay convención de nombres; no hay metadatos; múltiples herramientas creando instantáneas.
FIJO: Estandariza nombres por clase + marca de tiempo UTC. Añade propiedades de usuario para propietario y clase de retención. Detén creadores no autorizados.
5) «El rendimiento empeoró al añadir instantáneas»
SÍNTOMA: Aumento de latencia; el pool se siente ‘pesado’ bajo carga.
CAUSA RAÍZ: Alto uso del pool + fragmentación + churn por instantáneas frecuentes amplifica costos de metadatos y asignación CoW.
FIJO: Mantén CAP bajo control (objetivo < 80%). Reduce retención de alta frecuencia en datasets churny. Considera rediseño de datasets y expansión de capacidad.
6) «La poda corre, pero el conteo de instantáneas solo aumenta»
SÍNTOMA: La automatización reporta éxito, pero las instantáneas antiguas permanecen.
CAUSA RAÍZ: Los filtros del script no coinciden con los nombres; instantáneas en hold; permisos; o la poda opera en el ámbito equivocado.
FIJO: Valida listando las instantáneas objetivo antes de borrar. Añade monitoreo del conteo de instantáneas por clase y del número de holds.
7) «Las restauraciones son poco fiables o inconsistentes para bases de datos»
SÍNTOMA: La restauración arranca pero la BD necesita recovery, o los datos están lógicamente dañados.
CAUSA RAÍZ: Instantánea de sistema de archivos sin coordinación de aplicación.
FIJO: Usa mecanismos nativos de la BD (freeze/flush, checkpoints consistentes) alrededor del tiempo de snapshot, o replica usando herramientas de BD y snapshotea las réplicas.
Listas de verificación / plan paso a paso
Paso a paso: implementar una política de retención sin crear un nuevo incidente
-
Inventaria datasets y clasifícalos por churn/valor.
Agrupa en: bases de datos, imágenes de VM, datos de usuario, logs, scratch. Si todo está en un solo dataset, ya encontraste el problema #1. -
Define RPO/RTO por clase.
No dejes que «queremos todo para siempre» entre en la sala a menos que traigan una orden de compra. - Elige niveles de retención (horario/diario/semanal/mensual) y conteos por clase.
- Adopta un esquema de nombres usando timestamps UTC y prefijo de clase.
- Implementa automatización para la creación de instantáneas con el alcance correcto y nombres consistentes.
-
Implementa automatización para la poda que:
- mantenga las N más nuevas por clase
- nunca borre instantáneas en hold
- sea consciente de clones (o al menos informe clones que bloquean eliminación)
- registre lo que eliminó y lo que no pudo eliminar
- Establece guardarraíles de capacidad: alerta al 75% y 80% de uso del pool; trata 85% como crítico según la carga.
-
Prueba restauraciones trimestralmente, no durante incidentes.
Restaurar es una característica del producto. Si no la pruebas, no la tienes. - Alinea la replicación con anclas y autoridad de retención (origen vs destino).
- Documenta el procedimiento de «instantánea especial»: tomar instantánea, aplicar tag de hold con ID de ticket, fijar un propietario/expiración y requerir eliminación al cerrar.
Checklist operacional: el día «el pool se está llenando»
- Confirma CAP e identifica los datasets principales por
usedbysnapshots. - Lista las instantáneas más grandes por USED y verifica holds/clones.
- Poda primero instantáneas de alta frecuencia en datasets churny (horarias), preservando anclas de replicación.
- Si el espacio aún no se libera, busca clones y holds de larga duración.
- Si estás cerca del 90% de CAP, planifica alivio de capacidad de emergencia (mover datos, expandir pool) mientras podas—no elijas solo una cosa y esperes milagros.
Checklist de diseño: prevenir estructuralmente el infierno de instantáneas
- Separa rutas de alto churn en datasets dedicados.
- Desactiva atime donde no sea necesario.
- Decide qué sistema es el «almacén de retención larga» (a menudo el destino de replicación).
- Usa holds solo con propietario y fecha de expiración.
- Monitorea conteo de instantáneas y espacio retenido por instantáneas, no solo CAP del pool.
- Mantén nombres consistentes entre hosts para simplificar herramientas.
FAQ
¿Las instantáneas ralentizan ZFS?
No por existir. Te ralentizan de forma indirecta al aumentar bloques retenidos, lo que empuja el uso del pool, incrementa el trabajo de asignación y puede amplificar la fragmentación.
Además, más metadatos y compartición compleja de bloques pueden hacer que algunas operaciones sean más pesadas.
¿Por qué cambia el número USED de una instantánea con el tiempo?
Porque USED es «bloques únicos que se liberarían si se destruyera esta instantánea». A medida que el dataset vivo cambia, la instantánea se convierte en la última referencia a bloques antiguos,
por lo que su propiedad única puede aumentar.
¿Cuántas instantáneas son demasiadas?
Es la pregunta equivocada. La pregunta correcta es: ¿cuánto espacio retienen las instantáneas y puedes restaurar lo que necesitas dentro de tu RPO/RTO?
Puedes tener miles de instantáneas con bajo churn y estar bien; puedes tener 200 instantáneas en un dataset de VM de alto churn y quedarte sin espacio.
¿Debo mantener retención larga en el origen o en el destino de replicación?
Prefiere retención larga en el destino de replicación. Mantén el origen ligero para rendimiento y para envíos incrementales pequeños.
Conserva anclas explícitas en ambos lados para preservar la replicación incremental.
¿Cuál es la forma más segura de borrar instantáneas?
Seguro significa: sabes por qué existe la instantánea, sabes qué depende de ella (holds/clones/replicación) y la borras según una política.
Empieza listando instantáneas por USED, comprueba holds, comprueba relaciones origin/clone, luego borra de lo más antiguo a lo más nuevo dentro de la clase que estés podando.
¿Puedo snapshotear una base de datos de forma segura sin coordinación?
La consistencia del sistema de archivos no es lo mismo que la consistencia de la aplicación. Algunas bases de datos pueden recuperarse limpiamente; otras pueden necesitar recovery largo o tener problemas lógicos sutiles.
Coordina instantáneas con la base de datos (flush/freeze), o snapshotea una réplica diseñada para backups.
¿Por qué la poda no liberó tanto espacio como esperaba?
Porque las instantáneas que borraste no poseían de forma única los bloques que pensabas, o otras instantáneas aún referencian los mismos bloques.
También revisa clones: un clone puede retener bloques incluso después de podar instantáneas.
¿Los holds son un buen mecanismo de retención a largo plazo?
No. Los holds son un guardarraíl para instantáneas excepcionales, no un motor de política. Si usas holds como retención, acumularás instantáneas permanentes con propiedad poco clara,
y tu sistema de poda se volverá mentiroso.
¿Qué política de retención debería empezar si estoy abrumado?
Empieza con: hourly 48, daily 35, weekly 12, monthly 18—luego ajusta por churn del dataset. Pon imágenes de VM y bases de datos en datasets separados y acorta su retención local.
Haz del destino de replicación tu almacén de largo plazo.
¿Cómo evito que herramientas creen instantáneas aleatorias?
Estandariza la automatización de instantáneas en un solo lugar, limita el acceso administrativo y monitorea la tasa de creación y el cumplimiento de nombres.
Si aparecen instantáneas con prefijos desconocidos, trátalo como deriva de configuración, no como curiosidad.
Conclusión: pasos prácticos siguientes
El infierno de instantáneas es un fallo de política vestido de almacenamiento. ZFS te dio el mecanismo; tú aún debes darle gobernanza.
Si quieres dejar de vivir con miedo de zfs destroy, haz el trabajo una vez y mantenlo aburrido.
- Medir: recopila
usedbysnapshotspor dataset y alerta sobre tendencias de crecimiento. - Clasificar: separa datasets por churn y valor para que una carga no pueda arruinar el pool.
- Estandarizar: adopta un esquema de nombres y añade propiedades de usuario para propiedad y clase de retención.
- Automatizar: crea y poda instantáneas según horario, con conciencia de clones/holds y logging real.
- Alinear replicación: conserva instantáneas ancla en ambos lados; traslada la retención larga al destino.
- Practicar restauraciones: prueba la ruta que importa antes de necesitarla a las 3 a.m.
Haz esto y las instantáneas se convertirán en lo que siempre debieron ser: un botón de deshacer rápido y fiable—no un sitio arqueológico.