ZFS zfs diff: Encontrar exactamente qué cambió entre snapshots

¿Te fue útil?

Los snapshots de ZFS son lo más parecido a viajar en el tiempo que existe en almacenamiento y que además pasa una auditoría. Pero viajar en el tiempo solo es útil si puedes responder la pregunta que tu jefe, tu equipo de seguridad o tu cerebro a las 3 a.m. hará: ¿qué cambió?

zfs diff es la herramienta directa y honesta para ese trabajo. No es elegante, no es una GUI y no le importan tus sentimientos. Te dice qué rutas se añadieron, eliminaron, modificaron o renombraron entre dos snapshots (o entre un snapshot y el “ahora”). Usado correctamente, convierte un alarmante “algo pasó” en una lista sobre la que puedes actuar.

Qué es zfs diff (y qué no es)

zfs diff compara dos puntos en el tiempo en un único dataset (o zvol, aunque las rutas de archivos son el caso más común). Esos puntos suelen ser snapshots como pool/ds@snapA y pool/ds@snapB, o un snapshot y el sistema de archivos vivo actual. El resultado es un flujo de cambios a nivel de ruta: archivos creados, eliminados, modificados o renombrados.

No es un diff consciente del contenido como diff -u. No te dirá “la línea 83 cambió.” Te dirá “este archivo cambió,” que suele ser justo lo que necesitan las operaciones y la respuesta a incidentes. Si quieres diffs de contenido, puedes montar snapshots y ejecutar tus propias herramientas (y sí, eso es más lento, genera más ruido y es más fácil de estropear).

Tampoco es un registro autoritativo de por qué algo cambió, ni de qué proceso lo hizo. Es una herramienta de contabilidad a nivel de sistema de archivos: este es el conjunto de rutas cuya metadata/estado de contenido difiere entre dos grupos de transacciones.

Broma #1: Los snapshots no mienten, pero los administradores sí—usualmente consigo mismos, cinco minutos antes de la llamada de incidentes.

Datos y contexto histórico útiles para reuniones

Estos son puntos cortos y concretos que te ayudan a explicar por qué los diffs de snapshots de ZFS se comportan como lo hacen—y por qué eso es una característica, no una molestia.

  1. Los snapshots de ZFS son copy-on-write, no “copias de backup”. Un snapshot es una referencia consistente a bloques existentes; las nuevas escrituras van a otro sitio. Por eso los snapshots son baratos e instantáneos.
  2. “Renombrar” no es “copiar y luego borrar” al nivel semántico del sistema de archivos. ZFS puede detectar renombres como una operación de primera clase, y zfs diff puede reportarlos cuando puede correlacionar la identidad del objeto.
  3. ZFS fue diseñado con checksums de extremo a extremo como base. Eso significa que “archivo cambiado” se puede atar a cambios reales de bloques, no solo a timestamps que mienten porque una app tocó metadata.
  4. La replicación basada en snapshots (send/receive) precede al marketing actual de “backup inmutable”. ZFS lleva años haciendo streams incrementales de snapshots; la “inmutabilidad” viene de políticas y permisos, no de un nuevo formato de archivo.
  5. FreeBSD e illumos han tratado a ZFS como ciudadano de primera clase por mucho tiempo. Muchos comportamientos de producción (incluida la madurez de las herramientas alrededor de snapshots) se definieron allí antes de que ZFS en Linux alcanzara la misma comodidad operativa.
  6. La salida de zfs diff es una vista del estado de metadata y objetos, no de la intención de la aplicación. Por ejemplo, un checkpoint de base de datos puede cambiar muchos archivos incluso si los “datos” lógicos se movieron apenas.
  7. Los datasets ZFS pueden tener diferentes mountpoints y pueden estar desmontados. zfs diff no necesita que el dataset esté montado para comparar snapshots; compara internamente los árboles de snapshot.
  8. Los clones son snapshots escribibles. El diff entre un snapshot y el snapshot de un clone puede contar una historia limpia de “qué divergió”—útil en dev/test, o cuando prod se ejecutó accidentalmente en un clone (sí, pasa).

