Las cadenas de clones son una de esas funcionalidades de ZFS que se sienten como un truco de magia hasta el día en que no puedes destruir un snapshot, no puedes liberar espacio y tu trabajo de replicación empieza a transportar historial que juraste que borraste el trimestre pasado. La herramienta que te saca de ese nudo es zfs promote. No es glamorosa, pero marca la diferencia entre “lo limpio después del almuerzo” y “¿por qué se está fundiendo el teléfono de guardia?”.
Este artículo está escrito desde el lado de producción del rack: el lado donde los datasets tienen propietarios, los SLA tienen dientes y descubres dependencias de clones interesantes durante un bridge de incidentes. Iremos lo bastante profundo para ser precisos, pero no tan académicos como para que no lo puedas usar a las 3 a.m.
Qué hace realmente zfs promote
En ZFS, un clone es un dataset escribible creado a partir de un snapshot. El snapshot es el “origin” de ese clone. Bajo el capó, el clone inicialmente comparte bloques con su snapshot origin, y se desvía a medida que escribe nuevos datos (comportamiento clásico copy-on-write).
La consecuencia operativa clave: un clone crea una dependencia. Mientras el clone exista, el snapshot origin no puede destruirse, porque ZFS todavía lo necesita para representar el punto de partida del clone. Por eso a veces te topas con el muro “can’t destroy snapshot: snapshot has dependent clones”.
zfs promote es la vía de escape: revierte la dependencia entre un clone y su origin. Después de la promoción, el clone se convierte en el dataset “principal” y el antiguo padre pasa a ser el clone dependiente (o, más precisamente: la relación de origin se invierte para que el dataset promovido ya no dependa del snapshot origin antiguo).
Piénsalo como cambiar qué dataset se considera ancestro en la relación origin. No estás copiando datos; estás cambiando qué snapshot se considera el punto de referencia origin para la relación de clones. Por eso la promoción es rápida: es cirugía de metadatos, no reescritura de datos.
Una frase que puedes repetir en una ventana de mantenimiento: promote cambia quién depende de quién; no “fusiona” datasets.
Primer chiste (corto y dolorosamente preciso): si nunca dijiste “es solo un clone” y te arrepentiste al instante, felicidades por tu carrera en almacenamiento: pacífica y sospechosamente corta.
Términos clave que debes tener en la cabeza
- Snapshot: vista de solo lectura de un dataset en un punto en el tiempo.
- Clone: dataset escribible creado a partir de un snapshot.
- Origin: el snapshot del que se creó un clone (visible mediante la propiedad
origin). - Cadena de clones: cuando un clone tiene snapshots y se crean nuevos clones a partir de esos snapshots, formando un grafo de dependencias.
- Promoción: invertir la dependencia origin para que el dataset promovido ya no esté bloqueado por un snapshot ancestro más antiguo.
Cadenas de clones: el árbol genealógico que no querías iniciar
Un caso simple se ve así:
pool/apptiene el snapshotpool/app@baselinepool/app_clonese crea desdepool/app@baseline
En este punto, pool/app@baseline está anclado. No puedes destruirlo mientras exista pool/app_clone, porque ese snapshot es el origin que define el estado inicial del clone.
Ahora añade tiempo y creatividad humana. Alguien toma snapshots del clone. Alguien crea otro clone a partir del clone. Alguien renombra datasets. Alguien replica a un pool DR. La dependencia simple de dos nodos se convierte en un pequeño ecosistema.
En producción, las cadenas de clones tienden a ocurrir en tres lugares previsibles:
- Plantillas de VM e imágenes base: un snapshot base genera docenas de clones (discos de VM), luego se crean nuevas “plantillas” clonadas desde esos clones por conveniencia.
- Entornos CI/CD: clones efímeros creados por build, pero los snapshots base se mantienen “por si acaso” y después se vuelven críticos para el negocio.
- Refrescos de bases de datos: un snapshot de prod se clona en staging, staging se convierte en “el lugar donde se arregla”, y de repente staging tiene snapshots e hijos que deben conservarse.
Aquí está la trampa operativa: las cadenas de clones pueden hacer que el pool parezca que está perdiendo espacio. Eliminás snapshots antiguos, pero el “USED” casi no se mueve. Destruyes lo que crees que es el último dataset dependiente, y otro todavía ancla el snapshot origin. Mientras tanto, tu política de retención se convierte silenciosamente en “para siempre”.
Por qué la promoción importa en la vida real
La promoción sirve para:
- Liberar un dataset antiguo para que pueda borrarse manteniendo el dataset más nuevo.
- Recentralizar la genealogía de una carga de trabajo en el dataset que realmente importa ahora.
- Limpiar un árbol de snapshots donde el dataset “padre” está muerto, pero su snapshot sigue bloqueándolo todo.
- Hacer más sensatos los flujos de replicación estabilizando qué dataset es la fuente autorizada.
Hechos interesantes y contexto histórico
- Los clones de ZFS preceden al auge de contenedores: los clones ya eran una forma práctica de crear copias escribibles rápidamente mucho antes de que “capas copy-on-write” fuera un término de moda en otros ecosistemas.
- La promoción existe porque borrar es más valioso que crear: clonar es fácil; limpiar de forma segura fue lo que requirió un comando de primera clase.
- El “origin” es una propiedad, no una sensación: ZFS registra explícitamente el snapshot origin, por eso puedes consultar y razonar sobre dependencias en lugar de adivinar.
- Las cadenas de clones son grafos, no listas: un snapshot puede tener múltiples clones; cada clone puede tener sus propios snapshots y clones. La gente dice “cadena” porque se siente lineal hasta que deja de serlo.
- El espacio lo mantienen los bloques referenciados, no tu intención: eliminar un snapshot solo libera bloques que no estén referenciados en otro lugar. Los clones son “otro lugar”.
- La promoción suele ser trabajo de metadatos: es rápida porque ZFS ajusta la contabilidad de linaje, no copia terabytes. (Aun así puede tardar en sistemas muy ocupados por sincronización y grupos de transacciones.)
- Renombrar no cambia la ascendencia:
zfs renamecambia nombres; no cambia la relación origin. Así es como “lo renombramos, así que es nuevo” se convierte en un incidente de almacenamiento. - Las políticas de retención de snapshots a menudo ignoran clones: los scripts caseros suelen destruir snapshots por antigüedad y luego chocan contra un clone dependiente y se detienen—o peor, tienen éxito parcial y dejan un desastre.
Cuándo deberías promover (y cuándo no)
Promueve cuando…
- Quieres borrar el dataset original (o sus snapshots antiguos), pero hay clones que dependen de él.
- Un clone se ha convertido en la carga de trabajo real y el dataset original ahora es “solo historia”.
- Heredaste un pool donde el dataset de producción actual es un clone de un clone de un snapshot de 2019 y tu retención es básicamente un museo.
- Necesitas romper una dependencia para que la destrucción de snapshots o el recorte de replicación puedan proceder.
No promuevas cuando…
- No estás seguro de qué dataset es la fuente autorizada y la replicación río arriba espera un linaje concreto.
- Tienes automatizaciones que asumen que un dataset dado es el padre y usan
origino convenciones de nombres como lógica. - Estás intentando “fusionar cambios de vuelta” al padre. La promoción no fusiona; solo reorganiza quién es el origin.
Segundo chiste (porque todo el mundo necesita exactamente uno más): Promover el dataset equivocado es como “responder a todos” en un correo—técnicamente impresionante, socialmente caro y memorablemente irreversible.
Tareas prácticas con comandos (y qué significa la salida)
Estas son tareas reales de operador: “muéstrame la dependencia”, “prueba qué snapshot está anclado”, “promociona de forma segura”, “valida después”. Los comandos asumen un pool llamado tank y datasets como tank/app. Ajusta a tu entorno.
Tarea 1: Encontrar clones y sus origins
cr0x@server:~$ zfs list -t filesystem,volume -o name,origin
NAME ORIGIN
tank/app -
tank/app-clone tank/app@baseline
tank/db -
tank/db-staging tank/db@weekly-2025w51
Interpretación: Cualquier dataset con un origin distinto de - es un clone. Aquí, tank/app-clone depende de tank/app@baseline.
Tarea 2: Ver qué snapshot se niega a morir (error de dependencia)
cr0x@server:~$ zfs destroy tank/app@baseline
cannot destroy 'tank/app@baseline': snapshot has dependent clones
use '-R' to destroy the following datasets:
tank/app-clone
Interpretación: ZFS te está diciendo exactamente qué está anclado. Puedes destruir el clone (-R destruiría recursivamente), o promocionar el clone para poder eliminar el historial antiguo sin borrar la carga activa.
Tarea 3: Mostrar espacio de snapshots y “¿por qué sigue en uso?”
cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -s creation tank/app
NAME USED REFER CREATION
tank/app@baseline 0B 5.20G Mon Nov 10 09:12 2025
tank/app@post-upgrade 88M 5.45G Tue Nov 18 14:03 2025
Interpretación: USED del snapshot es espacio atribuible únicamente a ese snapshot comparado con el dataset en vivo, no el espacio total anclado por su existencia. Los clones aún pueden forzar que ese snapshot exista incluso si “usa 0B”.
Tarea 4: Comprobar la contabilidad de espacio del dataset que apunta a clones/snapshots
cr0x@server:~$ zfs get -H -o name,property,value used,usedbysnapshots,usedbychildren,usedbydataset tank/app
tank/app used 220G
tank/app usedbysnapshots 12G
tank/app usedbychildren 180G
tank/app usedbydataset 28G
Interpretación: Si usedbychildren es enorme, los datasets hijos (incluidos clones montados en otros lugares) están manteniendo espacio referenciado. Si usedbysnapshots es grande, la retención de snapshots es la sospechosa.
Tarea 5: Encontrar dónde está montado el clone (para no promover lo equivocado)
cr0x@server:~$ zfs get -H -o name,value mountpoint tank/app tank/app-clone
tank/app /srv/app
tank/app-clone /srv/app-staging
Interpretación: Así relacionas un nombre de dataset con una carga real. Antes de promocionar, confirma cuál está siendo usada por producción.
Tarea 6: Promocionar el clone (la operación central)
cr0x@server:~$ sudo zfs promote tank/app-clone
Interpretación: Después de esto, tank/app-clone se vuelve independiente de tank/app@baseline en el sentido operativo: el antiguo “padre” pasa a ser el dependiente en la relación origin.
Tarea 7: Verificar origins después de la promoción
cr0x@server:~$ zfs list -o name,origin tank/app tank/app-clone
NAME ORIGIN
tank/app tank/app-clone@baseline
tank/app-clone -
Interpretación: El dataset promovido ahora no tiene origin. El antiguo padre ahora apunta a un snapshot en el dataset promovido. Este es el vuelco. También explica por qué la promoción puede crear/requerir una referencia de snapshot correspondiente en la línea del dataset promovido.
Tarea 8: Ahora destruye el historial de snapshots antiguo (la limpieza)
cr0x@server:~$ sudo zfs destroy tank/app@baseline
cannot destroy 'tank/app@baseline': snapshot has dependent clones
Interpretación: Si aún ves este error, puede que tengas más de un clone o un grafo más profundo. La promoción arregla una relación; no disuelve automáticamente todas las dependencias si varios clones cuelgan del mismo snapshot.
Tarea 9: Enumerar todos los clones de un snapshot (mapeo de dependencias)
cr0x@server:~$ zfs get -H -o name,value clones tank/app@baseline
tank/app@baseline tank/app-clone,tank/app-ci-112,tank/app-ci-113
Interpretación: Esto te dice quién ancla ese snapshot. Solo podrás destruirlo cuando ninguno de estos exista (o cuando cada uno haya sido promovido apropiadamente y la genealogía actualizada).
Tarea 10: Renombrar de forma segura después de promover (estabilizar nombres)
cr0x@server:~$ sudo zfs rename tank/app tank/app-old
cr0x@server:~$ sudo zfs rename tank/app-clone tank/app
Interpretación: La promoción cambia la ascendencia; renombrar cambia los nombres que usan tus herramientas y humanos. En la práctica a menudo promocionas y luego renombras para que producción quede en el nombre canónico del dataset.
Tarea 11: Confirma que nada cambió en los mountpoints (o arréglalo)
cr0x@server:~$ zfs get -H -o name,value mountpoint tank/app tank/app-old
tank/app /srv/app
tank/app-old /srv/app-staging
Interpretación: Renombrar no siempre hace lo que querés con los mountpoints si estaban explícitamente configurados. Confirma y establece los mountpoints deliberadamente.
cr0x@server:~$ sudo zfs set mountpoint=/srv/app tank/app
cr0x@server:~$ sudo zfs set mountpoint=/srv/app-old tank/app-old
Tarea 12: Validar el efecto de “espacio anclado” después de la limpieza
cr0x@server:~$ zfs list -o name,used,usedbysnapshots,usedbychildren,usedbydataset tank/app-old
NAME USED USEDBYSNAPSHOTS USEDBYCHILDREN USEDBYDATASET
tank/app-old 28G 0B 0B 28G
Interpretación: El dataset antiguo ahora es un dataset normal (o un clone) sin equipaje de hijos/snapshots. Si lo vas a retirar, ahora es sencillo snapshotear/ destruir según la política.
Tarea 13: Encontrar todos los clones en un subárbol (auditoría antes de mantenimiento)
cr0x@server:~$ zfs list -r -o name,origin tank | awk '$2 != "-" {print}'
tank/app-ci-112 tank/app@baseline
tank/app-ci-113 tank/app@baseline
tank/db-staging tank/db@weekly-2025w51
Interpretación: Esto es un inventario rápido y sucio. En entornos grandes, el crecimiento de clones rara vez está documentado; lo descubres preguntándole a ZFS, no a Slack.
Tarea 14: Comprobar holds que impiden la destrucción de snapshots (problema distinto, síntoma similar)
cr0x@server:~$ zfs holds tank/app@baseline
NAME TAG TIMESTAMP
tank/app@baseline keep Wed Dec 10 10:21 2025
Interpretación: Si la destrucción falla pero los clones no son la razón, puede ser un hold de usuario. La promoción no te ayudará aquí; necesitas liberar el hold.
cr0x@server:~$ sudo zfs release keep tank/app@baseline
Tarea 15: Simular una decisión de “destroy recursively” con zfs destroy -nvp
cr0x@server:~$ sudo zfs destroy -nvp tank/app@baseline
would destroy tank/app@baseline
would destroy tank/app-ci-112
would destroy tank/app-ci-113
would reclaim 41.2G
Interpretación: Así evitas el movimiento que podría arruinar tu carrera al borrar un entorno de CI que alguien silenciosamente convirtió en producción el año pasado.
Replicación y copias: zfs send/receive con clones
Las cadenas de clones no solo complican la eliminación; complican la replicación. En el momento en que dependés de envíos incrementales, implícitamente aceptaste el linaje como contrato: “este dataset en el receptor comparte historial de snapshots con el emisor”. Los clones introducen bifurcaciones en ese historial.
Qué suele salir mal
Dos sorpresas clásicas:
- La replicación envía más de lo esperado porque replicaste la rama equivocada o mantuviste un snapshot origin vivo, por lo que el receptor también debe retenerlo.
- La replicación falla con “incremental source does not match” porque alguien promovió/renombró en un lado y no en el otro, rompiendo el linaje de snapshots asumido.
La promoción en sí no es inherentemente incompatible con la replicación, pero sí es un cambio estructural. Si promovés un dataset que se replica de forma incremental, tratalo como una migración de esquema: coordiná, registrá y validá ambos lados.
Tarea 16: Inspeccionar el linaje de snapshots para replicación (base común)
cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation tank/app | tail -n 5
tank/app@replica-2025-12-20 Sat Dec 20 01:00 2025
tank/app@replica-2025-12-21 Sun Dec 21 01:00 2025
tank/app@replica-2025-12-22 Mon Dec 22 01:00 2025
tank/app@replica-2025-12-23 Tue Dec 23 01:00 2025
tank/app@replica-2025-12-24 Wed Dec 24 01:00 2025
Interpretación: Un esquema de nombres de snapshots estable y predecible es tu amigo. Si tus snapshots son ad hoc, las dependencias de clones son más difíciles de razonar y replicar limpiamente.
Tarea 17: Usar un stream de replicación con cuidado (ejemplo incremental)
cr0x@server:~$ sudo zfs send -I tank/app@replica-2025-12-23 tank/app@replica-2025-12-24 | sudo zfs receive -u backup/app
Interpretación: -I envía todos los snapshots intermedios. Si las cadenas de clones y promociones cambiaron los snapshots disponibles, el receptor puede no tener la base esperada. Confirmá siempre que la snapshot base exista en ambos extremos antes de ejecutar incrementales.
Tarea 18: Confirmar origin y pensar en identidad similar a GUID (chequeo pragmático)
cr0x@server:~$ zfs get -H -o name,property,value origin tank/app backup/app
tank/app origin -
backup/app origin -
Interpretación: La replicación no requiere que el dataset receptor sea un clone, pero sí requiere snapshots compartidos para incrementales. No confundas “origin” (relación de clones) con “historial compartido” (conjunto de snapshots de replicación). Conceptualmente se solapan, pero son mecanismos diferentes.
Tres mini-historias del mundo empresarial
1) Incidente causado por una suposición errónea: “Borrar el snapshot liberará espacio”
En una gran empresa muy normal, un equipo de aplicaciones gestionaba su propio pool ZFS para artefactos de build y entornos “temporales”. Su script de retención era simple: destruir snapshots mayores de 30 días. Cuando el pool se acercó al 90% de uso, hicieron lo que todo el mundo hace bajo presión: borraron más snapshots.
No sirvió de nada. zfs list mostraba menos snapshots, pero zpool list no se movió. El ingeniero de guardia supuso que ZFS era “lento para recuperar espacio” y programó un reinicio porque—bueno—a veces funciona en otras cosas.
El reinicio no recuperó espacio. El pool alcanzó una marca más alta, las asignaciones empezaron a fallar y algunos trabajos comenzaron a producir salidas corruptas (no porque ZFS las corrompiera, sino porque herramientas río arriba no manejaron ENOSPC). El puente de incidentes se llenó con el sonido de personas descubriendo que “disco lleno” es un hobby cross-funcional.
La solución fue vergonzosamente sencilla: los snapshots que estaban borrando estaban anclados por clones creados para trabajos de CI. Esos clones se conservaron más de 30 días porque a alguien le gustaba tener “builds reproducibles antiguos”. El script de retención nunca comprobó dependencias de clones y silenciosamente omitió snapshots que no pudo destruir. Fue el peor tipo de fallo: uno silencioso.
Auditaron los origins, promovieron los pocos clones que se habían vuelto entornos permanentes y borraron los datasets clones verdaderamente efímeros. El espacio bajó de inmediato y el incidente terminó con las lecciones habituales: ZFS hizo exactamente lo prometido; los humanos no.
2) Optimización que salió mal: “Clonemos todo para ahorrar tiempo”
Un equipo de plataforma quería acelerar refrescos de bases de datos para QA. Tenían un proceso ordenado: snapshot de producción nocturno, replicación, restauración a QA. Era lento y el equipo tenía presión de rendimiento. Alguien propuso una idea ingeniosa: dejar de restaurar; simplemente clonar el snapshot más reciente y entregarlo a QA como dataset escribible. Los refrescos serían instantáneos.
Funcionó de maravilla durante un mes. QA lo adoró. El equipo de plataforma disfrutó la rara sensación de haber ganado tiempo. Luego el almacenamiento empezó a verse raro: la retención de snapshots no liberaba espacio, los streams de replicación crecían y el pool DR retenía historial mucho más allá de la política. Todos culparon a la “sobrecarga de ZFS”. Nadie dijo “dependencia de clones” en voz alta hasta que alguien intentó borrar un snapshot antiguo y encontró el error de dependent-clone.
El verdadero problema fue organizacional, no técnico. La optimización convirtió a los datasets de QA en entornos perdurables similares a producción con sus propios hábitos de snapshots. Los ingenieros empezaron a crear clones desde clones para ejecutar tests en paralelo. El grafo resultante ancló meses de snapshots de prod. El truco de “refresco instantáneo” reescribió silenciosamente el contrato de retención para todo el sistema.
Se recuperaron trazando una frontera clara: los clones efímeros recibieron un TTL aplicado por automatización y los entornos QA de larga vida fueron promovidos para que ya no anclaran el historial de prod. Mantuvieron la optimización, pero solo después de agregar protecciones: inventario de orígenes de clones, puntos de promoción explícitos y una política que decía “los clones son ganado salvo que se promuevan explícitamente”.
3) Una práctica aburrida pero correcta que salvó el día: “Nombra snapshots con intención y ensaya la promoción”
Un equipo cercano a finanzas gestionaba una granja de VM respaldada por ZFS. Tenían la complejidad habitual: plantillas, clones para VMs y un pequeño ejército de snapshots para parches y rollback. Nada especial—lo suficiente para hacer que una caída sea picante.
Su práctica aburrida fue esta: cada clone de disco de VM tenía una etiqueta en sus propiedades ZFS con propietario y entorno, cada snapshot de plantilla tenía un nombre estable y una vez por trimestre ejecutaban un ensayo de mantenimiento donde promovían deliberadamente un clone en un pool de laboratorio y validaban que su backup/replicación seguía comportándose.
Un día, un ingeniero intentó retirar una plantilla antigua. Borrar sus snapshots falló porque existían clones dependientes. Aquí es donde los equipos suelen entrar en pánico. Pero el inventario de este equipo les dijo exactamente qué clones eran de larga vida y cuáles efímeros. Promovieron los de larga vida, luego destruyeron el resto y finalmente eliminaron el historial antiguo de la plantilla.
La mejor parte no fue la promoción—fue lo poco emocionante que fue. Sin tiempo de inactividad sorpresa. Sin arqueología de “¿quién es el propietario de este dataset?”. Sin colapso de replicación. La orden de cambio parecía aburrida, que es el mayor cumplido que podés hacer al trabajo de almacenamiento.
Guion rápido de diagnóstico
Esta es la secuencia “tengo 15 minutos antes de que el pool alcance 95% y mi pager empiece a componer poesía”. El objetivo es identificar si tu cuello de botella son clones anclando snapshots, retención de snapshots, datasets hijos o algo completamente distinto.
Primero: confirma el problema a nivel de pool y su naturaleza
cr0x@server:~$ zpool list
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 7.25T 6.71T 560G - - 38% 92% 1.00x ONLINE -
Interpretación: Un CAP alto es la emergencia. La fragmentación puede importar, pero normalmente no es la causa de primer orden de “por qué la eliminación no liberó espacio”.
Segundo: encuentra los mayores consumidores y si son snapshots o hijos
cr0x@server:~$ zfs list -o name,used,usedbysnapshots,usedbychildren,usedbydataset -S used | head -n 10
NAME USED USEDBYSNAPSHOTS USEDBYCHILDREN USEDBYDATASET
tank/vm 4.90T 900G 3.80T 200G
tank/app 220G 12G 180G 28G
tank/db 140G 60G 0B 80G
Interpretación: Si usedbychildren domina, tu espacio está en hijos (a menudo clones). Si usedbysnapshots domina, la retención es tu sospechosa. Si usedbydataset domina, los datos en vivo son grandes y no estás borrando lo correcto.
Tercero: comprueba dependencias de clones que anclan snapshots antiguos
cr0x@server:~$ zfs list -t filesystem,volume -o name,origin -r tank/vm | awk '$2 != "-" {print}' | head
tank/vm/qa-01 tank/vm/template@golden
tank/vm/qa-02 tank/vm/template@golden
tank/vm/prod-17 tank/vm/template@2025q3
Interpretación: Esto te dice si existen clones y qué anclan. Si no podés borrar un snapshot, normalmente esta es la razón.
Cuarto: para un snapshot anclado específico, lista sus clones
cr0x@server:~$ zfs get -H -o value clones tank/vm/template@golden
tank/vm/qa-01,tank/vm/qa-02,tank/vm/ci-881,tank/vm/ci-882
Interpretación: Ahora tenés la lista de tareas: destruir clones efímeros, promover los que deben perdurar y después eliminar el historial del snapshot antiguo.
Quinto: chequeo de cordura de la presión I/O antes de hacer operaciones pesadas
cr0x@server:~$ zpool iostat -v 1 3
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 6.71T 560G 380 520 42.1M 88.3M
mirror-0 3.35T 280G 190 260 21.0M 44.1M
sda - - 95 130 10.5M 22.1M
sdb - - 95 130 10.5M 22.0M
mirror-1 3.36T 280G 190 260 21.1M 44.2M
sdc - - 95 130 10.6M 22.1M
sdd - - 95 130 10.5M 22.1M
Interpretación: Las promociones suelen ser rápidas, pero las operaciones de limpieza que desencadenan muchas liberaciones pueden coincidir con escrituras intensas y aumentar latencias. Si ya estás al límite, programá la limpieza o limitá las cargas.
Errores comunes, síntomas y soluciones
Error 1: Intentar destruir el snapshot origin sin abordar los clones
Síntoma: cannot destroy ... snapshot has dependent clones
Solución: Identificá los clones dependientes con zfs get clones pool/ds@snap. Decidí: destruir clones (efímeros) o promover clones (de larga vida), luego reintentar la destrucción del snapshot.
Error 2: Promover el dataset que querías borrar
Síntoma: Tras la promoción, el dataset “equivocado” tiene origin=- y tu automatización apunta al mountpoint incorrecto.
Solución: Antes de promover, confirmá mountpoints y escritores activos. Usá zfs get mountpoint y comprobaciones a nivel OS (qué proceso escribe dónde). Si ya promoviste, podés recuperar renombrando datasets y ajustando mountpoints; los datos no se pierden, pero cambió el linaje, así que actualizá runbooks y asunciones de replicación.
Error 3: Pensar que la promoción liberará espacio inmediatamente
Síntoma: Promoviste un clone pero el uso del pool no baja.
Solución: La promoción no borra nada. Solo te permite destruir snapshots/datasets antes anclados. Seguí el procedimiento: destruí los snapshots/datasets obsoletos tras verificar que las dependencias desaparecieron.
Error 4: Confundir “snapshot USED” con “espacio anclado por el snapshot”
Síntoma: Un snapshot muestra USED=0B, pero su destrucción está bloqueada y/o parece anclar mucho espacio.
Solución: Usá zfs get clones y propiedades usedby* a nivel de dataset para entender el espacio. USED en un snapshot no es una contabilidad completa de lo que habilita en otro lugar.
Error 5: Dejar que el crecimiento de clones se vuelva política por accidente
Síntoma: Snapshots “baseline” antiguos no se pueden borrar años después; la replicación mantiene grandes historiales; nadie sabe qué puede destruirse.
Solución: Agregá metadatos (propiedades como owner/env), TTL automatizado para clones efímeros y una auditoría trimestral: listar clones y sus origins, identificar cuáles deben promoverse para convertirse en linajes independientes.
Error 6: Romper la replicación incremental cambiando el linaje unilateralmente
Síntoma: El envío incremental falla porque el receptor carece del snapshot base esperado; después de promover, los nombres y la ascendencia de snapshots ya no coinciden.
Solución: Coordiná la promoción con la replicación. Validá snapshots comunes en ambos extremos. En algunos casos deberás volver a sembrar con un envío completo o ajustar la replicación a nuevas bases.
Listas de verificación / plan paso a paso
Lista A: “Necesito borrar un dataset antiguo, pero sus snapshots están anclados”
- Identificá el dataset y los snapshots específicos que querés eliminar.
- Listá los clones de esos snapshots con
zfs get clones. - Clasificá cada clone: efímero (seguro para destruir) vs de larga vida (debe conservarse).
- Para cada clone de larga vida, confirmá que es el dataset correcto para preservar (mountpoint, propietario, escritores activos).
- Promové los clones de larga vida (
zfs promote). - Destruí los clones efímeros (preferí
zfs destroy -nvpprimero). - Destruí los snapshots ahora sin anclajes.
- Destruí o archivá el dataset retirado (tras un snapshot de seguridad final si la política lo requiere).
Lista B: “Estoy promoviendo un clone que es (o podría ser) producción”
- Congelá la ventana de cambios; avisá a propietarios de apps y backups sobre el cambio de linaje.
- Verificá el dataset y el mountpoint; verificá que la carga en ejecución use ese mount.
- Tomá un snapshot de seguridad tanto del padre como del clone.
- Registrá la salida de
zfs list -o name,originantes del cambio. - Ejecutá
zfs promote. - Verificá el vuelco de origin con
zfs list -o name,origin. - Si querés, renombrá datasets para restaurar la nomenclatura canónica.
- Validá I/O de la aplicación, montajes y trabajos de replicación.
- Sólo entonces procedé a borrar snapshots/datasets padres antiguos.
Lista C: “Necesitamos evitar que las cadenas de clones sean una sorpresa trimestral”
- Definí qué datasets pueden ser orígenes de clones (plantillas, baselines).
- Etiquetá los datasets clone con propietario/entorno usando propiedades de usuario de ZFS.
- Automatizá la limpieza TTL para clones efímeros y sus snapshots.
- Ejecutá una auditoría semanal: listá todos los datasets con
originno vacío. - Revisá los “snapshots anclados”: snapshots con muchos clones.
- Promové clones de larga vida intencionadamente, no por accidente.
Preguntas frecuentes
1) ¿zfs promote copia datos?
No. La promoción es principalmente trabajo de metadatos que cambia la relación origin. Tus bloques permanecen donde están; ZFS cambia cómo contabiliza la ascendencia y las dependencias.
2) ¿Promover un clone liberará espacio inmediatamente?
No. La promoción te permite eliminar snapshots/datasets que antes estaban anclados. El espacio se recupera cuando destruyes los snapshots/datasets ya no necesarios y esos bloques dejan de estar referenciados.
3) ¿Puedo promover un dataset que tiene hijos?
En la práctica sí, pero tenés que tener cuidado: los datasets hijos, snapshots y clones pueden hacer que el grafo de dependencias sea más grande de lo que creés. Audita el subárbol primero (zfs list -r -o name,origin) para no promover hacia una situación más enredada.
4) ¿Qué le pasa a la propiedad origin después de la promoción?
El dataset promovido mostrará origin=-. El dataset que solía ser el padre normalmente ganará un origin apuntando a un snapshot del dataset promovido (la relación se invierte).
5) ¿Es seguro promover en un sistema en vivo?
Se hace comúnmente en sistemas en vivo, pero “seguro” depende de qué más esté ocurriendo: I/O intenso, replicación en curso y automatizaciones que reaccionan a cambios de dataset pueden convertir una operación simple en algo ruidoso. Promové durante una ventana controlada y validá montajes y herramientas después.
6) ¿Por qué no puedo destruir un snapshot aunque no haya clones?
Dos razones frecuentes: existe un hold de usuario (zfs holds), o el snapshot es necesario para el historial de replicación incremental (no es un “bloqueo” a nivel ZFS, pero tu proceso puede depender de él). ZFS te dirá si los clones bloquean la destrucción; los holds son un tema aparte.
7) ¿Renombrar un dataset ayuda con las dependencias de clones?
No. Renombrar cambia el nombre, no la ascendencia. Si un snapshot está anclado por clones, renombrar no lo desanclará. Promoción o destrucción de clones es lo que cambia la dependencia.
8) ¿Cómo encuentro todos los snapshots que tienen clones?
Podes iterar snapshots y comprobar la propiedad clones. Prácticamente, empezá por los datasets donde el espacio está atascado y consultá sus snapshots más antiguos para clones. En muchos entornos es más rápido listar primero todos los datasets con origin establecido y luego mapearlos de vuelta a los snapshots origin.
9) ¿Puede la promoción romper mi replicación incremental?
Pue-de, si tu workflow de replicación asume un linaje de snapshots y lo cambiás en el emisor sin coordinar con el receptor. Tratá la promoción como un cambio de linaje: verificá snapshots compartidos y estate preparado para reseedar o ajustar baselines.
10) ¿Cuál es la forma más segura de experimentar con la promoción?
Hacelo en un pool de pruebas con un dataset pequeño que mime tu estructura: creá un snapshot, clonalo, agregá snapshots en ambos lados, creá un clone-de-un-clone, luego promové y observá los vuelcos de origin. La memoria muscular paga dividendo cuando lo hacés bajo presión.
Conclusión
zfs promote es uno de esos comandos que parece una esquina nicho de ZFS hasta que te das cuenta de que es la clave para borrar cosas de forma segura en un mundo lleno de clones. La promoción no mueve datos; mueve responsabilidad. Te permite declarar “este dataset es la nueva verdad” y luego retirar limpiamente la verdad antigua sin aplastar el presente por accidente.
El enfoque de nivel producción es consistente: inventariá orígenes de clones, promové intencionalmente, validá después y solo entonces destruí los snapshots y datasets que querías retirar. Si hacés eso, las cadenas de clones dejan de ser espeluznantes. Se convierten en otra herramienta que podés usar—con confianza—sin pagar intereses ocultos después.