Los rollbacks deberían resultar aburridos. Pulsas el botón, tu ritmo cardiaco se mantiene estable y el informe posterior al incidente es una sola frase: “Restaurado desde la snapshot”.
En la práctica, el pánico llega antes —en el momento en que tienes que elegir qué snapshot es “la buena”. Si tus nombres de snapshot parecen un cajón de trastos, no estás haciendo copias de seguridad; estás acumulando sorpresas.
Por qué el nombrado es un control de producción (no una pérdida de tiempo)
El nombrado de snapshots es uno de esos temas que atraen a dos tipos de personas: quienes piensan que es estética, y quienes han tenido que hacer rollback de un dataset mientras un VP observa cómo se actualiza el canal de incidentes. El segundo grupo tiene razón.
Una snapshot de ZFS es una vista puntual en el tiempo. Es barata de crear, rápida de listar y brutalmente literal: captura bloques, no tu intención. El único sitio donde tu intención vive de forma fiable es en el nombre de la snapshot y los metadatos alrededor (propiedades, holds, bookmarks). Por eso el nombrado es un control operativo—como rotular los interruptores en una sala de servidores. Claro, puedes adivinar. También puede que no te lo puedas permitir.
Aquí está la realidad operativa:
- Tomarás más snapshots de las que planeas.
- Olvidarás por qué tomaste al menos el 30% de ellas.
- Necesitarás la correcta bajo presión.
- Tendrás al menos una snapshot tomada durante una caída parcial (y parecerá “reciente”).
Así que el objetivo no es “nombres bonitos”. El objetivo es hacer que el rollback correcto sea el camino de menor resistencia, y el rollback equivocado sorprendentemente difícil.
Una verdad seca: si tu lista de snapshots no te dice instantáneamente cuándo, por qué, quién/qué y si es segura, no estás gestionando un sistema de snapshots. Estás gestionando una carpeta de capturas de pantalla.
Broma #1: Una snapshot sin esquema de nombres es como un gestor de contraseñas lleno de “password123”—técnicamente funciona, espiritualmente condenado.
Datos interesantes y contexto histórico
Un poco de contexto ayuda porque el nombrado en ZFS se sitúa en la intersección de sistemas de archivos, gestión de volúmenes y cultura operativa. Algunos hechos concretos:
- ZFS fue diseñado como un sistema integrado: sistema de archivos + gestor de volúmenes + checksum + snapshots, desarrollado originalmente en Sun Microsystems a principios de los 2000.
- Los nombres de snapshots no son globales: están limitados a un dataset o zvol (por ejemplo,
pool/app@name). Dos datasets pueden tener cada uno@dailyy a ZFS no le importa. - Las snapshots solo son escribibles mediante clones: una snapshot es de solo lectura; puedes
zfs clonepara obtener un dataset escribible. Ese flujo moldea cómo nombras puntos “candidatos a restaurar”. - Enviar snapshots depende de los nombres:
zfs send -iincremental depende de una snapshot ancestro común. Un nombrado desordenado hace la ascendencia ambigua para los humanos aunque ZFS pueda calcularla. - Las snapshots son baratas, hasta que dejan de serlo: no duplican bloques de inmediato, pero retienen bloques antiguos. Una política de snapshots puede convertirse silenciosamente en tu mayor consumidor de espacio.
- ZFS soporta “holds”: puedes aplicar una etiqueta de hold para que una snapshot no se destruya. Es básicamente tu mecanismo de “retención legal” / “no borrar, en serio”.
- Existen bookmarks: son referencias ligeras a puntos de snapshot para flujos de replicación, y pueden reducir la sobrecarga de retención cuando necesitas “anclas de replicación” sin mantener snapshots completas.
- Los nombres forman parte de tu rastro de auditoría: ZFS en sí no guardará tu número de ticket o la razón a menos que lo pongas en el nombre o en propiedades. Los equipos de operaciones típicamente usan ambos.
- Hay múltiples ramas de ZFS: OpenZFS es la implementación comunitaria usada en illumos, FreeBSD, Linux y más. Las convenciones de nombres son tu capa de portabilidad entre diferencias de herramientas.
Qué hace un buen nombre de snapshot en el mundo real
Un buen nombre de snapshot es una entrada de índice. Debe permitirte responder estas preguntas sin desplazarte:
- ¿Cuándo? se tomó (zona horaria incluida, o UTC inequívoco)?
- ¿Qué lo generó? (programa automático, trabajo de CI, operador manual, runbook de upgrade)?
- ¿Por qué? (pre-upgrade, pre-migración, post-backup, captura de incidente)?
- ¿Qué nivel de seguridad? (puede eliminarse; debe mantenerse; es “golden”)?
- ¿A qué flujo de trabajo pertenece (replicación, gestión de VM, quiesce de BD, despliegue de app)?
El sistema de nombres también debe ser:
- Ordenable cronológicamente.
- Estable entre equipos y herramientas de automatización.
- Seguro de teclear bajo estrés (sin espacios, sin peligros de shell, sin puntuación “creativa”).
- Compatible con cómo seleccionas snapshots en scripts (
grep,awko filtros de propiedades ZFS).
Y debe anticipar modos de fallo. El grande: tendrás múltiples snapshots tomadas alrededor del mismo evento, pero no todas son puntos de restauración igualmente buenos. Ejemplo: datasets de bases de datos. Una snapshot “crash-consistent” puede ser aceptable, o puede requerir reproducción de journals por 20 minutos que asuste a todo el mundo. Tu nombrado debe distinguir “quiesced” de “no quiesced”, o tu on-call aprenderá la diferencia en directo.
Una idea parafraseada de Werner Vogels (CTO de Amazon): Todo falla todo el tiempo; diseña y opera como si la falla fuera normal.
(idea parafraseada)
El sistema de nombres de snapshots: convenciones que escalan
Regla 0: Usa UTC en los nombres de snapshot
La hora local es para calendarios. Las operaciones de restauración son problemas de sistemas distribuidos: equipos en varias zonas horarias, servidores con relojes que se desincronizan y logs ya en UTC. Pon UTC en el nombre de la snapshot y eliminas toda una clase de discusiones “espera, ¿fue eso antes del deploy?”.
Recomendación de formato: YYYYMMDDThhmmssZ (estilo ISO, sin dos puntos). Ordena lexicográficamente y es obvio para los humanos.
Regla 1: Separa “programación” de “intención”
Muchos equipos empiezan con @daily, @hourly, @weekly. Es simpático hasta que necesitas restaurar “la snapshot justo antes de la migración de esquema”. Ahora cuentas dailies. No lo hagas.
En lugar de eso, codifica:
- cadencia (hourly/daily/adhoc)
- intención (predeploy, preupgrade, postbackup, incident)
- creador (auto/manual/ci)
Regla 2: Usa un orden de tokens predecible
Elige un orden canónico y no lo dejes. Los humanos escanean de izquierda a derecha. Los scripts analizan de izquierda a derecha. Tu yo futuro estará cansado y poco impresionado por la creatividad.
Un patrón práctico y amigable para producción:
<prefix>.<cadence>.<creator>.<intent>.<ts>[.<ticket>][.<flags>]
Nombres de ejemplo:
snap.hourly.auto.base.20260204T010000Zsnap.daily.auto.base.20260204T000000Zsnap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345snap.adhoc.ci.predeploy.20260204T015912Z.PR4812snap.adhoc.manual.incident.20260204T021100Z.INC7781.holdsnap.adhoc.auto.quiesced-db.20260204T020000Z
Notas:
- Prefijo (
snap) te permite filtrar tus propias snapshots de las herramientas del proveedor. - Los puntos son aburridos y amigables con el shell. Evita espacios. Evita dos puntos. Evita “@prod:good”.
- IDs de ticket son opcionales pero valiosos. No pongas información sensible en nombres; aparecen en logs, monitorización y flujos de replicación.
- Flags son palabras cortas como
hold,gold,quiesced. Evita que se conviertan en prosa.
Regla 3: Pon la “especialidad” al final, pero mantén el timestamp antes
La gente quiere añadir “-final” o “-good”. Si lo pones antes del timestamp, se rompe el orden. Si lo pones después, el orden sigue siendo cronológico y sigues teniendo la pista.
Bueno: snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345.gold
Malo: snap.adhoc.manual.gold.preupgrade.CHG12345.20260203T221530Z
Regla 4: Codifica la quiescencia explícitamente para las apps que lo requieren
Hay datasets donde la consistencia por crash está bien (contenido estático, la mayoría de discos VM si el journaling del invitado está sano). Luego hay datasets donde es una ruleta (bases de datos muy activas, ciertas colas de mensajes, apps legacy). Para esos, tu sistema de nombres debería incluir un token como:
quiesced-db(app confirmó flush / fsfreeze / coordinación)crash(sin coordinación; la restauración puede requerir recuperación)
Esto no es un juicio moral. Es etiquetado de riesgo.
Regla 5: Usa propiedades ZFS para metadatos legibles por máquina (y nombres para humanos)
Los nombres de snapshot son visibles. Las propiedades son consultables. Usa ambos. Un patrón práctico:
- El nombre lleva cadencia/intención/timestamp y quizá un ticket.
- Las propiedades llevan metadatos estructurados como
com.company:reason,com.company:owner,com.company:expiry.
¿Por qué ambos? Porque los humanos eligen snapshots por nombre durante incidentes, y la automatización necesita selectores fiables que no dependan de parsear una cadena que inevitablemente “mejorarás” algún día.
Regla 6: Planifica la replicación y la retención desde el día uno
Si replicáis snapshots, vuestros nombres forman parte del protocolo entre sitios. Un sistema de nombres que no es estable se convierte en una caída de replicación disfrazada de “limpieza”.
Recomendación práctica:
- Mantén las snapshots de cadencia automatizada en un patrón estricto: fáciles de buscar, fáciles de expirar.
- Mantén las snapshots “de evento” (preupgrade/incident) en un patrón distinto y protégelas con holds.
- Usa bookmarks como anclas de replicación cuando corresponda, pero nómbralos con la misma disciplina de timestamp.
Tareas prácticas: comandos, salidas y decisiones (12+)
Task 1: Listar snapshots en un dataset, ordenadas por tiempo de creación
cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation tank/app
NAME CREATION
tank/app@snap.daily.auto.base.20260203T000000Z Mon Feb 3 00:00 2026
tank/app@snap.hourly.auto.base.20260203T230000Z Mon Feb 3 23:00 2026
tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345 Tue Feb 3 22:15 2026
Qué significa la salida: Tienes timestamps de creación desde ZFS mismo, no inferidos del nombre. Eso importa cuando los relojes se desincronizan o alguien renombra patrones manualmente.
Decisión: Si la hora de creación de ZFS no coincide con el token timestamp en el nombre, tienes un problema de procesos (o de sincronización horaria). Arregla NTP y tu automatización antes de confiar en los timestamps para trabajo de incidentes.
Task 2: Mostrar espacio retenido por snapshots (por qué “barato” se vuelve “caro”)
cr0x@server:~$ zfs list -o name,used,refer,usedbysnapshots tank/app
NAME USED REFER USEDBYSNAPSHOTS
tank/app 850G 620G 210G
Qué significa la salida: USEDBYSNAPSHOTS es espacio retenido porque las snapshots referencian bloques antiguos.
Decisión: Si USEDBYSNAPSHOTS es alto y tu pool está justo de espacio libre, deberías expirar snapshots (preferiblemente por política y no por pánico). Si es alto en un dataset con mucho churn, revisa la cadencia y retención inmediatamente.
Task 3: Encontrar las snapshots más grandes (útil para limpieza dirigida)
cr0x@server:~$ zfs list -t snapshot -o name,used,refer -s used tank/app
NAME USED REFER
tank/app@snap.hourly.auto.base.20260203T230000Z 18G 620G
tank/app@snap.hourly.auto.base.20260203T220000Z 14G 615G
tank/app@snap.adhoc.manual.incident.20260203T210100Z.INC7781.hold 9G 610G
Qué significa la salida: USED de la snapshot es cuánto espacio único mantiene la snapshot vivo en comparación con el dataset en directo.
Decisión: Snapshots horarias grandes implican churn pesado. Considera bajar la frecuencia, dividir datasets para aislar el churn, o asegurar que la app escribe en un dataset dedicado con retención diferente.
Task 4: Verificar que una snapshot existe antes de hacer algo irreversible
cr0x@server:~$ zfs list -t snapshot tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345
NAME
tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345
Qué significa la salida: Si imprime el nombre, existe. Si da error, tu plan de restauración ya está mal.
Decisión: Si no puedes identificar positivamente la snapshot, detente. No “aproximes” con la daily más cercana. Así es como restauras al esquema equivocado.
Task 5: Crear una “snapshot de evento” con un nombre disciplinado
cr0x@server:~$ ts=$(date -u +%Y%m%dT%H%M%SZ); zfs snapshot tank/app@snap.adhoc.manual.preupgrade.${ts}.CHG12345
Qué significa la salida: Sin salida es éxito. ZFS es así.
Decisión: Sigue inmediatamente con un hold para cambios de alto riesgo (tarea siguiente). Si no lo haces, un trabajo de limpieza puede eliminar la única snapshot que realmente te importa.
Task 6: Proteger una snapshot con una etiqueta de hold (hacer que la eliminación falle por diseño)
cr0x@server:~$ zfs hold keep tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345
cr0x@server:~$ zfs holds tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345
NAME TAG TIMESTAMP
tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345 keep Tue Feb 3 22:16 2026
Qué significa la salida: La snapshot tiene una etiqueta de hold keep. No puede destruirse hasta que se liberen los holds.
Decisión: Para snapshots de incidentes y pre-upgrade, los holds son un seguro barato. Úsalos. Luego crea un proceso para liberarlos cuando el cambio esté validado como seguro.
Task 7: Añadir metadatos estructurados mediante propiedades de usuario (consultables luego)
cr0x@server:~$ zfs set com.acme:reason="preupgrade app 7.4" tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345
cr0x@server:~$ zfs set com.acme:ticket="CHG12345" tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345
cr0x@server:~$ zfs get -H -o property,value com.acme:reason,com.acme:ticket tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345
com.acme:reason preupgrade app 7.4
com.acme:ticket CHG12345
Qué significa la salida: La snapshot ahora lleva metadatos legibles por máquina que puedes filtrar sin parsear el nombre.
Decisión: Si ejecutas automatización, orienta tus scripts a propiedades para la selección y mantén nombres legibles para humanos. Reduce la lógica frágil de parseo.
Task 8: Hacer rollback de un dataset (y entender qué estás sobrescribiendo)
cr0x@server:~$ zfs rollback -n tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345
would rollback tank/app to tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345
would destroy the following snapshots:
tank/app@snap.hourly.auto.base.20260203T230000Z
tank/app@snap.daily.auto.base.20260204T000000Z
Qué significa la salida: -n es una ejecución en seco. Hacer rollback descartará snapshots más nuevas a menos que uses -r con cuidado o las preserves clonando.
Decisión: Si el rollback destruiría snapshots que necesitas para replicación o auditoría, detente y considera clonar en su lugar (Tarea 9). El dry-run es innegociable en producción.
Task 9: Clonar una snapshot en vez de hacer rollback (más seguro para forense)
cr0x@server:~$ zfs clone tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345 tank/app-restore
cr0x@server:~$ zfs list -o name,used,refer,mountpoint tank/app-restore
NAME USED REFER MOUNTPOINT
tank/app-restore 1G 620G /tank/app-restore
Qué significa la salida: El clone es escribible e inicialmente pequeño (USED) porque comparte bloques con la snapshot.
Decisión: Para respuesta a incidentes, clonar suele ser el primer movimiento correcto. Puedes validar datos, extraer ficheros o ejecutar comprobaciones de la aplicación sin destruir el estado actual.
Task 10: Send/receive con ascendencia clara (replicación que no adivina)
cr0x@server:~$ zfs send -nvP -i tank/app@snap.daily.auto.base.20260203T000000Z tank/app@snap.daily.auto.base.20260204T000000Z
send from @snap.daily.auto.base.20260203T000000Z to tank/app@snap.daily.auto.base.20260204T000000Z estimated size is 12.3G
total estimated size is 12.3G
TIME SENT SNAPSHOT
Qué significa la salida: Envío en seco (-n) con estimación de progreso (-P). Confirma que la snapshot base incremental existe y el tamaño del delta.
Decisión: Si el tamaño estimado es inesperadamente grande, es una señal de churn (o cambios en compresión/encriptación). Revisa qué cambió entre snapshots antes de saturar un enlace WAN.
Task 11: Usar bookmarks para mantener ligeras las anclas de replicación
cr0x@server:~$ zfs bookmark tank/app@snap.daily.auto.base.20260204T000000Z tank/app#bmark.daily.20260204T000000Z
cr0x@server:~$ zfs list -t bookmark -o name,creation tank/app
NAME CREATION
tank/app#bmark.daily.20260204T000000Z Tue Feb 4 00:00 2026
Qué significa la salida: Un bookmark referencia un punto en la historia del dataset sin mantener la semántica completa de retención de una snapshot.
Decisión: Si la presión de retención es alta, los bookmarks pueden ayudar a flujos de replicación permitiendo borrar snapshots antiguas. Pero no trates los bookmarks como puntos de restauración para humanos; no son montables.
Task 12: Verificar holds antes de la limpieza (por qué destroy a veces “falla”)
cr0x@server:~$ zfs destroy tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345
cannot destroy snapshot tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345: snapshot has holds
cr0x@server:~$ zfs holds tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345
NAME TAG TIMESTAMP
tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345 keep Tue Feb 3 22:16 2026
Qué significa la salida: Los holds están haciendo su trabajo: evitando la eliminación.
Decisión: Si esta snapshot aún es necesaria, déjala. Si es seguro eliminarla, libera el hold explícitamente con un registro de cambio (Tarea 13).
Task 13: Liberar un hold y luego destruir (hacerlo deliberado)
cr0x@server:~$ zfs release keep tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345
cr0x@server:~$ zfs destroy tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345
Qué significa la salida: Sin salida: éxito.
Decisión: Liberar holds debería ser más raro que crearlos. Si liberas holds a la ligera, acabarás borrando la snapshot que necesitabas. Trata los holds como controles de emergencia.
Task 14: Encontrar snapshots por intención usando patrones de nombre (triaje humano)
cr0x@server:~$ zfs list -t snapshot -o name -s creation tank/app | grep preupgrade | tail -5
tank/app@snap.adhoc.manual.preupgrade.20260110T210002Z.CHG12111
tank/app@snap.adhoc.manual.preupgrade.20260124T210011Z.CHG12202
tank/app@snap.adhoc.manual.preupgrade.20260203T221530Z.CHG12345
Qué significa la salida: Tu sistema de nombres hace que la intención sea buscable bajo presión.
Decisión: Si necesitas regex complicada para encontrar “la última snapshot preupgrade”, tus nombres son demasiado ingeniosos. Simplifica los tokens.
Task 15: Confirmar mountpoints de datasets antes de acciones de restauración
cr0x@server:~$ zfs get -o name,property,value mountpoint,canmount tank/app tank/app-restore
NAME PROPERTY VALUE
tank/app mountpoint /srv/app
tank/app canmount on
tank/app-restore mountpoint /tank/app-restore
tank/app-restore canmount on
Qué significa la salida: Ves dónde se montarán las cosas y si se montarán automáticamente.
Decisión: Antes de un rollback, verifica que no montarás accidentalmente un clone sobre rutas de producción. Para restauraciones de prueba, establece un mountpoint seguro o canmount=noauto.
Task 16: Revisar la salud del pool antes de culpar a las snapshots por lentitud
cr0x@server:~$ zpool status -x
all pools are healthy
Qué significa la salida: ZFS no ve errores ni vdevs degradados. Esa es la línea base.
Decisión: Si el pool no está sano, las operaciones con snapshots pueden ir lentas porque el sistema ya está luchando. Arregla hardware o el resilver primero; no intentes tunear para salir de un pool degradado.
Broma #2: Lo único más aterrador que “no tenemos snapshots” es “tenemos 40.000 snapshots y nadie sabe cuáles son reales”.
Tres mini-historias corporativas desde el frente
Mini-historia 1: El incidente causado por una suposición equivocada (“@daily significa seguro”)
En una empresa SaaS de tamaño medio, el equipo de almacenamiento tenía una política simple: snapshots horarias para datasets críticos, diarias para todo lo demás. Los nombres eran cortos: @hourly, @daily. La automatización mantenía solo una semana de hourlies y un mes de dailies. El equipo se sentía responsable. Lo eran. Solo que no de lo correcto.
Un deploy de backend salió mal y corrompió un subconjunto de metadatos de usuarios. El comandante del incidente pidió una restauración a “ayer a medianoche”. El on-call encontró la snapshot @daily, hizo rollback del dataset y vio cómo la app reiniciaba. Se levantó. Luego empezó a emitir un nuevo tipo de error: registros faltantes referenciados por ficheros más recientes. El rollback había restaurado el dataset, pero no el sistema.
La suposición equivocada era que “daily” implicaba “conocida y buena”. En realidad, la snapshot era crash-consistent y capturó un estado a mitad de ingesta. La aplicación esperaba un checkpoint coordinado entre dos datasets: uno con metadatos y otro con blobs. El dataset de blobs tenía su propio @daily, tomado unos minutos después. El rollback restauró un lado de la relación, no ambos. Felicidades, inventaste inconsistencia de datos con gran confianza.
La solución no fue una herramienta heroica nueva. Fue un cambio de nombres y políticas: las snapshots para aplicaciones multi-dataset se tomaron en un lote orquestado con un token de timestamp compartido, y el nombre incluía quiesced solo cuando la app lo confirmó. El runbook se actualizó para restaurar un conjunto consistente buscando el mismo timestamp entre datasets. De repente “¿qué snapshot?” dejó de ser debate y se volvió un filtro.
Mini-historia 2: La optimización que salió mal (frecuencia de snapshots como amplificador de latencia)
Un equipo de servicios financieros ejecutaba ZFS en una flota que servía discos de VM. Tenían un requisito de cumplimiento para conservar puntos de restauración frecuentes. Alguien se emocionó: “Si las snapshots son baratas, deberíamos tomarlas cada cinco minutos.” La automatización se actualizó. Funcionó. Por un tiempo.
Dos meses después, las quejas por rendimiento se hicieron rutinarias. No catastróficas, solo constantes: picos de latencia periódicos, especialmente durante horas pico de escritura. Todo el mundo culpó “al hipervisor” o “a la red”. Los gráficos de almacenamiento mostraron algo más aburrido: ráfagas de trabajo de metadata alrededor de las horas de snapshot, mayor amplificación de escritura por bloques retenidos y pools que se acercaban más al lleno porque la retención se había expandido silenciosamente.
El fallo fue sutil: el equipo optimizó para RPO ignorando la curva de coste del churn. Snapshots de alta frecuencia en datasets de VM con muchas escrituras no solo crean más entradas; retienen más historiales de bloques divergentes. Combinado con un pool que rozaba un umbral alto de utilización, la asignación se volvió más difícil, la fragmentación peor y el sistema tuvo menos buenas opciones. La política de cinco minutos no solo añadió trabajo; magnificó el peor comportamiento de un pool estresado.
El plan de recuperación fue pragmático: reducir frecuencia para datasets con mucho churn, separar “discos OS” y “discos de datos” en datasets distintos con retenciones diferentes, y hacer cumplir un piso de espacio libre. El nombrado ayudó también: el equipo pudo identificar y expirar con precisión la cadencia de cinco minutos (snap.5min.auto.base...) sin tocar snapshots de evento o anclas de replicación.
Aun así cumplieron con la normativa. Simplemente dejaron de pretender que el subsistema de almacenamiento concedía deseos.
Mini-historia 3: La práctica aburrida pero correcta que salvó el día (dry runs + holds)
Una plataforma sanitaria tenía una cultura de “hacer lo aburrido primero”. Sus runbooks ZFS mandaban dos pasos antes de cualquier rollback: zfs rollback -n en seco, y confirmar holds en cualquier snapshot asociada a un ticket de cambio. Los ingenieros refunfuñaban. Parecía papeleo con tecleo extra.
Durante una ventana de upgrade rutinaria, un ingeniero necesitó restaurar un dataset tras una herramienta de migración que escribió valores inesperados. Eligió lo que parecía la snapshot correcta: mismo día, timestamp cercano. La salida del dry-run avisó que el rollback destruiría varias snapshots más nuevas usadas como incrementales de replicación. Eso no es solo pérdida de datos; es una cola de replicación convirtiéndose en fin de semana de trabajo.
El ingeniero se detuvo. En vez de eso clonó, validó el estado de la aplicación en el clone y luego eligió una snapshot diferente que preservaba la cadena de replicación. El paso aburrido evitó un segundo incidente: replicación fallida seguida de un re-seed frenético.
Más tarde, la automatización de limpieza intentó podar snapshots “adhoc” más antiguas que un umbral. No pudo borrar las pre-upgrade porque los holds se habían establecido con una etiqueta estándar. Nadie tuvo que recordarlo. El sistema lo hizo. El upgrade se completó, los holds se liberaron tras la verificación y el ticket del incidente se cerró sin drama.
La madurez operativa a menudo se parece a esto: menos momentos heroicos, resultados más predecibles.
Guía de diagnóstico rápido: encuentra el cuello de botella
Cuando las operaciones de snapshot se vuelven lentas—o la replicación va a paso de tortuga—la gente tiende a culpar “a las snapshots ZFS” como si fueran un demonio con estados de ánimo. No sigas la tradición. Haz triage. Aquí tienes una secuencia rápida y de alta señal.
Primero: ¿está el pool enfermo?
- Comprobar:
zpool status -x - Por qué: vdevs degradados, resilvers, errores de checksum o dispositivos offline dominarán todo lo demás.
- Decisión: Si no está sano, arregla eso primero. Afinar es una pérdida de tiempo mientras tu pool cojea.
Segundo: ¿está el pool demasiado lleno?
- Comprobar:
zpool listyusedbysnapshotsde datasets - Por qué: alta utilización reduce la flexibilidad de asignación; las snapshots retienen bloques; ambos pueden disparar latencia.
- Decisión: Si te acercas al piso operativo de espacio libre, expira snapshots (de forma segura), añade capacidad o reduce churn. Elige al menos una hoy.
Tercero: ¿proviene el churn de un solo dataset?
- Comprobar:
zfs list -o name,used,usedbysnapshotsen datasets; encuentra los culpables. - Por qué: un dataset de logs puede dominar los deltas de snapshot y el volumen de replicación.
- Decisión: Divide datasets por perfil de escritura. Deja de snapshotear logs efímeros a alta frecuencia a menos que te guste pagar por basura retenida.
Cuarto: ¿la replicación es lenta porque los deltas son enormes?
- Comprobar:
zfs send -nvP -ientre snapshots. - Por qué: No puedes optimizar un delta 10x a menos que cambies lo que está escribiendo.
- Decisión: Si los deltas son inesperadamente grandes, investiga comportamiento de la app, desajustes de recordsize, cambios de compresión y frecuencia de snapshots.
Quinto: ¿sufres de “acumulación de snapshots”?
- Comprobar: cuenta de snapshots:
zfs list -t snapshot | wc -l(crudo, pero rápido) - Por qué: recuentos muy grandes de snapshots aumentan la sobrecarga de gestión y la probabilidad de error humano.
- Decisión: Si los recuentos se desbocan, arregla la automatización de retención y los patrones de nombrado para que puedas expirar de forma segura sin ruleta regex.
Errores comunes: síntomas → causa raíz → solución
Mistake 1: “No podemos decir qué snapshot es segura para restaurar”
Síntomas: Hilos largos de incidentes discutiendo timestamps; múltiples restauraciones parciales; miedo al rollback.
Causa raíz: Los nombres codifican solo cadencia (@daily) pero no intención, quiescencia ni agrupamiento por flujo de trabajo.
Solución: Adopta un esquema de nombres tokenizado con timestamps UTC y marcadores de intención (preupgrade, predeploy, incident, quiesced-db). Para apps multi-dataset, toma snapshots coordinadas que compartan el mismo token timestamp en todos los datasets.
Mistake 2: “La limpieza borró la snapshot que necesitábamos”
Síntomas: Snapshots de evento desaparecen; el postmortem incluye “pensamos que estaría allí”.
Causa raíz: No hay holds; scripts de limpieza concuerdan con “adhoc” de forma amplia; no hay separación entre clases de retención.
Solución: Aplica holds a snapshots de cambio/incidente por defecto. Separa retenciones: snap.hourly.auto.base expira agresivamente; snap.adhoc.manual.preupgrade se mantiene con hold hasta liberación explícita.
Mistake 3: “El rollback destruiría snapshots más nuevas y la replicación se rompe”
Síntomas: El dry-run muestra destrucción de snapshots; las tuberías de replicación fallan tras el rollback; hay que re-seed.
Causa raíz: Hacer rollback en vez de clonar; malinterpretar que rollback retrocede la historia del dataset y descarta snapshots más nuevas.
Solución: Usa siempre zfs rollback -n. Prefiere clonar para validación y forense. Si debes hacer rollback, planifica explícitamente el re-anclaje de replicación y preserva las snapshots necesarias.
Mistake 4: “El uso de espacio por snapshots sigue creciendo aunque borremos ficheros”
Síntomas: USED del dataset no baja; el pool sigue lleno; borrar datos no libera espacio.
Causa raíz: Las snapshots retienen bloques antiguos, así que las eliminaciones en el dataset en directo no liberan espacio hasta destruir las snapshots.
Solución: Identifica snapshots grandes (zfs list -t snapshot -s used). Reduce retención en datasets con mucho churn. Considera cambios en el layout de datasets para aislar fuentes de churn.
Mistake 5: “Los nombres son inconsistentes entre herramientas; los scripts no encuentran snapshots”
Síntomas: Algunas snapshots usan guiones bajos, otras guiones; timestamps difieren; scripts de retención ignoran algunas; snapshots de incidente no se encuentran con grep.
Causa raíz: Múltiples creadores de snapshots (cron, CI, admins) sin convención impuesta.
Solución: Define un orden de tokens canónico y separadores; aplícalo mediante scripts wrapper o política. Añade propiedades para metadatos estructurados de modo que la automatización pueda seleccionar por propiedad y no por parseo de cadenas.
Mistake 6: “Tomamos snapshots demasiado seguido y el rendimiento se vuelve picoso”
Síntomas: Picos de latencia en tiempos de snapshot; deltas de replicación enormes; utilización del pool sube.
Causa raíz: Snapshots de alta frecuencia en datasets con mucho churn; retención no afinada; pool demasiado lleno.
Solución: Reduce la frecuencia para datasets con mucho churn; divide datasets por perfil de escritura; impón un piso de espacio libre; verifica deltas con zfs send -nvP antes de replicar cambios globalmente.
Listas de verificación / plan paso a paso
Checklist A: Adoptar un sistema de nombres sin romperlo todo
- Inventaria los creadores de snapshots: trabajos cron, pipelines de CI, herramientas de proveedores, humanos. Si no sabes quién crea snapshots, no controlas el nombrado.
- Elige un patrón de nombre canónico: p. ej.,
snap.<cadence>.<creator>.<intent>.<ts>. - Estandariza el formato de timestamp UTC:
YYYYMMDDThhmmssZ. Sin excepciones. - Define clases de retención:
hourly.auto.base(corta)daily.auto.base(media)adhoc.*.preupgradeyadhoc.*.incident(retenidas)
- Decide tokens de quiescencia: al menos,
quiesced-dbvscrash. - Añade propiedades para metadatos: reason, ticket, expiry, owner.
- Actualiza runbooks: restaurar por grupo de timestamp para apps multi-dataset; política de clonar-primero para restauraciones de alto riesgo.
- Despliega gradualmente: empieza con nuevas snapshots. No renombres las viejas en sitio a menos que estés seguro de que las herramientas no fallarán.
Checklist B: “Necesito restaurar ahora” (pasos del operador)
- Confirma la salud del pool:
zpool status -x. Si está sano, espera menos riesgos y demoras. - Identifica el/los dataset(s) exactos implicados. No restaures un dataset padre si solo un hijo está afectado.
- Lista snapshots ordenadas por creación y busca el token de intención (
predeploy/preupgrade/incident). - Verifica la quiescencia para datasets tipo BD. Elige
quiesced-dbcuando esté disponible. - Dry-run de rollback:
zfs rollback -n. Lee lo que destruiría. - Prefiere clonar primero para validación. móntalo de forma segura y verifica las comprobaciones de la app.
- Rollback solo cuando entiendas el radio de explosión y lo hayas comunicado (replicación, snapshots más nuevas, servicios dependientes).
- Tras la restauración: toma una snapshot nueva con intención
postrestorey ponle un hold breve. Te da un “estado conocido” estable si los cambios posteriores fallan.
Checklist C: Higiene de snapshots (mantenimiento semanal)
- Revisa uso de espacio por snapshots: encuentra los datasets principales por
usedbysnapshots. - Detecta cadencias desbocadas: demasiadas snapshots por dataset suele significar deriva en la automatización.
- Expira por clase: borra primero
hourly.auto.baseantiguas; no toques snapshots de evento con hold. - Audita los holds: si los holds nunca se liberan, tu “temporal” se vuelve permanente. Añade una propiedad de expiración y un circuito de revisión.
- Prueba restauraciones: no solo “podemos listar snapshots?”—clona y valida datos realmente. Tu sistema de nombres solo se prueba cuando ayuda en una restauración.
Preguntas frecuentes
1) ¿Los nombres de snapshot deben incluir el nombre del dataset?
No. El dataset ya forma parte del nombre completo de la snapshot (tank/app@...). Duplicarlo alarga los nombres y los hace menos legibles. Codifica intención y tiempo en su lugar.
2) ¿Puedo renombrar una snapshot ZFS?
Sí. ZFS soporta el renombrado de snapshots en muchas implementaciones, pero puede tener consecuencias operativas (expectativas de replicación, scripts, monitorización). Trata los renombres como una tarea de migración con pruebas, no como limpieza casual.
3) ¿Por qué no usar solo @hourly y mantenerlo simple?
Porque “hourly” responde solo a una de tus preguntas reales. Bajo presión de incidente necesitas “hourly de qué intención, tomado por qué sistema, y si está quiesced?” La simplicidad que borra significado no es simplicidad; es dolor diferido.
4) ¿Cómo agrupo snapshots en múltiples datasets para una restauración consistente?
Usa un token de timestamp compartido en todos los datasets en la ejecución coordinada de snapshots. Entonces restaura buscando ese timestamp coincidente. Ejemplo: todos los datasets implicados tienen ...20260204T020000Z.... Aquí es donde la disciplina del timestamp UTC renta.
5) ¿Los nombres de snapshot influyen en la corrección de zfs send?
La corrección de ZFS depende de la ascendencia de snapshots, no del significado legible del nombre. Pero los humanos operan el sistema. Un buen nombrado evita que envíes incrementales equivocados o selecciones la base equivocada bajo estrés.
6) ¿Debemos poner números de ticket en los nombres de snapshot?
Suele ser sí, para snapshots de cambio e incidente. Es trazabilidad ligera. Manténlos cortos y no sensibles. Si los IDs de tickets son caóticos, guárdalos en propiedades y deja los nombres limpios.
7) ¿Cuántas snapshots son “demasiadas”?
No hay un número mágico. El límite práctico es donde la sobrecarga de gestión, el espacio de retención y el error humano se vuelven problemas. Si listar snapshots es lento, la limpieza es arriesgada o los operadores eligen rutinariamente la equivocada, ya excediste la línea.
8) ¿Cuál es la diferencia entre un hold de snapshot y simplemente “no borrarlo”?
Un hold hace que la eliminación falle a nivel de sistema de archivos, incluso si un script de limpieza se ejecuta con buenas intenciones. “No lo borres” es una esperanza. Los holds son un control.
9) ¿Debemos conservar snapshots “golden” para siempre?
Rara vez. Las snapshots de larga vida pueden acumular bloques retenidos y aumentar la presión de espacio, especialmente en datasets con mucho churn. Si necesitas retención a largo plazo, replica a un objetivo de backup y mantén menos snapshots locales, o mueve los datos archivados a un dataset diseñado para ello.
10) ¿Los nombres de snapshot deben ser idénticos entre entornos (dev/stage/prod)?
El patrón debería ser idéntico. Las rutas de dataset diferirán. Patrones de nombrado consistentes ayudan a reutilizar runbooks y automatización y reducen los “funciona en staging” sorpresas.
Conclusión: siguientes pasos que realmente reducen el estrés
Si quieres rollbacks sin estrés, deja de tratar las snapshots como un montón de puntos en el tiempo y empieza a tratarlas como un sistema: nombrado, metadatos, retención y flujos de trabajo de operadores. La mejor convención de nombres es la que tu on-call puede usar medio dormido sin improvisar.
Pasos prácticos:
- Elige el orden de tokens (
snap.cadence.creator.intent.ts) y aplica timestamps UTC. - Separa clases de retención: cadencia base vs snapshots de evento. Usa holds para eventos.
- Añade propiedades para reason/ticket/expiry para que la automatización sea robusta.
- Actualiza el runbook de restauración a: listar → dry-run → clonar-primero → validar → rollback solo cuando esté entendido.
- Ejecuta un ejercicio de restauración este mes usando los nuevos nombres. Si el ejercicio confunde, el sistema de nombres te está mintiendo.
Las snapshots son una de las superpotencias de ZFS. El nombrado es cómo la apuntas.