Cómo funciona realmente zfs diff internamente

A alto nivel, ZFS rastrea conjuntos de objetos. Un dataset es un conjunto de objetos; un snapshot es una versión de solo lectura y fijada de ese conjunto. zfs diff recorre dos versiones y compara entradas de directorio y metadata de objetos, luego emite un conjunto de cambios por ruta.

La consecuencia operativa importante: el diff se basa en objetos del sistema de archivos, no en la visión de la aplicación. Si una aplicación reescribe un archivo in-place, verás una modificación. Si escribe un archivo temporal nuevo y lo renombra sobre el original, puede que veas una modificación más comportamiento de rename dependiendo de cómo la operación aterrizó en el txg y si la correlación de identidad de objetos es posible.

Otra consecuencia: el informe basado en rutas se reconstruye. ZFS tiene números de objeto y estructuras de directorio; para imprimir “/var/log/messages” la herramienta debe recorrer directorios y reconstruir nombres. En árboles de directorios enormes, especialmente con alta rotación, esto puede ser costoso. “Costoso” aquí no significa necesariamente “disco lento”; puede significar “mucho recorrido de metadata”, lo que se convierte en presión sobre ARC o muchas lecturas aleatorias si no está en caché.

Una sutileza a recordar: el sistema de archivos vivo (“ahora”) no es un snapshot. Si ejecutas zfs diff pool/ds@snap contra el dataset vivo mientras está cambiando activamente, estás pidiendo un objetivo en movimiento. ZFS hará lo mejor que pueda, pero tu conclusión operativa debería ser “esto es indicativo”, no “esto es una transcripción judicial.” Para una comparación estable, diff snapshot a snapshot.

Leer la salida sin engañarte

El formato canónico de salida es un código de cambio de un solo carácter seguido de una ruta. Códigos comunes que verás:

  • + ruta añadida
  • - ruta eliminada
  • M ruta modificada (cambio de contenido o metadata)
  • R ruta renombrada (a menudo mostrado como rutas “desde” y “hacia” dependiendo de la implementación)

Consejos de interpretación de alguien que se quemó:

“Modificado” es más amplio que “contenido cambiado”

Un archivo puede estar “modificado” por permisos, propiedad, ACLs, xattrs, timestamps, cambios en el recuento de enlaces o por contenido. Si estás haciendo respuesta a incidentes, a menudo te interesa el cambio de contenido; si haces cumplimiento, puede que te importen más los cambios de metadata.

Los renombres son tus amigos—hasta que no lo son

Cuando se detecta un renombrado, es un regalo: significa que puedes rastrear movimientos sin entrar en pánico por un borrar+crear. Pero la detección de renombres puede fallar cuando la correlación es ambigua (alta rotación, archivos temporales o patrones que rompen el mapeo de identidad de objetos). No trates la ausencia de R como prueba de que no hubo renombre; trátala como “la herramienta no pudo probarlo de forma fiable.”

Las eliminaciones suelen ser la señal más valiosa

Si estás depurando un despliegue roto, un único archivo eliminado en /etc puede explicar más que 5.000 archivos “modificados” en /var. Al leer diffs, filtra por directorios que mapearían a tu dominio de fallo.

Broma #2: zfs diff es como una revisión de código: no arregla el problema, pero sí te quita la posibilidad de fingir que no pasó nada.

Tareas prácticas: 14 comandos reales con interpretación

Todos los ejemplos suponen un dataset como tank/app con snapshots @pre y @post. Ajusta nombres a tu entorno.

Task 1: Compare dos snapshots (línea base)

cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post
M       /etc/app/app.conf
+       /var/lib/app/new-index.db
-       /var/lib/app/old-index.db
R       /var/log/app/old.log   -> /var/log/app/old.log.1

Interpretación: La configuración cambió, el índice se rotó, un archivo fue reemplazado y un log fue rotado mediante renombrado. Esto es típico de una actualización de paquete o una tarea de mantenimiento de la aplicación.

Task 2: Compare un snapshot con el sistema vivo actual

