Tienes datos en una máquina ZFS más nueva que el destino. O el origen es antiguo y frágil, y el destino nuevo es estricto con las características.
En cualquier caso, tu primer “zfs send | zfs receive” parece confiado hasta que falla a las 2 a.m. con un mensaje de error que da a entender que nadie sabe por qué.
Esta es la realidad operativa: la replicación ZFS es potente, pero no es mágica. Los flujos de envío llevan suposiciones —sobre las características del conjunto de datos,
los feature flags del pool, modos de cifrado e incluso si el destino entiende el dialecto que usas. Esta guía es cómo dejar de adivinar.
Un modelo mental que realmente predice fallos
La replicación ZFS son dos contratos separados superpuestos:
-
El contrato del pool: ¿puede el pool de destino siquiera representar las estructuras en disco requeridas por el estado entrante del dataset?
Aquí es donde importan los feature flags del pool y las “versiones” de ZFS. -
El contrato del stream: ¿es el formato del send stream comprensible por la implementación ZFS del receptor, y contiene tipos de registro que pueda aplicar?
Aquí es donde las “nuevas características del send stream” y flags como-L,-c,-w,
-e, o--rawpueden jugarte una mala pasada.
Esos contratos están relacionados pero no son idénticos. Puedes tener un pool destino que soporte todos los feature flags necesarios y aún así fallar porque
usaste un sabor de stream que el receptor no sabe parsear. O a la inversa: el receptor entiende el stream, pero el pool destino
no puede activar de forma segura una característica requerida.
Deja de pensar en “versiones de ZFS”
La gente pregunta: “¿Puede ZFS 2.1 enviar a ZFS 0.8?” Esa pregunta es entendible y a menudo inútil. En el ecosistema OpenZFS, lo que importa es:
- Feature flags del pool (
zpool get all,zpool status,zpool get feature@*). - Características y propiedades del dataset (cifrado, bloques grandes, datos embebidos, redaction, etc.).
- Características del stream negociadas por el receptor (qué puede aceptar
zfs receive). - Lo que pediste a
zfs send(raw vs descifrado, comprimido o no, recursión de replicación, propiedades).
Operativamente, la compatibilidad es una intersección de tres: capacidades del pool origen, capacidades del pool destino y el formato del send stream elegido.
Si cualquiera es “demasiado nuevo” para los demás, la replicación falla. O peor: tiene éxito pero fuerza decisiones que no advertiste (como perder cifrado
o heredar mountpoints no deseados en producción).
Una idea parafraseada de Jeff Bezos (relacionada con fiabilidad, y dolorosamente cierta para ops): “Sé terco en la visión, flexible en los detalles.”
Para la replicación ZFS, tu visión es la integridad de los datos. Tus “detalles” son las flags del stream. Sé flexible ahí.
Hechos e historia relevantes para producción
- ZFS originalmente usaba “versiones de pool” (un entero único). El OpenZFS moderno pasó a feature flags para que los pools puedan evolucionar sin un gran salto de versión.
- Los feature flags son por pool, no por host. Actualizar el SO no actualiza el pool hasta que explícitamente habilites características (a menudo vía
zpool upgrade). - Una vez activa una característica del pool, normalmente no se retrocede. “Downgrade” suele ser “restaurar desde replicación a un pool más antiguo”, no una reversión in situ.
- Los send streams pueden incluir más que bloques: propiedades, snapshots, clones y a veces suposiciones sobre mountpoints y holds.
- Los datasets cifrados cambiaron la semántica de replicación. Los envíos raw preservan el cifrado y las claves permanecen en el origen; los envíos no-raw pueden entregar texto plano silenciosamente.
- Los bookmarks existen para hacer robusta la replicación incremental sin conservar snapshots antiguos para siempre, pero necesitas soporte en el receptor y nombres disciplinados.
- El envío comprimido no es solo “compresión en la red”. Dependiendo de flags y versiones, puede llevar bloques ya comprimidos; excelente para ancho de banda, confuso para compatibilidad.
- El soporte de bloques grandes no es solo una propiedad. Interactúa con feature flags del pool y el comportamiento del receptor; los desajustes pueden generar errores de receive que parecen corrupción.
- OpenZFS es multiplataforma, pero no perfectamente uniforme. FreeBSD, derivados de illumos y Linux generalmente se alinean, pero características de borde llegan en momentos distintos.
Chiste #1: Las discusiones sobre compatibilidad ZFS son como chats familiares grupales: todos juran hablar el mismo idioma, y nadie lo hace.
Reglas de compatibilidad: qué debe coincidir y qué puede diferir
Regla 1: el destino debe soportar todas las características en disco requeridas por el estado entrante del dataset
Si el send stream representa un estado del dataset que requiere una característica que el pool destino no puede habilitar, el receive fallará. Esto no es negociable.
No importa lo educadas que sean tus flags de send.
Matiz clave: un pool puede tener características “enabled” pero no “active”. Una característica “enabled” está disponible; “active” significa que ya se usa en los metadatos del pool.
La replicación puede disparar la activación cuando materializa estructuras que la requieren.
Regla 2: el receptor debe entender el formato de stream que generas
Algunas mejoras del send stream son puramente aditivas; receptores antiguos pueden fallar con tipos de registro desconocidos. Si tu destino es más antiguo, asume
que necesitas mantener el stream conservador a menos que hayas verificado soporte del receptor.
Regla 3: el cifrado es un multiplicador de compatibilidad
Los datasets cifrados son donde “funcionó en laboratorio” suele morir en producción. La decisión crítica es si envías:
- Raw cifrado (preserva el cifrado, requiere soporte de receive cifrado en destino y las características de cifrado).
- Descifrado (los datos llegan en texto plano; puede ser aceptable para migrar a un nuevo dominio de cifrado, pero es una decisión de seguridad, no una conveniencia).
Si el destino es más antiguo y no puede hacer receive cifrado correctamente, o lo actualizas, o aceptas replicación en texto plano y vuelves a cifrar en destino.
Fingir que hay una tercera opción es como terminar con backups “temporales” sin cifrar en el lugar equivocado.
Regla 4: los streams incrementales requieren historia compartida
El send incremental depende de un snapshot común (o bookmark) existente en ambos lados. Si el destino lo perdió, renombró o nunca lo recibió, el incremental falla.
La solución suele ser reseed con un send completo o usar una cadena de bookmarks bien gestionada.
Regla 5: la recursión y las propiedades pueden ser peligrosas
zfs send -R es cómodo. También replica gustosamente propiedades que quizá no quieras en el destino: mountpoints, sharenfs/smb,
reservas de cuota y ajustes heredados extraños. Trata -R como un cambio en producción, no como una copia inocua.
Tareas prácticas: comandos, salidas y decisiones
Estos son los chequeos que realmente ejecuto antes y durante migraciones. Cada uno incluye lo que significa la salida y la decisión derivada.
Ejecútalos en ambos extremos. Compara. No supongas.
Tarea 1: Identificar implementación y versión de ZFS (Linux)
cr0x@server:~$ modinfo zfs | egrep 'version:|srcversion:'
version: 2.2.2-1
srcversion: 1A2B3C4D5E6F7G8H9I0J
Significado: Esto te dice la versión del módulo OpenZFS en Linux. No es toda la historia, pero ancla expectativas.
Decisión: Si el destino es significativamente más antiguo, planifica streams conservadores y espera desajustes de características.
Tarea 2: Identificar la versión del userland de ZFS
cr0x@server:~$ zfs version
zfs-2.2.2-1
zfs-kmod-2.2.2-1
Significado: El módulo del kernel y el userland deberían estar alineados razonablemente. Grandes desincronizaciones pueden causar comportamientos extraños.
Decisión: Si están fuera de sincronía, arréglalo primero. Depurar replicación mientras tu stack está medio actualizado es un hobby, no un trabajo.
Tarea 3: Comprobar feature flags del pool en el origen
cr0x@server:~$ zpool get -H -o name,property,value all tank | head
tank size 23.8T
tank capacity 61%
tank health ONLINE
tank ashift 12
tank autotrim off
Significado: Sanidad básica, y prueba de que el pool es legible. Aún no es suficiente para compatibilidad.
Decisión: Si la salud del pool no es ONLINE, para y arregla eso antes de migrar. La replicación no es una estrategia de reparación.
Tarea 4: Enumerar feature flags explícitamente
cr0x@server:~$ zpool get -H -o property,value feature@* tank | egrep 'active|enabled' | head
feature@async_destroy active
feature@bookmarks active
feature@embedded_data active
feature@extensible_dataset active
feature@encryption active
feature@device_removal enabled
Significado: “active” significa usado; “enabled” significa disponible. Cualquier cosa active en el origen es una señal de alerta para destinos más antiguos.
Decisión: Compara esto con las features soportadas por el pool destino. Si el destino no soporta una feature active, debes actualizar destino o migrar por otra vía.
Tarea 5: Comprobar qué features soporta el pool destino
cr0x@server:~$ zpool get -H -o property,value feature@* backup | head
feature@async_destroy enabled
feature@bookmarks enabled
feature@embedded_data enabled
feature@encryption disabled
feature@extensible_dataset enabled
feature@filesystem_limits enabled
Significado: Si una feature requerida está disabled porque la implementación no la conoce, estás atascado.
Si está disabled pero conocida, podrías habilitarla.
Decisión: Si el origen requiere feature@encryption active y el destino muestra feature@encryption disabled, actualiza OpenZFS/pool destino o planifica una migración descifrada (con los ojos abiertos).
Tarea 6: Confirmar estado de cifrado del dataset y manejo de claves
cr0x@server:~$ zfs get -o name,property,value -H encryption,keylocation,keystatus tank/prod
tank/prod encryption aes-256-gcm
tank/prod keylocation file:///root/keys/prod.key
tank/prod keystatus available
Significado: Estás lidiando con cifrado nativo de ZFS. Las opciones de replicación importan.
Decisión: Si necesitas preservar el cifrado, planifica send raw y asegúrate de que el destino lo soporte. Si aceptas re-cifrar, planifica envío en texto plano y cifrado en destino.
Tarea 7: Listar snapshots y verificar que exista una base común
cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation tank/prod | tail -3
tank/prod@replica_2025-12-20 Sat Dec 20 02:00 2025
tank/prod@replica_2025-12-21 Sun Dec 21 02:00 2025
tank/prod@replica_2025-12-22 Mon Dec 22 02:00 2025
Significado: Esto muestra la cadena de snapshots disponible para envíos incrementales.
Decisión: Confirma que el destino también tiene el snapshot base que usarás. Si no, no puedes hacer incremental sin reseed.
Tarea 8: Verificar que el destino tiene el snapshot base
cr0x@server:~$ zfs list -t snapshot -o name backup/prod | head -3
NAME
backup/prod@replica_2025-12-20
backup/prod@replica_2025-12-21
Significado: Bien: existe historia compartida.
Decisión: Procede con el incremental desde el snapshot común más reciente. Si falta, detente y reseed o usa una estrategia de bookmarks.
Tarea 9: Estimar tamaño del send antes de saturar la WAN
cr0x@server:~$ zfs send -nP -i tank/prod@replica_2025-12-21 tank/prod@replica_2025-12-22
size 14839210496
incremental tank/prod@replica_2025-12-21 tank/prod@replica_2025-12-22
Significado: Unos 13.8 GiB de datos lógicos del stream (no necesariamente bytes en la red).
Decisión: Si eso es mayor de lo esperado, investiga churn (imágenes VM, bases de datos, desajuste de recordsize) antes de programar replicación en horas pico.
Tarea 10: Receive en modo simulación para validar permisos y dataset objetivo
cr0x@server:~$ zfs receive -nvu backup/prod
would receive incremental stream of tank/prod@replica_2025-12-22 into backup/prod
would destroy snapshots: none
would overwrite: none
Significado: -n es no-op, -v verbose, -u no montar. Esto confirma que el receptor entiende el stream y lo que haría.
Decisión: Si esto falla, no “lo ejecutes igual”. Arregla nombres, permisos y desajustes de features primero.
Tarea 11: Realizar un send incremental con resiliencia
cr0x@server:~$ zfs send -v -i tank/prod@replica_2025-12-21 tank/prod@replica_2025-12-22 | ssh backup01 zfs receive -uF backup/prod
send from tank/prod@replica_2025-12-21 to tank/prod@replica_2025-12-22 estimated size is 13.8G
total estimated size is 13.8G
TIME SENT SNAPSHOT
02:00:12 13.8G tank/prod@replica_2025-12-22
Significado: -F puede revertir el destino para que coincida; es útil pero peligroso.
Decisión: Usa -F solo para destinos de replicación dedicados donde el rollback no destruya cambios locales. Si humanos escriben allí, quita -F y arregla la divergencia correctamente.
Tarea 12: Inspeccionar una falla de receive y mapearla a compatibilidad
cr0x@server:~$ zfs receive -u backup/prod
cannot receive incremental stream: most recent snapshot of backup/prod does not match incremental source
Significado: El snapshot base en el destino es distinto del que estás enviando (o fue revertido/renombrado).
Decisión: Encuentra el snapshot común más reciente, o reseed con un send completo. No lo fuerces con rollback a menos que el destino sea descartable.
Tarea 13: Verificar holds para evitar que se borre el snapshot durante el envío
cr0x@server:~$ zfs holds tank/prod@replica_2025-12-22
NAME TAG TIMESTAMP
tank/prod@replica_2025-12-22 repl Fri Dec 22 02:00 2025
Significado: Un hold evita que la limpieza automática borre el snapshot que aún necesitas.
Decisión: Si ejecutas pruning de snapshots, usa holds (o bookmarks) para que la cadena incremental no sea “limpiada” hasta causar fallos.
Tarea 14: Usar bookmarks como anclas incrementales de larga vida
cr0x@server:~$ zfs bookmark tank/prod@replica_2025-12-22 tank/prod#bkm_2025-12-22
cr0x@server:~$ zfs list -t bookmark -o name,creation tank/prod | tail -1
tank/prod#bkm_2025-12-22 Mon Dec 22 02:00 2025
Significado: Los bookmarks son referencias livianas que permiten envíos incrementales sin conservar el snapshot completo para siempre.
Decisión: Si la presión de retención es alta, muévete a bookmarks. Pero prueba soporte en el receptor; sistemas más antiguos pueden no manejar bien incrementales basados en bookmarks.
Tarea 15: Confirmar mountpoint y comportamiento de canmount antes de usar -R
cr0x@server:~$ zfs get -o name,property,value -H mountpoint,canmount tank/prod
tank/prod mountpoint /prod
tank/prod canmount on
Significado: Si replicas propiedades, podrías montar rutas de producción en un servidor de backup. Eso no es un “ups”; es una interrupción.
Decisión: En el destino, usa zfs receive -u y establece mountpoints seguros. Considera eliminar o sobrescribir propiedades peligrosas.
Tarea 16: Confirmar que el dataset destino no esté montado (o montar con seguridad)
cr0x@server:~$ zfs get -o name,property,value -H mounted,mountpoint backup/prod
backup/prod mounted no
backup/prod mountpoint /backup/prod
Significado: Bien: no montará por sorpresa sobre algo.
Decisión: Mantén los destinos de replicación desmontados por defecto; monta solo cuando necesites leer o restaurar.
Elegir las flags de send correctas (y cuándo no hacerlo)
Empieza conservador, luego añade potencia
Al enviar a un receptor más antiguo, tu objetivo es compatibilidad aburrida, no ingenio. El enfoque más compatible suele ser:
un envío completo para el seeding, luego envíos incrementales, con flags minimalistas.
Raw vs no-raw con cifrado
Si el dataset está cifrado y quieres preservarlo tal cual (misma cifra, mismas claves no expuestas), quieres send raw. Dependiendo de tu plataforma,
eso suele ser zfs send -w (raw) y recibir en un destino que soporte receive cifrado.
cr0x@server:~$ zfs send -w tank/prod@replica_2025-12-22 | ssh backup01 zfs receive -u backup/prod
cannot receive: stream is encrypted but encryption feature is disabled
Significado: El destino no puede aceptar stream cifrado/raw porque su pool o implementación carece de soporte de cifrado.
Decisión: Actualiza OpenZFS y features del pool en el destino, o cambia a send no-raw (aceptando transferencia en texto plano) y re-cifra en destino.
Send comprimido: genial hasta que no lo es
El send comprimido puede reducir ancho de banda y CPU en algunos casos, pero depende del soporte del receptor. En versiones mixtas, trátalo como una optimización
que te ganas, no como un defecto por defecto.
Streams de replicación (-R) y minas de propiedades
-R es para replicar un subtree con snapshots, propiedades y datasets descendientes. Es perfecto para DR.
También es una forma elegante de replicar un mountpoint problemático en el lugar equivocado.
cr0x@server:~$ zfs send -R tank/prod@replica_2025-12-22 | ssh backup01 zfs receive -u backup/tank
receiving full stream of tank/prod@replica_2025-12-22 into backup/tank/prod
Significado: Estás recreando la estructura en el destino. Las propiedades pueden venir de serie.
Decisión: Si el destino no es un entorno espejo, evita -R. O úsalo, pero inmediatamente sobrescribe propiedades peligrosas en el destino.
Force receive (-F): a veces requerido, a menudo abusado
zfs receive -F revierte el destino para coincidir con el stream. Arregla divergencias. También borra snapshots y cambios locales que conflijan.
En términos corporativos, -F es un despido masivo: efectivo, rápido, y debería tener aprobaciones.
Compatibilidad de dataset: recordsize, volblocksize y bloques grandes
Las propiedades del dataset en sí pueden causar sorpresas de rendimiento incluso si el stream se recibe bien. Un origen más nuevo con recordsize grande y ajustes afinados
puede replicarse a un destino más antiguo que técnicamente lo acepta, pero luego tu rendimiento de restauración es extraño y tus supuestos se rompen.
Chiste #2: Si quieres emoción, replica bases de datos por una VPN inestable; si quieres dormir, haz un send completo un fin de semana y trae tentempiés.
Tres mini-historias corporativas desde las trincheras de replicación
Incidente: una suposición equivocada sobre “compatibilidad de versiones”
Una empresa mediana migraba de almacenamiento FreeBSD antiguo a un appliance Linux con OpenZFS más nuevo. El plan parecía simple:
inicializar la nueva caja, cortar los exports NFS, retirar el hardware viejo. Alguien preguntó, “¿Son compatibles las versiones de ZFS?” y obtuvo un confiado “Sí, ZFS es ZFS.”
Esa frase les costó un fin de semana.
El pool origen tenía varios feature flags activos (bookmarks, embedded_data, large_blocks). El sistema destino sí soportaba algunos, pero el pool
del appliance nunca se había actualizado y corría con un conjunto conservador porque así venía por defecto. Durante pruebas iniciales replicaron
un dataset pequeño sin que se activaran las características nuevas. En producción, el estado principal del dataset sí las requería.
El receive falló a mitad del seed stream. El mensaje de error no ayudaba; parecía una falla genérica de receive. Reintentaron, obtuvieron errores distintos,
y cayeron en la trampa clásica: “Quizá es la red”. No lo fue. Era el contrato del pool.
La solución fue aburrida: actualizar explícitamente el pool destino para soportar los feature flags necesarios, y luego re-seedar. Pero el re-seed implicó otra
transferencia larga, y la ventana de corte ya estaba ocupada por otros equipos. Terminaron haciendo una migración parcial y arrastrando hardware antiguo por semanas.
La lección no fue “actualiza todo”. La lección fue: inventaria features antes de mover bytes, y trata las actualizaciones de pool como operaciones gestionadas
con planes de rollback (que normalmente significan “replicar a otro lado”, no “deshacer”).
Optimización que salió mal: flags agresivas en una flota mixta
Otra compañía tenía una flota de oficinas remotas, cada una con una pequeña caja ZFS que replicaba a un clúster DR central. El ancho de banda era limitado y caro.
Un ingeniero decidió “hacer el stream más pequeño” activando send comprimido y recursión en todas partes, y usando force receive para mantener todo alineado.
Funcionó al principio, que es el estado más peligroso para un cambio. Con el tiempo, algunas oficinas actualizaron ZFS como parte de ciclos de refresco del SO,
mientras otras se quedaron atrás por restricciones de aplicaciones. El script de replicación no cambió; usó las mismas flags para todas.
Un subconjunto de receptores empezó a fallar intermitentemente en una clase de dataset: zvols de VM. Los fallos coincidieron con un cambio en cómo esos sistemas
creaban snapshots y qué contenían los streams. El script, ejecutándose con zfs receive -F, empezó a revertir y reaplicar estado repetidamente.
Los datos no se corrompieron, pero los objetivos de punto de recuperación empeoraron porque la canalización pasaba tiempo luchando consigo misma.
Eventualmente descubrieron dos cosas: primero, el send comprimido no era soportado de forma uniforme entre versiones receptoras para las formas de stream específicas generadas;
segundo, -F estaba enmascarando el problema subyacente de “snapshot común faltante” al reescribir constantemente la historia del destino, lo que fragilizó las cadenas incrementales.
La solución fue dividir la flota en niveles de compatibilidad. Streams conservadores para receptores antiguos, streams modernos para los nuevos, y quitar -F
salvo para destinos dedicados tratados explícitamente como espejos descartables. El ancho de banda subió algo. El sueño mejoró mucho.
Práctica aburrida pero correcta que salvó el día: inventario de features + seeding por etapas
Un equipo de servicios financieros planeó un traslado de centro de datos. Tenían ZFS en ambos extremos, pero el destino lo gestionaba otro grupo con ritmo de actualizaciones distinto.
En vez de precipitarse con flags de stream, hicieron una disciplina simple: inventariar features del pool y propiedades de datasets, y acordar una línea base de compatibilidad.
Crearon un pool staging en el destino dimensionado para aceptar seeds completos, y ejecutaron receives en modo dry-run durante horas laborales para verificar que los streams se parsearan y que
no implicaran acciones destructivas. Usaron zfs send -nP para estimar y programar grandes transferencias, y emplearon holds de snapshots para que la limpieza automática
no rompiera incrementales durante la ventana de corte.
Durante la mudanza real, la red tuvo un mal día. Las transferencias se ralentizaron y stallaron. Pero como ya habían seeded la mayoría de datasets y verificado compatibilidad incremental,
solo necesitaron pequeños deltas para el corte. La red lenta fue una molestia, no una crisis.
No pasó nada heroico. Ese es el punto. La práctica correcta lucía aburrida en las reuniones de estado, pero redujo las incógnitas casi a cero.
Guía rápida de diagnóstico
Cuando la replicación falla o va lenta, quieres un bucle corto: identifica si es una falla de compatibilidad, un desajuste de historia o un cuello de botella de throughput.
Comprueba en este orden. No te saltes a tunear flags.
Primero: ¿es una falla de compatibilidad?
- En el destino, intenta un receive en simulación:
zfs receive -nvu target/ds. Si el parseo falla, es compatibilidad de stream o permisos. - Compara feature flags:
zpool get feature@* srcpoolvszpool get feature@* dstpool. - Revisa estado de cifrado:
zfs get encryption,keystatus. Si usas raw send, el destino debe soportar cifrado.
Segundo: ¿es un desajuste de historia incremental?
- Confirma que ambos lados tienen el snapshot base:
zfs list -t snapshot | grep. - Verifica divergencia en el destino: ¿alguien tomó snapshots locales, revirtió o destruyó snapshots?
- Si usas bookmarks, verifica que existan en ambos extremos (o que tu send use snapshot-to-snapshot, no bookmark-to-snapshot).
Tercero: ¿es un cuello de botella de throughput?
- Estima tamaño del stream:
zfs send -nP. Si es enorme, el “cuello” puede ser churn, no la red. - Revisa CPU y compresión: si comprimes en vuelo externamente, la CPU puede ser el limitador.
- Observa red y SSH: si usas SSH, la elección de cifrado y el single-threading pueden limitar el throughput.
- Revisa rendimiento del pool: el pool destino puede estar fragmentado, ocupado o con settings de sync que limitan escrituras.
Esta guía es intencionalmente poco glamorosa. En producción, la solución más rápida suele ser “asumir correctamente” en vez de “tunear ingeniosamente.”
Errores comunes: síntoma → causa raíz → solución
1) “cannot receive: unsupported feature or stream”
Síntoma: Receive falla inmediatamente; el error menciona feature/stream no soportado, o simplemente “invalid stream”.
Causa raíz: El receptor destino no entiende los tipos de registro del stream, o el pool destino no puede soportar las features requeridas.
Solución: Compara zpool get feature@* y ajusta. Actualiza OpenZFS/pool destino, o envía un stream más conservador (evita raw/compressed/replication flags hasta verificar).
2) “most recent snapshot does not match incremental source”
Síntoma: El envío incremental falla; el destino tiene snapshots pero no el que esperabas.
Causa raíz: Se perdió el snapshot base común por pruning, renombres, destrucciones manuales o rollback del destino.
Solución: Encuentra el snapshot común más reciente y envía incrementales desde ahí. Si no existe, reseed con un send completo. Añade holds o bookmarks para prevenir recurrencias.
3) Replicación “tiene éxito” pero el destino monta sobre algo crítico
Síntoma: Contenido extraño en el filesystem del destino; servicios leyendo datos incorrectos; mountpoints cambiados.
Causa raíz: Propiedades replicadas (a menudo vía -R) aplicaron mountpoint/canmount/shares.
Solución: Siempre recibe con -u en rutas seguras; establece explícitamente mountpoint/canmount tras el receive. Evita replicar propiedades a menos que el destino sea un espejo real.
4) Raw encrypted send falla en el destino
Síntoma: Errores sobre feature de cifrado deshabilitada o problemas de claves.
Causa raíz: OpenZFS/pool del destino no soporta cifrado, o las claves no se manejan correctamente para el modo de receive.
Solución: Actualiza el destino para soportar cifrado y habilita las features necesarias del pool, o haz migración descifrada y vuelve a cifrar en el destino con nuevas claves.
5) “zfs receive” es lento y satura CPU
Síntoma: La red está relativamente ociosa; la CPU está al máximo; la replicación avanza a paso de tortuga.
Causa raíz: Estás haciendo compresión/cifrado pesado en userland (cifrado SSH, compresión externa), o el pool destino es el cuello de botella.
Solución: Reduce sobrecarga en userland (elige cifrados SSH sensatos, evita compresión innecesaria), revisa IOPS del pool destino y evita apilar compresión sobre datos ya comprimidos.
6) Incrementales se rompen aleatoriamente tras “trabajos de limpieza”
Síntoma: Funciona por días y luego falla tras ejecución de pruning de snapshots.
Causa raíz: La política de retención borra el snapshot base necesario para incrementales.
Solución: Usa holds de snapshot para anclas de replicación o pasa a bookmarks; alinea retención con frecuencia de replicación y lag.
7) El uso de espacio en destino explota después de la migración
Síntoma: Mismos datos lógicos, pero más espacio consumido en destino.
Causa raíz: Diferentes ajustes de compresión, diferencias de recordsize, comportamiento especial de vdev, o destino que no recibe bloques comprimidos como esperabas.
Solución: Revisa zfs get compression,recordsize y diferencias en diseño del pool. No asumas uso físico idéntico entre pools; valida con muestras pequeñas primero.
Listas de verificación / plan paso a paso
Plan A: Migración segura de un origen más nuevo a un destino más antiguo
-
Inventaria features y cifrado.
Ejecuta en origen y destino:zpool get feature@*,zfs get encryption,keystatus.
Decide: actualizar destino vs aceptar migración descifrada. -
Crea un dataset objetivo dedicado.
Manténlo desmontado: recibe con-u. Decide: ¿necesitas un espejo (-R) o un único dataset? -
Receive en simulación.
Usazfs receive -nvupara atrapar problemas de parseo/permisos sin escribir. -
Seed con un send completo.
Evita flags sofisticadas inicialmente. Valida que el snapshot exista en destino tras el receive. -
Pasa a envíos incrementales.
Usa nombres de snapshot consistentes; protege anclas con holds o bookmarks. -
Corte final.
Incremental final, verifica integridad a nivel de aplicación y luego cambia clientes.
Plan B: Construir un estándar de replicación en versiones ZFS mixtas
- Define niveles de compatibilidad. Agrupa sistemas por capacidad del receptor; no ejecutes una única combinación de flags “universal”.
- Elige un stream conservador por defecto. Solo añade raw/compressed/recursión tras validación por nivel.
- Estandariza nombres de snapshots y bookmarks. Tu yo futuro necesita coincidencia determinística, no creatividad.
- Automatiza validación. Periódicamente confirma que existen snapshots comunes y que receives en simulación funcionan.
- Documenta políticas de upgrade de pools. Las actualizaciones de pool son irreversibles; trátalas como eventos de cambio con aprobación.
Plan C: Cuando los incrementales están rotos y necesitas servicio de vuelta
- Deja de borrar snapshots. Pausa los trabajos de retención.
- Encuentra el snapshot común más reciente. Si existe, reanuda incrementales desde ahí.
- Si no hay snapshot común, reseeda. Send completo del snapshot más reciente; luego restablece la cadena incremental.
- Tras la recuperación, implementa holds/bookmarks. Evita repetir la caída por limpieza.
Guardarraíles operativos extra (hazlos y agradécetelo después)
- Los destinos de replicación deben tratarse como ganado: dedicados, no interactivos y seguros de revertir.
- Nunca replique mountpoints en un host que también ejecute aplicaciones a menos que tengas controles explícitos de propiedades.
- Prueba un dataset completo de extremo a extremo, incluida la restauración, antes de programar “la gran migración”.
Preguntas frecuentes
1) ¿Puede siempre un OpenZFS más nuevo enviar a un OpenZFS más antiguo?
No. El receptor debe entender el formato del stream, y el pool destino debe soportar las features requeridas. “ZFS es ZFS” no es un contrato.
2) ¿Cuál es el indicador más grande de incompatibilidad?
Features de pool activas en el origen que el destino no soporta. Revisa zpool get feature@* y busca “active” en el origen y “disabled/unsupported” en el destino.
3) Si el pool destino soporta una feature pero no está enabled, ¿el receive la activará?
Puede, dependiendo de la implementación y de las estructuras escritas. En la práctica, deberías gestionar explícitamente actualizaciones/habilitaciones de pool para no “activar accidentalmente” features irreversibles durante una migración.
4) ¿Es necesario el send raw para datasets cifrados?
Es necesario si quieres preservar el cifrado como ciphertext end-to-end. Si no usas raw, puedes estar enviando texto plano (incluso si el dataset origen está cifrado), y eso es una decisión de seguridad.
5) ¿Por qué el send incremental se queja de snapshots que no coinciden cuando los nombres parecen correctos?
Los nombres no son identidad. El snapshot del destino podría no ser el mismo estado (podría provenir de una historia distinta), o el destino fue revertido. Los incrementales requieren una cadena de ascendencia compartida.
6) ¿Debería siempre usar zfs send -R para replicación?
Solo si el destino está destinado a ser una réplica fiel de un subtree, incluidas propiedades y datasets descendientes. De lo contrario, -R puede replicar “suposiciones de entorno” que no querías copiar.
7) ¿Cuándo es apropiado zfs receive -F?
Para destinos de replicación dedicados donde el rollback es aceptable y esperado. No para datasets compartidos, no para nada que humanos modifiquen, y no como parche para retención rota.
8) ¿Cómo ayudan los bookmarks con compatibilidad y retención?
Los bookmarks permiten envíos incrementales sin conservar cada snapshot antiguo. Reducen la presión de retención y evitan que los trabajos de limpieza rompan incrementales, siempre que ambos extremos soporten envíos basados en bookmarks.
9) ¿Por qué la estimación del tamaño del send no coincide con los bytes reales transferidos?
La estimación es tamaño lógico del stream. Los bytes en la red dependen de si los bloques ya están comprimidos, si el stream está comprimido y qué overhead añade SSH/red.
10) ¿Puedo “downgradear” un pool para que coincida con un sistema más antiguo y que la replicación funcione?
No realísticamente in-place. Una vez que las features están activas, normalmente no se puede volver atrás. El downgrade práctico es: crea un pool compatible con versiones antiguas en otro lugar y replica en él usando streams compatibles.
Conclusión: siguientes pasos prácticos
Si adoptas una postura operacional de esta guía: la compatibilidad no es una sensación, es un inventario. No “pruebes un send” y esperes. Comprueba features del pool,
estado de cifrado del dataset, capacidad del receptor e historial de snapshots primero—luego mueve bytes.
Siguientes pasos que puedes hacer hoy:
- Ejecuta
zpool get feature@*en cada extremo de replicación y guarda las salidas en un lugar donde humanos las puedan comparar. - Elige un modo de replicación conservador por defecto para receptores antiguos y aplícalo por nivel.
- Implementa holds o bookmarks para que la retención no pueda romper tu cadena incremental.
- Practica restauraciones, no solo envíos. La replicación que no se puede recibir y montar de forma segura es solo streaming caro.