La replicación falla en el peor momento posible: justo después de que prometiste al negocio que el nodo DR está “totalmente sincronizado”. Entonces aparece una sola línea roja—replication failed—y de repente tu plan es solo una captura en una diapositiva.
Esta es una guía práctica de campo para la replicación en Proxmox VE cuando se rompe: qué está ocurriendo realmente bajo el capó, cómo diagnosticar rápidamente el cuello de botella y cómo recuperar sin convertir una pequeña interrupción en un fin de semana largo.
Qué hace realmente la “replicación” de Proxmox (y qué no hace)
En Proxmox VE, la “replicación” no es un espejo mágico a nivel de bloque para todo lo que puedas almacenar. Es un trabajo programado que—cuando usas almacenamiento basado en ZFS—crea snapshots de discos de VM y los envía desde un nodo origen a un nodo destino usando ZFS send/receive. Para pools ZFS locales, esto es fiable, rápido y relativamente aburrido. Cuando no lo es, es porque alguna de las capas subyacentes dejó de ser aburrida.
Bajo el capó, una ejecución típica de replicación se ve así:
- Proxmox coordina el trabajo (por VM, según el calendario).
- Se crean snapshots ZFS para los discos de la VM (datasets o zvols dependiendo de tu diseño).
- Se realiza un ZFS send incremental desde el último snapshot exitoso hasta el nuevo snapshot.
- El stream viaja por SSH hasta el nodo destino.
- El destino hace un ZFS receive en su dataset local.
- Proxmox registra éxito/fallo y poda snapshots antiguos de replicación.
Lo que no es no:
- No es un mecanismo de HA por sí mismo. Alimenta datos a un nodo; HA decide dónde ejecutar la VM.
- No es replicación continua. Es periódica; tu RPO es como máximo el intervalo de programación, más cualquier retraso que acumule el trabajo.
- No sustituye a las copias de seguridad. La replicación replica con gusto corrupción, borrados y errores humanos.
- No es independiente del tipo de almacenamiento. Si no usas almacenamiento compatible con replicación ZFS, estás en otro universo de resolución de problemas.
Una cita, porque sigue capturando la realidad en producción: “La esperanza no es una estrategia.” —idea parafraseada atribuida a líderes de fiabilidad en operaciones.
Datos interesantes y contexto histórico
- Los snapshots ZFS son baratos porque son referencias de metadatos, no copias completas—hasta que cambias bloques; entonces el uso de espacio crece con la divergencia.
- ZFS send/receive viene de los primeros días de Solaris ZFS y se hizo popular porque era una primitiva de replicación portable y streamable con consistencia integrada.
- Los envíos incrementales requieren un snapshot común en ambos lados; quítalo en cualquiera de los dos extremos y rompes la cadena.
- La replicación de Proxmox siempre ha sido “centrada en el almacenamiento”: está construida alrededor de la semántica de ZFS, no de copiar discos genéricos.
- SSH es parte de tu canal de almacenamiento para la replicación ZFS; la gestión de llaves y las claves de host pueden romper el “almacenamiento” de una manera no relacionada con almacenamiento.
- Los tokens de reanudación (función ZFS) pueden permitir que un receive interrumpido se reanude sin empezar de cero, pero también crean estados confusos si no los reconoces.
- ZFS puede detectar corrupción silenciosa con sumas de verificación, pero la replicación aún puede propagar corrupción lógica (como borrar un archivo de base de datos limpiamente).
- Las convenciones de nombres de snapshots importan porque las herramientas esperan patrones; una limpieza ad-hoc de snapshots puede hacer que Proxmox parezca “equivocado” cuando ZFS realmente está bien.
- La deriva temporal es un viejo enemigo: la programación, el orden de trabajos, la correlación de logs e incluso la validación de certificados empeoran con NTP descuidado.
Guion rápido de diagnóstico (comprueba 1/2/3)
Este es el orden para “dejar de adivinar”. Estás intentando identificar el cuello de botella en minutos, no leyendo cada log desde el martes pasado.
1) ¿Es fallo del plano de control (Proxmox) o del plano de datos (ZFS/SSH/red)?
- Si el trabajo no arranca, no puede resolver nodos o informa problemas de permisos: plano de control.
- Si arranca pero falla a mitad de stream, se queda bloqueado o informa errores de ZFS receive: plano de datos.
2) Confirma el estado del trabajo de replicación y el último error
- Revisa los logs de tareas y el journal del worker de replicación.
- Extrae el error real de ZFS (dataset exists, no space, invalid stream, etc.).
3) Valida los tres requisitos aburridos
- SSH funciona de forma no interactiva desde el origen al destino para root (o el usuario configurado).
- Los pools ZFS están sanos en ambos extremos y tienen espacio libre/margen.
- Existe un snapshot común para la replicación incremental.
4) Si está lento/atascado en vez de “fallado”, aísla el throughput
- ¿Está limitado por la red? (iperf3, errores de interfaz, duplex, desajuste de MTU)
- ¿Está limitado por disco? (zpool iostat, contención de txg sync)
- ¿Está limitado por CPU? (compresión, cifrado, cuellos de botella de un solo hilo)
Regla de decisión: si no puedes nombrar el cuello de botella después de 10 minutos, no estás comprobando las cosas correctas—estás leyendo.
Por qué se rompe la replicación: los modos de fallo reales
1) Ruptura de la cadena de snapshots (el clásico)
La replicación incremental ZFS depende de: “enviar desde snapshot A hasta snapshot B”. Eso requiere que el snapshot A exista en ambos, origen y destino. Si alguien borra snapshots en el destino para “ahorrar espacio” o ejecuta una poda agresiva, tu siguiente send incremental fallará porque no hay base común.
Este modo de fallo es común porque parece mantenimiento. La gente ve snapshots, asume que son “temporales” y los limpia. Luego la replicación exige justamente el snapshot que acabas de borrar.
2) Coincidencia incorrecta del dataset objetivo (lugar, tipo o nombre equivocado)
ZFS receive es quisquilloso, en el buen sentido. Si el dataset destino existe pero no coincide con lo esperado (desajuste de tipo: dataset vs zvol, propiedades incompatibles, semántica de mountpoint distinta), receive puede fallar. Proxmox espera ciertas estructuras de dataset bajo un storage ID. Cambios manuales en el destino pueden provocar que el siguiente receive choque con la realidad.
3) Sin espacio (y no solo el “df -h”)
ZFS necesita margen para copy-on-write, metadatos y comportamiento de grupos de transacción. Un pool al 95% no está “bien”. Es un pool preparando una pequeña ópera llamada ENOSPC.
También vigila:
- quota/reservation en datasets
- refquota/refreservation
- clases de asignación especiales (special vdev lleno)
- comportamiento del slop space
4) Fallos en SSH y en la gestión de llaves (el almacenamiento es asaltado en un callejón oscuro)
La replicación usa SSH. Eso significa que cambios en claves de host, cifrados endurecidos, llaves revocadas, nuevas políticas de salto o una rotación de la contraseña root pueden romper la replicación con errores que parecen “almacenamiento” pero no lo son.
Chiste #1: SSH es como una tarjeta corporativa—todo funciona hasta que Seguridad la “mejora” cinco minutos antes de tu ventana de mantenimiento.
5) Problemas en la ruta de red: MTU, pérdidas, enrutamiento asimétrico
ZFS send es un stream constante. Si la red pierde paquetes, verás estancamientos, resets o streams corruptos. Si el MTU está desajustado (un extremo a 9000, el otro no), puede haber fragmentación, rendimiento extraño o fallos según la ruta.
6) Problemas de salud del pool: degradado, errores, I/O lento
Si un pool está degradado, en resilvering o arrojando errores de checksum, la replicación puede fallar o volverse glacial. Proxmox reportará “failed”, pero el problema real es el subsistema de almacenamiento con problemas.
7) Flags de características ZFS y versiones incompatibles
Si el pool destino no soporta una característica usada en el stream de envío (o usas sends raw/encrypted sin soporte coincidente), receive puede fallar. Esto importa cuando replicas entre nodos con diferentes versiones de ZFS o conjuntos de feature flags habilitados distintos.
8) Problemas con claves de cifrado y envíos/receives raw
Los datasets cifrados pueden replicarse como streams raw (manteniendo los datos cifrados) o como streams descifrados (requiriendo llaves). Si tu política cambió a mitad del proceso, o las llaves no están cargadas en el destino cuando se necesitan, verás errores del tipo “cannot mount” o “key not loaded”.
9) Planificador y contención de locks
Los trabajos de replicación pueden entrar en conflicto con backups, operaciones con muchos snapshots, scrub/resilver u otros picos de I/O. A veces el fallo es solo un timeout o un problema de locks. Otras veces es un simple “demasiados trabajos a la vez” vestido de complejidad.
10) Estado de receive corrupto o incompleto (resume tokens, datasets parciales)
Un receive interrumpido puede dejar estado parcial. ZFS moderno puede emitir un resume token para continuar. Pero si el receive fue interrumpido y luego alguien “arregló” manualmente borrando snapshots/datasets, puedes acabar con un enredo que requiere limpieza cuidadosa.
Tareas prácticas: comandos, salidas y decisiones
Estas son tareas reales que puedes ejecutar en nodos Proxmox. Cada una incluye: comando, salida de ejemplo, qué significa y la decisión que tomas.
Task 1: Confirmar trabajos de replicación y último estado
cr0x@server:~$ pvesr status
JobID Guest Target Status Last Sync
local-zfs:101 101 pve02 ok 2025-12-26 09:10:02
local-zfs:102 102 pve02 failed 2025-12-26 08:55:14
Significado: El trabajo de la VM 102 falló; tienes una marca temporal para correlacionar.
Decisión: Extrae el log de la tarea específica para esa ventana de tiempo y VM/ID de trabajo antes de tocar nada.
Task 2: Leer el log de tarea de Proxmox para la replicación fallida
cr0x@server:~$ grep -R "local-zfs:102" /var/log/pve/tasks/active /var/log/pve/tasks/index 2>/dev/null | tail -n 5
/var/log/pve/tasks/index:UPID:pve01:0000A3F1:0B7C9E2A:676D22E2:pvesr:local-zfs:102:root@pam:
cr0x@server:~$ cat /var/log/pve/tasks/UPID:pve01:0000A3F1:0B7C9E2A:676D22E2:pvesr:local-zfs:102:root@pam:
starting replication job 'local-zfs:102'
command: /usr/bin/ssh -o BatchMode=yes pve02 -- zfs receive -o readonly=on -u -F rpool/replica/vm-102-disk-0
cannot receive incremental stream: most recent snapshot of rpool/replica/vm-102-disk-0 does not match incremental source
TASK ERROR: command 'ssh ... zfs receive ...' failed: exit code 1
Significado: Mismatch de snapshot base incremental. Alguien borró o alteró snapshots en un lado, o el dataset divergió.
Decisión: Verifica snapshots en ambos lados; planifica un envío completo nuevo (o rebase) en lugar de reintentos ciegos.
Task 3: Inspeccionar snapshots en el dataset origen
cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation rpool/data/vm-102-disk-0 | tail -n 8
rpool/data/vm-102-disk-0@replicate_2025-12-26_08-00-01 Fri Dec 26 08:00 2025
rpool/data/vm-102-disk-0@replicate_2025-12-26_08-30-01 Fri Dec 26 08:30 2025
rpool/data/vm-102-disk-0@replicate_2025-12-26_08-45-01 Fri Dec 26 08:45 2025
rpool/data/vm-102-disk-0@replicate_2025-12-26_09-00-01 Fri Dec 26 09:00 2025
Significado: El origen tiene snapshots de replicación continuos. Bien.
Decisión: Compáralo con el destino. Si el destino no tiene el snapshot base, necesitarás un re-seed completo o restaurar un snapshot coincidente.
Task 4: Inspeccionar snapshots en el dataset destino
cr0x@server:~$ ssh pve02 -- zfs list -t snapshot -o name,creation -s creation rpool/replica/vm-102-disk-0 | tail -n 8
rpool/replica/vm-102-disk-0@replicate_2025-12-26_07-30-01 Fri Dec 26 07:30 2025
rpool/replica/vm-102-disk-0@replicate_2025-12-26_08-00-01 Fri Dec 26 08:00 2025
Significado: El destino carece de snapshots más recientes que el origen espera como base para incrementales (o que el trabajo espera).
Decisión: Determina el último snapshot común y si el estado registrado por Proxmox coincide con la realidad. Si el estado es inconsistente, re-seed.
Task 5: Verificar acceso SSH no interactivo y sanidad de claves de host
cr0x@server:~$ ssh -o BatchMode=yes -o ConnectTimeout=5 pve02 -- "echo ok && hostname"
ok
pve02
Significado: SSH funciona sin prompts. Eso elimina la clase de fallos “esperando contraseña/confirmación de clave de host”.
Decisión: Si esto falla, arregla SSH primero. No toques ZFS hasta que la conectividad del plano de control esté limpia.
Task 6: Comprobar salud de pools en ambos nodos
cr0x@server:~$ zpool status -x
all pools are healthy
cr0x@server:~$ ssh pve02 -- zpool status -x
all pools are healthy
Significado: No hay errores evidentes en pools.
Decisión: Si ves “DEGRADED”, “too many errors” o resilvering en curso, trátalo como un incidente de almacenamiento primero; la replicación es un síntoma.
Task 7: Comprobar espacio libre y cuotas de dataset (a la manera ZFS)
cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint rpool | head -n 5
NAME USED AVAIL REFER MOUNTPOINT
rpool 3.21T 620G 192K /rpool
cr0x@server:~$ ssh pve02 -- zfs list -o name,used,avail,refer,mountpoint rpool | head -n 5
NAME USED AVAIL REFER MOUNTPOINT
rpool 3.79T 110G 192K /rpool
Significado: El destino tiene solo 110G disponibles. Eso coquetea con el fallo.
Decisión: Si el destino está justo de espacio, deja de intentar “forzar” la replicación. Libera espacio o expande el pool antes de re-seedear; de lo contrario crearás receives parciales y proliferación de snapshots.
Task 8: Identificar si el destino tiene un resume token (receive interrumpido)
cr0x@server:~$ ssh pve02 -- zfs get -H -o name,property,value receive_resume_token rpool/replica/vm-102-disk-0
rpool/replica/vm-102-disk-0 receive_resume_token -
Significado: No hay resume token. El destino no está esperando reanudar un stream parcial.
Decisión: Si ves un valor largo de token, decide si reanudar (preferible) o abortar/retroceder (más arriesgado) según política y tiempo.
Task 9: Ejecutar un dry-run manual del tamaño del send incremental (planificación de capacidad)
cr0x@server:~$ zfs send -nPv -i rpool/data/vm-102-disk-0@replicate_2025-12-26_08-00-01 rpool/data/vm-102-disk-0@replicate_2025-12-26_09-00-01
send from @replicate_2025-12-26_08-00-01 to rpool/data/vm-102-disk-0@replicate_2025-12-26_09-00-01 estimated size is 18.4G
total estimated size is 18.4G
Significado: El delta es ~18.4G. Útil para decidir si el ancho de banda y el espacio en el destino son adecuados.
Decisión: Si la delta estimada es enorme, programa la replicación fuera de horas pico o aumenta la frecuencia; deltas grandes a menudo significan que tu programación es demasiado espaciada o que los trabajos fallan repetidamente.
Task 10: Medir rápidamente el throughput de la red
cr0x@server:~$ iperf3 -c pve02 -t 10
Connecting to host pve02, port 5201
[ 5] 0.00-10.00 sec 8.76 GBytes 7.52 Gbits/sec 0 sender
[ 5] 0.00-10.00 sec 8.75 GBytes 7.52 Gbits/sec receiver
Significado: ~7.5 Gbit/s efectivo. No es perfecto 10G, pero probablemente suficiente a menos que tus deltas sean enormes.
Decisión: Si ves 200–800 Mbit/s en un enlace 10G, deja de culpar a ZFS. Revisa MTU, errores, enrutamiento y congestión.
Task 11: Inspeccionar errores de interfaz y MTU
cr0x@server:~$ ip -s link show dev bond0
2: bond0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue state UP mode DEFAULT group default qlen 1000
RX: bytes packets errors dropped missed mcast
91234567890 81234567 0 0 0 0
TX: bytes packets errors dropped carrier collsns
82345678901 72345678 0 0 0 0
cr0x@server:~$ ssh pve02 -- ip link show dev bond0 | head -n 2
2: bond0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
Significado: Desajuste de MTU. Eso puede hacer la replicación lenta o frágil dependiendo de la ruta.
Decisión: Estandariza MTU end-to-end (incluyendo switches). No “medio-jumbo” y esperar que funcione.
Task 12: Revisar logs de Proxmox y del sistema alrededor del fallo
cr0x@server:~$ journalctl -u pvedaemon -u pveproxy -u pvescheduler --since "2025-12-26 08:45" --until "2025-12-26 09:05" | tail -n 30
Dec 26 08:55:14 pve01 pvescheduler[1123]: starting replication job local-zfs:102
Dec 26 08:55:18 pve01 pvedaemon[1109]: VM 102: replication job failed: exit code 1
Significado: Confirma la temporalidad y que es un fallo a nivel de trabajo, no un glitch de la GUI.
Decisión: Si ves reintentos repetidos, timeouts o trabajos solapados, puede que necesites ajustar horarios o concurrencia.
Task 13: Validar que el dataset destino existe y es del tipo esperado
cr0x@server:~$ ssh pve02 -- zfs list -o name,type,volsize,used,avail rpool/replica/vm-102-disk-0
NAME TYPE VOLSIZE USED AVAIL
rpool/replica/vm-102-disk-0 volume 128G 91G 110G
Significado: El destino es un zvol (“volume”). Eso es coherente con discos de VM almacenados como zvols.
Decisión: Si el tipo es “filesystem” pero esperas “volume”, para y corrige el layout de almacenamiento—forzar receives en el tipo equivocado es cómo se crean desastres creativos.
Task 14: Realizar un re-seed completo controlado (zfs send/receive manual)
cr0x@server:~$ zfs snapshot rpool/data/vm-102-disk-0@replicate_reseed_2025-12-26_09-30
cr0x@server:~$ zfs send -Pv rpool/data/vm-102-disk-0@replicate_reseed_2025-12-26_09-30 | ssh pve02 -- zfs receive -u -F rpool/replica/vm-102-disk-0
send from rpool/data/vm-102-disk-0@replicate_reseed_2025-12-26_09-30 estimated size is 92.1G
total estimated size is 92.1G
TIME SENT SNAPSHOT
00:00:10 5.62G rpool/data/vm-102-disk-0@replicate_reseed_2025-12-26_09-30
Significado: Estás sobrescribiendo/volcando el destino para que coincida con el estado snapshot del origen, usando -F para forzar el rollback en el dataset destino.
Decisión: Usa -F solo cuando estés absolutamente seguro de que el destino es una réplica y no aloja una VM en ejecución. Si ese destino está “activo”, estás a punto de destruir el estado activo del disco.
Task 15: Tras el re-seed, validar alineamiento de snapshots y preparación para replicación
cr0x@server:~$ ssh pve02 -- zfs list -t snapshot -o name -s creation rpool/replica/vm-102-disk-0 | tail -n 3
rpool/replica/vm-102-disk-0@replicate_2025-12-26_08-00-01
rpool/replica/vm-102-disk-0@replicate_2025-12-26_09-00-01
rpool/replica/vm-102-disk-0@replicate_reseed_2025-12-26_09-30
Significado: El destino ahora tiene el snapshot de reseed y los anteriores (según lo que se envió). Tienes una base común otra vez.
Decisión: Vuelve a habilitar la replicación de Proxmox para esa VM/trabajo y observa la siguiente ejecución incremental. Si falla de nuevo, probablemente tengas un problema sistémico (espacio, poda inconsistente, colisiones de programación).
Task 16: Buscar errores de receive ZFS que indiquen mismatch de feature/encriptación
cr0x@server:~$ ssh pve02 -- zpool get -H -o value feature@encryption rpool
active
Significado: El pool destino soporta la feature de encryption.
Decisión: Si esto está “disabled” o “inactive” mientras el origen usa datasets cifrados, espera fallos en receive. Alinea el soporte de features ZFS o ajusta el modo de envío.
Planes de recuperación que no generan nuevos problemas
Hay dos estrategias amplias de recuperación: reparar la cadena o re-seed. Elegir mal desperdicia tiempo; elegir de forma imprudente arriesga pérdida de datos.
Plan A: Reparar la cadena de snapshots (cuando sea posible)
Usa esto cuando el destino aún tiene un snapshot común, pero el estado de Proxmox está confundido o un snapshot reciente falta por un trabajo interrumpido.
- Confirma que el último snapshot común existe en ambos lados.
- No borres nada “para limpiar” hasta que sepas qué espera Proxmox.
- Si hay un resume token, intenta reanudar antes de re-seedear.
- Ejecuta un send incremental manual usando nombres de snapshot explícitos para probar la viabilidad.
La ventaja: mínimo ancho de banda y tiempo. La desventaja: requiere disciplina e inspección cuidadosa.
Plan B: Re-seed completo (el instrumento contundente que funciona)
Usa esto cuando la cadena está rota, los snapshots se han podado inconsistente o el dataset destino ha divergido.
- Asegura que el dataset destino no esté en uso por una VM en ejecución.
- Asegura suficiente espacio libre en el pool destino (margen real).
- Toma un nuevo snapshot “reseed” en el origen.
- Envíalo con un receive forzado al dataset réplica.
- Verifica snapshots y vuelve a habilitar la replicación programada.
Chiste #2: Un re-seed es como reinstalar tu SO para arreglar un driver—efectivo, algo embarazoso y a veces la mejor inversión de tiempo.
Cuándo parar y escalar
Para de “probar cosas” y escala a un incidente de almacenamiento si ves:
- errores crecientes en pools, errores de checksum o timeouts repetidos de dispositivos
- velocidad de replicación colapsando mientras
zpool iostatmuestra esperas largas - el pool destino está casi lleno y la fragmentación es alta
- scrub/resilver en curso durante ventanas de replicación
Tres mini-historias del mundo corporativo (anonimizadas, plausibles, instructivas)
Mini-historia 1: La suposición equivocada que rompió el DR
La organización tenía dos clusters Proxmox: uno primario y otro “warm DR”. La replicación corría cada hora y había estado en verde durante meses. El almacenamiento era ZFS en ambos lados, generaciones de hardware distintas, mismo esquema de nombres de dataset. Todos dormían tranquilos.
Entonces llegó un nuevo ingeniero y hizo lo que la gente concienzuda suele hacer: limpió lo que parecía basura. En el nodo DR vio una pila de snapshots con nombres de artefactos de replicación y asumió que eran restos antiguos. Los podó con un script rápido. Liberó espacio. Los dashboards siguieron en verde por un tiempo porque nada se ejecutó inmediatamente.
El siguiente ciclo de replicación falló para un tercio de las VMs. Los errores decían que los snapshots base incrementales no coincidían. El ingeniero (tratando de ayudar) borró más snapshots, pensando que Proxmox los reconstruiría. Esa es la suposición: “los snapshots de replicación son desechables”. No lo son. Son la cadena.
La recuperación no fue técnicamente difícil—re-seeds completos lo arreglaron—pero operacionalmente fue feo. Varias VMs grandes necesitaron envíos completos por un enlace que ya estaba ocupado en horas laborales. El equipo tuvo que limitar y reprogramar trabajos, y el RPO de DR fue pobre durante un día. El postmortem dejó una lección en negrita: nunca podes manualmente snapshots de replicación a menos que estés re-seedeando intencionalmente.
Mini-historia 2: La optimización que salió mal
Otra empresa quiso reducir el tiempo de replicación. Alguien notó que las configuraciones de compresión diferían entre pools. También vieron CPU ociosa en los nodos. Genial: activar compresión agresiva, aumentar la frecuencia de replicación y ver cómo las deltas se reducen.
Cambiaron propiedades ZFS en los datasets origen a un modo de compresión más intenso. En papel: menos ancho de banda, replicación más rápida, almacenamiento más pequeño. En realidad: durante horas pico, la contención de CPU afectó al hypervisor e incrementó la latencia de las VMs. No mucho—lo justo para que algunos servicios sensibles a la latencia se volvieran inestables. Los gráficos de red y almacenamiento se veían mejor, pero los de aplicaciones se veían peor.
Luego el efecto bumerán fue más agudo: los trabajos de replicación empezaron a solaparse con los backups. Ambos eran intensivos en snapshots. El sistema pasó más tiempo haciendo snapshots, podando y sincronizando txgs que moviendo datos. La replicación fallaba intermitentemente por timeouts y contención de locks, lo que aumentó tamaños de delta, alargando la replicación y provocando más solapamientos. Un bonito bucle de retroalimentación.
La solución fue aburrida: reducir la compresión a un ajuste equilibrado, separar ventanas de replicación y backup, e imponer límites de concurrencia. Mantuvieron algunas mejoras, eliminaron la latencia autoinfligida y recuperaron predictibilidad—la verdadera moneda en ops.
Mini-historia 3: La práctica aburrida que salvó el día
Una compañía financiera tenía una costumbre que parecía paranoica: cada mes realizaban una prueba controlada de DR para un puñado de VMs. No un gran corte. Solo una muestra rotativa. Verificaban que los datasets replicados estuvieran presentes, que la VM pudiera arrancar y que las comprobaciones a nivel de aplicación pasaran.
Un mes, la prueba falló. La VM no arrancó en el nodo DR porque el dataset réplica estaba presente pero incompleto. El estado de la replicación decía “ok” en la última ejecución, pero un receive parcial previo había dejado el dataset en un estado inconsistente de “parece que está allí”. Nadie lo había notado porque el primario estaba bien y a los dashboards les gusta mentir por omisión.
Como probaron, lo encontraron antes de que importara. Pausaron nuevos trabajos de replicación, arreglaron la flakiness de la red subyacente y re-seedearon un puñado de discos afectados. El incidente fue un ticket, no un titular.
Ese es el secreto: un drill de DR recurrente y aburrido te obliga a validar toda la cadena—ZFS, SSH, estado de Proxmox y capacidad de arranque. También te obliga a mantener runbooks precisos, porque realmente los usas.
Errores comunes (síntoma → causa raíz → solución)
1) “Most recent snapshot does not match incremental source”
Síntoma: La replicación falla con errores de mismatch incremental.
Causa raíz: Cadena de snapshots rota—snapshots borrados en destino/origen, o dataset destino divergió por cambios manuales.
Solución: Identifica el último snapshot común; si no hay ninguno, realiza un re-seed completo controlado con un nuevo snapshot y receive forzado. Deja de borrar snapshots “hasta que funcione”.
2) “cannot receive: destination exists” o “dataset already exists”
Síntoma: Receive falla inmediatamente.
Causa raíz: El dataset destino existe pero no es el objetivo réplica esperado, o las flags de receive no coinciden (falta -F donde corresponde).
Solución: Verifica tipo de dataset y estructura prevista. Si es una réplica verdadera, usa zfs receive -F controlado. Si no, renombra o reconfigura el layout de almacenamiento para evitar colisiones.
3) “No space left on device” durante receive
Síntoma: El trabajo falla a mitad de stream, a veces dejando estado parcial.
Causa raíz: Pool/dataset destino lleno, cuotas o margen insuficiente causando ENOSPC bajo presión de copy-on-write.
Solución: Libera espacio correctamente (borra backups antiguos, expande pool, ajusta cuotas). Luego limpia receives parciales y re-seedea si es necesario.
4) Replicación “atascada” o tarda una eternidad, pero no falla
Síntoma: Los trabajos duran horas, se encolan.
Causa raíz: Contención de I/O con backups/scrubs, colapso de throughput en la red o discos lentos en el destino.
Solución: Mide: iperf3, zpool iostat y errores de interfaz. Separa ventanas, limita concurrencia y evita scrubs durante picos de replicación.
5) “Host key verification failed” o prompts de contraseña en logs
Síntoma: La replicación falla inmediatamente; los logs mencionan SSH.
Causa raíz: Claves de host cambiadas, llaves faltantes o BatchMode fallando.
Solución: Repara la confianza SSH y las llaves. Confirma que ssh -o BatchMode=yes funciona. Luego vuelve a ejecutar la replicación.
6) Estado de replicación en verde, pero el arranque en DR falla
Síntoma: Intentas iniciar una VM replicada y hace panic o falta/corrupción del disco.
Causa raíz: Dataset réplica incompleto, mal montado, llaves de cifrado no cargadas o dataset recibido incorrectamente.
Solución: Valida propiedades del dataset, estado de llaves de cifrado y realiza pruebas de arranque periódicas. Si dudas, re-seedea los discos afectados.
Listas de verificación / plan paso a paso
Checklist: Antes de intentar la recuperación
- Confirma qué nodo es origen y cuál es destino para el trabajo fallido.
- Confirma que el dataset destino no está en uso por una VM en ejecución.
- Captura el log de fallo (log de tarea + línea exacta de error ZFS). No confíes en la memoria.
- Comprueba conectividad SSH BatchMode.
- Comprueba salud de pools y espacio libre en ambos extremos.
- Lista snapshots en ambos extremos y localiza el último snapshot común.
Paso a paso: Reparar replicación incremental (preferible cuando sea posible)
- Identifica el nombre del último snapshot común (ortografía exacta).
- Estima tamaño con
zfs send -nPv -i. - Ejecuta un send/receive incremental manual para validar que la cadena funciona.
- Reinicia el trabajo de replicación de Proxmox y observa la siguiente ejecución.
- Tras el éxito, revisa la retención de snapshots para que el snapshot base no sea podado prematuramente.
Paso a paso: Re-seed completo (cuando la cadena está rota)
- Detén o pausa el trabajo de replicación (para que no te compita).
- Asegura que el destino tiene suficiente margen; expande o limpia primero.
- Crea un nuevo snapshot “reseed” en el origen.
- Envía el snapshot completo al destino con receive forzado (
-F) solo si es seguro. - Verifica que el snapshot destino existe y coincide.
- Vuelve a habilitar la replicación de Proxmox y monitoriza.
Checklist: Después de la recuperación (no lo omitas)
- Ejecuta un ciclo de replicación más para la VM y confirma éxito.
- Confirma que el espacio del pool destino es estable (no tendencia a llenarse).
- Confirma que los horarios no se solapan mucho con backups/scrubs.
- Realiza una prueba de arranque DR para al menos una VM recuperada si la política lo permite.
- Documenta la causa raíz en un párrafo que un on-call cansado pueda entender.
Preguntas frecuentes
1) ¿La replicación de Proxmox es lo mismo que una copia de seguridad?
No. La replicación mantiene una copia nearline de los discos de VM en otro nodo, típicamente para failover rápido. Las copias de seguridad son archivos punto en el tiempo diseñados para restauración y retención prolongada. Necesitas ambos.
2) ¿Por qué falla la replicación después de que “limpié snapshots antiguos”?
Porque la replicación incremental requiere un snapshot común en ambos nodos. Borrar snapshots de replicación rompe la cadena. Si debes podar, hazlo mediante políticas de Proxmox o prepárate para re-seedear.
3) ¿Puedo simplemente hacer clic en “Retry” hasta que funcione?
Puedes, pero así conviertes una ruptura de cadena en un backlog de colas. Reintentar está bien después de arreglar la causa raíz (SSH, espacio, MTU). Si el error indica mismatch incremental, los reintentos no crearán snapshots ausentes.
4) ¿Cuál es la solución contundente más segura?
Un re-seed completo al dataset destino, realizado deliberadamente: verifica que el destino no está en uso, asegura espacio, haz snapshot en origen, zfs send a zfs receive -F. El martillo es seguro cuando confirmas lo que vas a tocar.
5) ¿Cómo sé si la red es el problema?
Mídela. Usa iperf3, revisa errores de interfaz con ip -s link y confirma que el MTU coincide end-to-end. Si el throughput es bajo y hay errores/paquetes perdidos, la replicación es inocente.
6) ¿La compresión ZFS ayuda a la replicación?
A veces. Puede reducir bytes enviados, pero aumenta CPU y puede amplificar contención en periodos ocupados. Optimiza para previsibilidad primero, velocidad segundo.
7) ¿Los datasets cifrados pueden replicarse correctamente?
Sí, pero debes alinear expectativas: el send encrypted raw mantiene los datos cifrados; los sends descifrados requieren llaves cargadas y pueden cambiar comportamiento. Feature flags ZFS mismatched o llaves faltantes romperán receives.
8) ¿Por qué la replicación muestra “ok” pero la réplica no arranca?
Porque “ok” suele significar que el último trabajo devolvió éxito—no que validaste el arranque. Datasets parciales, mapeo incorrecto de destinos o problemas con llaves aún pueden existir. Prueba arranques periódicamente.
9) ¿Debo replicar cada VM tan frecuentemente como sea posible?
No. La replicación tiene coste: snapshots, I/O, poda y contención de trabajos. Clasifica VMs por necesidades de RPO y tamaño. Haz que la programación coincida con la realidad.
10) ¿Qué automatizarías primero?
Alertas sobre: fallos de replicación, pool destino >80% uso, aumento de errores de interfaz y snapshots recientes ausentes en el destino. Los humanos son buenos arreglando problemas, malos notando una deriva lenta.
Próximos pasos que deberías hacer
Si la replicación falló hoy, haz esto en orden:
- Extrae el log exacto de la tarea y extrae la línea de error ZFS/SSH.
- Verifica SSH BatchMode y salud de pools en ambos extremos.
- Comprueba margen en el destino y presencia de snapshots; encuentra el último snapshot común.
- Si la cadena está intacta, repara incrementales. Si está rota, re-seedea deliberadamente.
- Tras la recuperación, corrige la política que lo causó: poda de snapshots, tendencias de espacio, solapamiento de horarios, desajuste MTU o gestión de llaves.
El objetivo de la replicación no es que los dashboards estén verdes. Es hacer que el fallo sea aburrido. Cuando la replicación se rompe, trátalo como cualquier otra canalización de producción: plano de control primero, plano de datos segundo, y no “limpiar” hasta que hayas probado qué falta realmente.