cr0x@server:~$ sudo zfs diff tank/app@pre
M       /etc/app/app.conf
+       /var/tmp/app-build-9281.tmp

Interpretación: “Desde @pre, ¿qué difiere ahora?” Útil para comprobaciones rápidas de “qué cambiamos desde el último conocido bueno”. Cuidado con la alta rotación: los resultados pueden cambiar mientras los lees.

Task 3: Limitar el ruido haciendo grep a un subárbol

cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post | grep '^M' | grep '^M[[:space:]]\+/etc/'
M       /etc/app/app.conf
M       /etc/app/limits.conf

Interpretación: Reduce el ruido de “logs cambiados”. En incidentes, normalmente quieres primero una lista corta de cambios de configuración y binarios.

Task 4: Contar cambios por tipo (triaje barato)

cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post | awk '{print $1}' | sort | uniq -c
   82 +
   10 -
  911 M
    4 R

Interpretación: 911 rutas modificadas es mucho. Si esperabas un cambio solo de configuración, esto es una señal de alerta. Si esperabas una actualización de paquete o una migración de BD, puede ser normal.

Task 5: Encontrar los “directorios principales” afectados

cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post \
  | awk '{print $2}' \
  | awk -F/ 'NF>2 {print "/"$2"/"$3} NF==2 {print "/"$2} NF==1 {print "/"}' \
  | sort | uniq -c | sort -nr | head
  640 /var/lib
  210 /var/log
   95 /usr/local
   12 /etc/app

Interpretación: La mayor rotación está bajo /var/lib y /var/log. Eso sugiere movimiento de datos de aplicación y logging—no deriva aleatoria de configuración.

Task 6: Verificar que los snapshots existen y pertenecen a la misma línea de dataset

cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation | grep '^tank/app@'
tank/app@pre     Mon Dec 23 11:58 2025
tank/app@post    Mon Dec 23 12:12 2025

Interpretación: Si los snapshots fueron tomados de datasets diferentes (o después de un rollback/divergencia de clone), los diffs pueden no tener sentido o fallar.

Task 7: Confirmar el mountpoint del dataset y si está montado

cr0x@server:~$ zfs get -H -o property,value mountpoint,mounted tank/app
mountpoint  /app
mounted     yes

Interpretación: No es requerido para zfs diff, pero sí lo es si planeas inspeccionar archivos directamente (por ejemplo, montar snapshots vía .zfs/snapshot).

Task 8: Inspeccionar un archivo cambiado entre snapshots (confirmación a nivel de contenido)

cr0x@server:~$ sudo sed -n '1,120p' /app/.zfs/snapshot/pre/etc/app/app.conf
# app.conf - baseline
max_workers=32
log_level=info
cr0x@server:~$ sudo sed -n '1,120p' /app/.zfs/snapshot/post/etc/app/app.conf
# app.conf - after deploy
max_workers=64
log_level=debug

Interpretación: zfs diff te dijo “modificado”; esto te dice “cómo.” En incidentes, haz esto para el puñado de archivos que importan.

Task 9: Detectar renombres masivos sospechosos (común en ransomware y scripts de “limpieza de logs”)

cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post | grep '^R' | head
R       /var/lib/app/data/part-0001 -> /var/lib/app/data/part-0001.locked
R       /var/lib/app/data/part-0002 -> /var/lib/app/data/part-0002.locked
R       /var/lib/app/data/part-0003 -> /var/lib/app/data/part-0003.locked

Interpretación: Una ráfaga de renombres uniformes con nuevas extensiones es sospechosa. Puede ser un proceso legítimo de archivado. También puede ser un patrón de “encriptar rápido y luego renombrar”. Escala rápidamente.

Task 10: Validar si un send incremental debería incluir los cambios esperados

cr0x@server:~$ sudo zfs diff tank/app@replica-base tank/app@replica-next | head -20
M       /etc/app/app.conf
+       /var/lib/app/new-index.db

Interpretación: Si tu destino de replicación “no recibió el cambio de configuración”, compara los snapshots exactos que estás enviando. Muchos “misterios” de replicación son solo “enviamos la base equivocada”.

Task 11: Correlacionar diffs de snapshot con uso de espacio (¿es este cambio costoso?)

cr0x@server:~$ zfs list -o name,used,refer,avail,mountpoint tank/app
NAME      USED  REFER  AVAIL  MOUNTPOINT
tank/app  412G  380G   2.1T   /app
cr0x@server:~$ zfs get -o name,property,value -s local,received,default usedbysnapshots,usedbydataset,usedbychildren tank/app
tank/app  usedbysnapshots  31.4G
tank/app  usedbydataset    380G
tank/app  usedbychildren   0B

Interpretación: Muchos archivos “modificados” no siempre significan muchos bloques nuevos, pero a menudo correlacionan. Si usedbysnapshots sube rápidamente, la rotación está pinando bloques antiguos.

Task 12: Detectar “rotación de metadata” que parece rotación de contenido

cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post | grep '^M' | grep '^M[[:space:]]\+/var/log/' | head
M       /var/log/app/access.log
M       /var/log/app/error.log
M       /var/log/app/metrics.log

Interpretación: Los logs cambiando es normal; no dejes que ahoguen la señal. Si necesitas “qué cambió en código/config”, filtra los directorios conocidos de rotación.

Task 13: Confirmar el nombrado y orden de snapshots para evitar confusión de “diff al revés”

cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation tank/app | tail -5
tank/app@daily-2025-12-21   Sun Dec 21 00:00 2025
tank/app@daily-2025-12-22   Mon Dec 22 00:00 2025
tank/app@daily-2025-12-23   Tue Dec 23 00:00 2025
tank/app@pre                Tue Dec 23 11:58 2025
tank/app@post               Tue Dec 23 12:12 2025

Interpretación: Cuando diffas “más nuevo vs más viejo” puedes confundirte sobre plus/minus. Siempre verifica tiempos de creación.

Task 14: Usar la salida de zfs diff como allowlist para restauraciones quirúrgicas

cr0x@server:~$ sudo zfs diff tank/app@good tank/app@bad | awk '$1 ~ /^M|^-$/ {print $2}' | head
/etc/app/app.conf
/usr/local/bin/app
/usr/local/lib/libapp.so
cr0x@server:~$ sudo cp -a /app/.zfs/snapshot/good/usr/local/bin/app /app/usr/local/bin/app

Interpretación: A veces no quieres un rollback completo; quieres restaurar un conjunto pequeño de archivos conocidos buenos. Navegar snapshots más un diff cuidadosamente filtrado te da un plan que no destruirá datos buenos no relacionados.

Tres historias del mundo corporativo (incluye dolor)

Mini-historia 1: El incidente causado por una suposición equivocada (snapshots como “backups”)

La configuración era familiar: un dataset de aplicación crítico en ZFS, snapshots horarios y un job de replicación a una máquina secundaria. Todos dormían tranquilos porque “tenemos snapshots”. El equipo incluso tenía una página en la wiki que decía “snapshots = backups”, que es el tipo de frase que debería venir con una etiqueta de advertencia y un extintor.

Entonces un desarrollador ejecutó un script de limpieza contra producción. No fue malicioso; simplemente apuntó a la variable de entorno equivocada. Un par de directorios bajo /var/lib/app fueron eliminados recursivamente. En minutos, la monitorización se convirtió en gritos. El on-call dijo la frase que nunca quieres oír: “Está bien, tenemos snapshots, haré un rollback.”

El rollback restauró los datos eliminados. También revirtió un puñado de escrituras legítimas hechas después del snapshot—escrituras que incluían estado de cara al cliente. La inconsistencia resultante no fue catastrófica, pero fue desagradable: reintentos, eventos duplicados y unas horas de conciliación manual con soporte y operaciones. El postmortem no fue sobre ZFS siendo arriesgado; fue sobre la suposición equivocada de que la acción “más segura” es la más rápida.

Lo que lo arregló la siguiente vez fue disciplina aburrida: antes de cualquier rollback, ejecutaban zfs diff entre el último snapshot conocido bueno y el estado actual. El diff hizo visible el radio de explosión. En lugar de revertir todo el dataset, restauraron solo los subárboles eliminados desde el snapshot. Mantuvieron las escrituras legítimas. El siguiente incidente no fue divertido, pero estuvo contenido—y contener es lo que significa “resiliencia” cuando suena el pager.

Mini-historia 2: La optimización que salió mal (cadencia agresiva de snapshots + diff en cron)

Otra organización quiso “auditoría casi en tiempo real” para una iniciativa de cumplimiento. El plan: tomar snapshots cada cinco minutos, ejecutar zfs diff entre los dos últimos, archivAR la salida y enviarla a un sistema central. Sobre el papel parecía elegante. En la práctica, fue una pequeña denegación de servicio contra su propio almacenamiento.

Primer problema: el dataset era una caché de builds con millones de archivos pequeños. zfs diff tuvo que recorrer enormes árboles de directorio y reconstruir rutas. Cada cinco minutos. Eso se tradujo en presión metadatos implacable. Las tasas de acierto del ARC bajaron. La latencia se disparó. Los desarrolladores se quejaron de que “ZFS es lento,” que es el equivalente en almacenamiento de culpar a la carretera por manejar mal.

Segundo problema: la salida era gigantesca y en su mayoría ruido. Los sistemas de build churnean. Crean archivos temporales, renombran cosas, borran directorios, repiten. El equipo de cumplimiento quería “qué cambió”, pero lo que obtuvieron fue “todo cambia siempre”. La relación señal/ruido fue tan baja que nadie miró los reportes, que es la falla secreta de cumplimiento: puedes generar evidencia infinita que nadie lee.

El plan de recuperación fue pragmático. Redujeron la frecuencia de snapshots para coincidir con necesidades de negocio (horario para la mayoría, más frecuente solo para algunos datasets pequeños). Dejaron de ejecutar diffs sobre cachés ruidosas y se enfocaron en datasets de configuración y datos de registro. Y cuando ejecutaban diffs, filtraban subárboles significativos y resumían conteos en lugar de archivar cada ruta. La optimización no falló porque ZFS no pudiera hacerlo; falló porque la carga de trabajo no merecía ese nivel de escrutinio.

Mini-historia 3: La práctica aburrida pero correcta que salvó el día (diff antes del corte de replicación)

Esta es la clase de historia que nadie cuenta en conferencias porque no es glamorosa. Un equipo planificó una migración de almacenamiento: servidores nuevos, layout de pool nuevo, replicación con ZFS send/receive y luego una ventana de corte. La ansiedad habitual: “¿Será idéntico el destino?” y “¿y si perdemos algo?”

Hicieron algo poco sexy: escribieron un runbook que requería un zfs diff previo al corte sobre un par congelado de snapshots—uno en la fuente, otro en el destino después del receive. No “confíes en el job de replicación”, no “compares salidas de zfs list”, sino una lista explícita de cambios sobre datasets representativos.

Durante el ensayo, el diff mostró un puñado de cambios inesperados bajo un directorio que “nunca debería cambiar.” Resultó que un servicio en el host de destino se había auto-iniciado y empezó a escribir archivos de caché en un mountpoint que debía permanecer inactivo hasta el corte. La replicación en sí estaba bien; el entorno no lo estaba.

Arreglaron el orden de inicio de servicios, repitieron el ensayo y los diffs se calmaron. En la noche del corte fue anticlimático en el mejor sentido. La práctica aburrida—differenciando snapshots que representaban “fuente de verdad” y “recibido como verdad”—capturó una divergencia real antes de que se convirtiera en una discusión nocturna sobre integridad de datos.

Guía rápida de diagnóstico

Cuando necesitas respuestas rápido, no empieces mirando miles de líneas de diff. Empieza con un pequeño número de comprobaciones que reduzcan el problema a “cambio esperado”, “cambio inesperado”, “problema de herramienta” o “cuello de botella de rendimiento”.

Paso 1: Confirma que estás comparando los snapshots correctos

cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation tank/app | tail -10

Mira: ¿Los nombres de snapshot son correctos? ¿Están en el orden que piensas? ¿Alguien hizo rollback y re-creó snapshots con nombres confusos?

Paso 2: Determina si el cambio es “churn de datos” o “churn de plano de control”

cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post | awk '{print $2}' | head

Luego inmediatamente: resume dónde está ocurriendo.

cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post \
  | awk '{print $2}' \
  | awk -F/ 'NF>2 {print "/"$2"/"$3} NF==2 {print "/"$2} NF==1 {print "/"}' \
  | sort | uniq -c | sort -nr | head -15

Mira: Mayormente /var/log y /var/tmp (usualmente ruido) vs /etc, /usr y los directorios de datos de la app (usualmente significativos).

Paso 3: Si el rendimiento es el cuello de botella, comprueba si estás limitado por metadata

cr0x@server:~$ arcstat 1 5
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  arcsz     c
12:00:01   210    88     41    60   28    22   10     6    2   128G  192G

Interpretación: Altas tasas de fallos durante una ejecución de diff sugieren que la metadata no está en ARC y el sistema está haciendo trabajo real para recorrer directorios. Si no tienes arcstat, usa telemetría nativa de IO y memoria; el patrón es el mismo: CPU + lecturas aleatorias + fallos de caché.

Paso 4: Valida propiedades del dataset que cambian el significado de “modificado”

cr0x@server:~$ zfs get -o name,property,value atime,recordsize,compression,acltype,xattr,overlay,encryption tank/app

Mira: atime=on puede crear churn de metadata. Cambios en ACL y comportamiento de xattr pueden generar olas de resultados “modificados” en muchos archivos.

Paso 5: Si el diff es enorme, decide si necesitas un resumen o una respuesta quirúrgica

Si estás en una llamada de incidentes, normalmente no necesitas todas las rutas. Necesitas: “¿Algo cambió bajo /etc?” “¿Cambió algún binario bajo /usr/local/bin?” “¿Se eliminaron archivos bajo el directorio de datos?” Eso es trabajo de filtrado, no un inventario completo.

Errores comunes (síntomas y soluciones)

Mistake 1: Hacer diff del dataset equivocado porque los mountpoints se parecen

Síntoma: zfs diff reporta cambios que no coinciden con lo que viste en disco, o no encuentras las rutas en el sistema vivo.

Causa: Múltiples datasets montados bajo rutas similares, o un cambio de mountpoint legado. Diffaste tank/app pero estabas mirando tank/app/data (o viceversa).

Solución: Confirma mountpoints y límites de dataset.

cr0x@server:~$ zfs list -o name,mountpoint -r tank/app
NAME           MOUNTPOINT
tank/app       /app
tank/app/data  /app/data

Mistake 2: Tratar diffs snapshot-a-vivo como verdad estable durante escrituras activas

Síntoma: Vuelves a ejecutar el mismo diff y los resultados cambian; ves archivos temporales aparecer/desaparecer; no puedes conciliar conteos.

Causa: El sistema de archivos vivo está cambiando mientras lo comparas con un snapshot fijo.

Solución: Toma un segundo snapshot y compara snapshot a snapshot.

cr0x@server:~$ sudo zfs snapshot tank/app@now
cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@now | head

Mistake 3: Asumir que “M” significa “contenido de archivo cambiado”

Síntoma: Seguridad marca “miles de archivos modificados” después de un escaneo, pero el comportamiento de la aplicación es normal.

Causa: Cambios de metadata (ACLs, xattrs, timestamps) también son modificaciones.

Solución: Valida con un hash de contenido en una pequeña muestra, o examina qué directorios están cambiando. También revisa si algo cambió en políticas de ACL o comportamiento de atributos extendidos.

Mistake 4: Olvidar que las eliminaciones pueden estar enmascaradas por recreación posterior

Síntoma: Un incidente sugiere que un archivo fue eliminado, pero el sistema actual tiene un archivo en esa ruta.

Causa: El archivo fue eliminado y luego recreado (posiblemente con contenido/propietario diferente). Dependiendo del momento y del comportamiento de la aplicación, el diff podría mostrar una modificación o un borrar+añadir en lugar de una historia limpia.

Solución: Usa la navegación de snapshots para inspeccionar la historia del inodo por contenido y metadata en ambos puntos del tiempo. Trata la ruta como “cambiada”, no “mismo nombre implica mismo archivo”.

Mistake 5: Ejecutar diffs enormes en producción en el peor momento posible

Síntoma: Picos de latencia durante zfs diff, usuarios se quejan, gráficas se ponen en rojo.

Causa: El recorrido pesado de metadata puede competir con la carga por ARC e IO. En algunos datasets, esto es efectivamente una tormenta de lecturas.

Solución: Ejecuta diffs fuera de pico, diffa subárboles más pequeños (filtra la salida) o realiza diffs en un host réplica cuando sea posible. Si debes diffear en prod, mantenlo corto y dirigido.

Mistake 6: Confundir “sin salida” con “sin cambios” cuando los permisos bloquean la visibilidad

Síntoma: Obtienes errores, salida truncada o resultados inesperadamente vacíos cuando sabes que ocurrieron cambios.

Causa: Privilegios insuficientes para recorrer snapshots o internals del dataset, especialmente en sistemas endurecidos.

Solución: Ejecuta como root (o con los permisos ZFS delegados apropiados). Confirma que el dataset es accesible y que los directorios de snapshot no están bloqueados por opciones de montaje o marcos de seguridad.

Listas de verificación / plan paso a paso

Checklist: “¿Qué cambió desde el último despliegue conocido bueno?”

  1. Identifica el último snapshot conocido bueno (usualmente tomado pre-despliegue).
  2. Toma un snapshot “now” si el sistema sigue cambiando.
  3. Ejecuta zfs diff snapshot-a-snapshot.
  4. Resume cambios por tipo y por directorio.
  5. Inspecciona una lista corta de rutas de alto valor: configuración, binarios, unit files de servicio y secretos.
  6. Decide entre rollback, restauración selectiva o corrección hacia adelante.
cr0x@server:~$ sudo zfs snapshot tank/app@now
cr0x@server:~$ sudo zfs diff tank/app@predeploy tank/app@now | awk '{print $1}' | sort | uniq -c
cr0x@server:~$ sudo zfs diff tank/app@predeploy tank/app@now | grep -E '^[M+-][[:space:]]+/(etc|usr|opt)/' | head -200

Consejo para decidir: Si los cambios se concentran en datos de app y logs, un rollback podría destruir estado legítimo. Si los cambios están en binarios/configuración solamente, el rollback es más seguro.

Checklist: “Restauración selectiva sin rollback completo”

  1. Diff entre snapshot conocido bueno y snapshot malo y extrae archivos eliminados/modificados en directorios críticos.
  2. Verifica existencia y sanidad de las copias en snapshot.
  3. Restaura con cp -a (o rsync -aHAX si está disponible) desde .zfs/snapshot.
  4. Reinicia el servicio y vuelve a comprobar.
  5. Documenta exactamente lo que restauraste (porque la próxima persona lo preguntará).
cr0x@server:~$ sudo zfs diff tank/app@good tank/app@bad | grep -E '^[M-][[:space:]]+/(etc/app|usr/local/bin)/' | head -50
cr0x@server:~$ sudo cp -a /app/.zfs/snapshot/good/etc/app/app.conf /app/etc/app/app.conf
cr0x@server:~$ sudo cp -a /app/.zfs/snapshot/good/usr/local/bin/app /app/usr/local/bin/app

Checklist: “Comprobación de sanidad de replicación antes del corte”

  1. Elige un nombre de snapshot específico que exista en fuente y destino después del receive.
  2. Compara diffs de snapshots de datasets representativos: baseline de fuente vs snapshot de corte; luego verifica que el destino tenga el mismo snapshot y permanezca quiescente.
  3. Asegura que nada esté escribiendo en mountpoints del destino antes del corte.
cr0x@server:~$ zfs list -t snapshot -o name | grep '^tank/app@cutover$'
cr0x@server:~$ sudo zfs diff tank/app@baseline tank/app@cutover | head

Preguntas frecuentes

1) ¿Muestra zfs diff el contenido de los archivos?

No. Reporta rutas cambiadas y el tipo de cambio (añadido/eliminado/modificado/renombrado). Para ver contenidos, navega los directorios de snapshot y usa herramientas de texto, o calcula hashes en ambas versiones.

2) ¿Puedo hacer diff de snapshots entre diferentes datasets?

No en el sentido de “comparar árboles arbitrarios.” zfs diff está pensado para snapshots dentro de la misma línea de dataset. Si necesitas comparaciones entre datasets, monta ambos snapshots y usa herramientas externas (con las habituales advertencias de rendimiento y corrección).

3) ¿Por qué veo miles de entradas M después de un escaneo de seguridad?

Porque “modificado” incluye cambios de metadata, y los escaneos pueden tocar atime o xattrs dependiendo de la configuración. Revisa atime y si el escáner escribe atributos extendidos o etiquetas de cuarentena.

4) ¿Por qué es lento zfs diff en este dataset?

Los árboles de directorio grandes con muchos archivos pequeños y rotación son el peor caso. La herramienta tiene que recorrer y reconstruir rutas, lo que es intensivo en metadata. Si el ARC está frío, hará IO real. Resume primero, filtra a subárboles y considera ejecutar diffs en un host réplica.

5) ¿Un renombrado siempre aparece como R?

No. La detección de renombre depende de la habilidad de la herramienta para correlacionar identidad de objeto y cambios en la estructura de directorio. Si no puede probar un renombrado, verás un borrar más un añadir. Trátalo como “algo se movió o fue reemplazado” y confirma inspeccionando los contenidos del snapshot.

6) ¿Puedo usar zfs diff para detectar ransomware?

Es una buena señal de alerta temprana: modificaciones masivas, renombres uniformes, ráfagas de eliminaciones. Pero no te dirá qué proceso lo hizo. Combínalo con política de snapshots inmutables, controles de acceso y telemetría a nivel de host.

7) ¿Qué es más seguro en un incidente: rollback o restauración selectiva?

El rollback es rápido y limpio cuando el dataset es mayormente código/config y el sistema puede tolerar revertir estado. La restauración selectiva es más segura cuando el dataset incluye datos vivos de registro. Usa zfs diff para decidir en lugar de adivinar.

8) ¿La encriptación cambia cómo funcionan los diffs?

No conceptualmente. Aún diffas árboles de snapshot dentro del dataset. Operativamente, asegúrate de tener las claves cargadas y permisos para recorrer el dataset y los snapshots; de lo contrario obtendrás errores o visibilidad incompleta.

9) ¿Cómo evito ruido si solo me importa la deriva de configuración?

Filtra la salida del diff a los directorios que importan (/etc, definiciones de servicio, config de la app). También considera separar datasets: pon logs y caches en su propio dataset para que diffs sobre el “dataset de configuración” sigan siendo legibles.

10) ¿Puedo automatizar zfs diff para trazas de auditoría?

Sí, pero ten cuidado: diffs de alta frecuencia en datasets de alta rotación pueden convertirse en carga auto infligida y generar ruido inútil. Resume y limita el alcance de la salida a subárboles significativos.

Conclusión

zfs diff es la herramienta a la que recurrir cuando la línea temporal importa y ya no quieres adivinar. Convierte snapshots de “podemos revertir” a “podemos explicar exactamente qué pasó”, que es una capacidad distinta y más poderosa.

Úsala como un operador: verifica que diffas los snapshots correctos, resume antes de inspeccionar en profundidad, filtra agresivamente y confirma rutas de alto impacto inspeccionando contenidos de snapshot. Y cuando sea lenta o ruidosa, tómatelo como información sobre el diseño de tu dataset y la rotación—no como un insulto personal del sistema de archivos.

← Anterior
Proxmox «VM is locked (backup/snapshot)»: cómo eliminar un bloqueo de forma segura
Siguiente →
Correo electrónico: Inundación de spam entrante — sobrevive al ataque sin bloquear usuarios reales

Deja un comentario